Skip to content

Commit 0d35c9f

Browse files
committed
Added TigaUser.update_score
1 parent 89fab90 commit 0d35c9f

File tree

7 files changed

+79
-237
lines changed

7 files changed

+79
-237
lines changed

requirements/prod_20_04.pip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ MarkupSafe==1.1.1
6161
matplotlib==2.0.2
6262
msgpack==1.0.2
6363
numpy==1.23.1
64+
numpyencoder==0.3.0
6465
odfpy==1.4.0
6566
openapi-codec==1.3.2
6667
openpyxl==3.0.0

stats/views.py

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@
1919
import json
2020
import datetime
2121
from django.utils import timezone
22-
from tigascoring.xp_scoring import compute_user_score_in_xp_v2
2322
from rest_framework.exceptions import ParseError
2423
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
2524
import math
2625
from django.utils import translation
2726

28-
from tigascoring.xp_scoring import compute_user_score_in_xp_v2
2927
from rest_framework.exceptions import ParseError
3028
from django.core.paginator import Paginator
3129
import math
@@ -642,13 +640,8 @@ def stats_user_score(request, user_uuid=None):
642640
pass
643641

644642
if user.score_v2_struct is None:
645-
user_score = compute_user_score_in_xp_v2(user_uuid, update=True)
646-
user.score_v2_struct = json.dumps(user_score, indent=2, sort_keys=True, default=str)
647-
user.last_score_update = datetime.datetime.now()
648-
user.save()
649-
else:
650-
user_score = json.loads(user.score_v2_struct)
651-
context = { "score_data": user_score, "score_last_update": user.last_score_update }
643+
user.update_score(commit=True)
644+
context = { "score_data": user.score_v2_struct, "score_last_update": user.last_score_update }
652645
return render(request, 'stats/user_score.html', context)
653646

654647

@@ -680,17 +673,11 @@ def stats_user_ranking(request, page=1, user_uuid=None):
680673
try:
681674
user = TigaUser.objects.get(pk=user_uuid)
682675
user.get_identicon()
683-
#user_score = compute_user_score_in_xp_v2(user_uuid, update=True)
684-
if user.score_v2_struct is None:
685-
user_score = compute_user_score_in_xp_v2(user_uuid, update=True)
686-
user.score_v2_struct = json.dumps(user_score, indent=2, sort_keys=True, default=str)
687-
user.last_score_update = datetime.datetime.now()
688-
user.save()
689-
else:
690-
user_score = json.loads( user.score_v2_struct )
691-
if user_score['total_score'] > 0:
692-
user_has_score = True
693676

677+
if user.score_v2_struct is None:
678+
user.update_score(commit=True)
679+
user_score = user.score_v2_struct
680+
user_has_score = bool(user.score_v2)
694681
except TigaUser.DoesNotExist:
695682
pass
696683
seek = request.GET.get('seek', 'f')
@@ -1046,13 +1033,9 @@ def get_user_xp_data(request):
10461033
translation.activate(locale)
10471034

10481035
if u.score_v2_struct is None:
1049-
retval = compute_user_score_in_xp_v2(user_id, update=True)
1050-
u.score_v2_struct = json.dumps(retval, indent=2, sort_keys=True, default=str)
1051-
u.last_score_update = datetime.datetime.now()
1052-
u.save()
1053-
else:
1054-
retval = json.loads(u.score_v2_struct)
1036+
u.update_score(commit=True)
10551037

1038+
retval = u.score_v2_struct
10561039
retval['last_update'] = u.last_score_update
10571040

10581041
return Response(retval)

tigascoring/xp_scoring.py

Lines changed: 6 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from tigaserver_app.models import Report, TigaUser, TigaProfile, Award
1+
from tigaserver_app.models import Report, TigaUser, Award
22
from tigaserver_project import settings as conf
33
import pandas as pd
44
import datetime
@@ -324,106 +324,17 @@ def get_unrelated_awards_score( user_uuid, user_uuids ):
324324
# return str(diff.days) + _(" days ago")
325325

326326

327-
def compute_user_score_in_xp_v2_fast(user_uuid):
327+
def compute_user_score_in_xp_v2(user_uuid):
328328

329329
user = TigaUser.objects.get(pk=user_uuid)
330330
user_uuids = None
331331
if user.profile is not None:
332332
user_uuids = TigaUser.objects.filter(profile=user.profile).values('user_UUID')
333333

334-
result = {}
335-
result['total_score'] = 0
336-
result['user_uuid'] = user_uuid
337-
result['score_detail'] = {}
338-
339-
if user_uuids is None:
340-
user_reports = Report.objects.filter(user__user_UUID=user_uuid).order_by('-creation_time')
341-
else:
342-
user_reports = Report.objects.filter(user__user_UUID__in=user_uuids).order_by('-creation_time')
343-
344-
adults = user_reports.filter(type='adult')
345-
#bites = user_reports.filter(type='bite')
346-
sites = user_reports.filter(type='site')
347-
348-
adult_last_versions = adults.non_deleted().all()
349-
#bite_last_versions = bites.non_deleted().all()
350-
site_last_versions = sites.non_deleted().all()
351-
352-
results_adult = {}
353-
results_adult['score'] = 0
354-
results_adult['score_items'] = []
355-
result['score_detail']['adult'] = results_adult
356-
357-
adult_score = 0
358-
for report in adult_last_versions:
359-
result = get_adult_report_score(report, result)
360-
index = len(result['score_detail']['adult']['score_items']) - 1
361-
result['score_detail']['adult']['score'] += result['score_detail']['adult']['score_items'][index][
362-
'report_score']
363-
adult_score += result['score_detail']['adult']['score_items'][index]['report_score']
364-
result['total_score'] += adult_score
365-
366-
'''
367-
results_bite = {}
368-
results_bite['score'] = 0
369-
results_bite['score_items'] = []
370-
result['score_detail']['bite'] = results_bite
371-
372-
bite_score = 0
373-
for report in bite_last_versions:
374-
result = get_bite_report_score(report, result)
375-
index = len(result['score_detail']['bite']['score_items']) - 1
376-
result['score_detail']['bite']['score'] += result['score_detail']['bite']['score_items'][index]['report_score']
377-
bite_score += result['score_detail']['bite']['score_items'][index]['report_score']
378-
result['total_score'] += bite_score
379-
'''
380-
381-
results_site = {}
382-
results_site['score'] = 0
383-
results_site['score_items'] = []
384-
result['score_detail']['site'] = results_site
385-
386-
site_score = 0
387-
for report in site_last_versions:
388-
result = get_site_report_score(report, result)
389-
index = len(result['score_detail']['site']['score_items']) - 1
390-
result['score_detail']['site']['score'] += result['score_detail']['site']['score_items'][index]['report_score']
391-
site_score += result['score_detail']['site']['score_items'][index]['report_score']
392-
result['total_score'] += site_score
393-
394-
unrelated_score = get_unrelated_awards_score(user_uuid, user_uuids)
395-
396-
result['total_score'] += unrelated_score['score']
397-
398-
return result
399-
400-
401-
def get_uuid_replicas():
402-
profiles = TigaProfile.objects.all()
403-
exclude = []
404-
for p in profiles:
405-
if p.profile_devices.count() > 1:
406-
i = 0
407-
for d in p.profile_devices.all().order_by('user_UUID'):
408-
if i > 0:
409-
exclude.append(d.user_UUID)
410-
i+=1
411-
return exclude
412-
413-
414-
def compute_user_score_in_xp_v2(user_uuid, update=False):
415-
416-
user = TigaUser.objects.get(pk=user_uuid)
417-
user_uuids = None
418-
if user.profile is not None:
419-
user_uuids = TigaUser.objects.filter(profile=user.profile).values('user_UUID')
420-
421-
uuid_replicas = get_uuid_replicas()
422-
423-
qs_overall = TigaUser.objects.exclude(score_v2=0).exclude(user_UUID__in=uuid_replicas)
424-
qs_adult = TigaUser.objects.exclude(score_v2_adult=0).exclude(user_UUID__in=uuid_replicas)
425-
qs_site = TigaUser.objects.exclude(score_v2_site=0).exclude(user_UUID__in=uuid_replicas)
426-
#qs_bite = TigaUser.objects.exclude(score_v2_bite=0).exclude(user_UUID__in=uuid_replicas)
334+
qs_overall = TigaUser.objects.exclude(score_v2=0)
335+
qs_adult = TigaUser.objects.exclude(score_v2_adult=0)
336+
qs_site = TigaUser.objects.exclude(score_v2_site=0)
337+
#qs_bite = TigaUser.objects.exclude(score_v2_bite=0)
427338

428339
overall_df = pd.DataFrame(list(qs_overall.values_list('score_v2', 'user_UUID')), columns=['score_v2', 'user_UUID'])
429340
adult_df = pd.DataFrame(list(qs_adult.values_list('score_v2_adult', 'user_UUID')), columns=['score_v2_adult', 'user_UUID'])
@@ -587,18 +498,6 @@ def compute_user_score_in_xp_v2(user_uuid, update=False):
587498
result['score_detail']['site']['top_perc'] = (float(site_number_below_rank) / float(site_number_total)) * 100.0
588499
result['score_detail']['site']['ranked_users'] = site_number_total
589500

590-
if update:
591-
if user_uuids is not None:
592-
all_users_in_profile = TigaUser.objects.filter(user_UUID__in=user_uuids)
593-
all_users_in_profile.update(score_v2=result['total_score'])
594-
all_users_in_profile.update(score_v2_adult=result['score_detail']['adult']['score'])
595-
all_users_in_profile.update(score_v2_site=result['score_detail']['site']['score'])
596-
else:
597-
user.score_v2 = result['total_score']
598-
user.score_v2_adult = result['score_detail']['adult']['score']
599-
user.score_v2_site = result['score_detail']['site']['score']
600-
user.save()
601-
602501
'''
603502
if bite_number_below_rank == 0 and bite_number_total == 0:
604503
result['score_detail']['bite']['top_perc'] = 100.0
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Generated by Django 2.2.7 on 2024-03-15 11:50
2+
3+
import django.contrib.postgres.fields.jsonb
4+
from django.db import migrations
5+
import numpyencoder.numpyencoder
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
('tigaserver_app', '0052_ensure_masked_fixes'),
11+
]
12+
13+
operations = [
14+
migrations.AlterField(
15+
model_name='tigauser',
16+
name='score_v2_struct',
17+
field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, encoder=numpyencoder.numpyencoder.NumpyEncoder, help_text='Full cached score data', null=True),
18+
),
19+
]

tigaserver_app/models.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from firebase_admin.messaging import Message, Notification as FirebaseNotification, AndroidConfig, AndroidNotification
99
import logging
1010
from math import floor
11+
from numpyencoder import NumpyEncoder
1112
from PIL import Image
1213
import pydenticon
1314
import os
@@ -21,16 +22,15 @@
2122
from django.contrib.gis.db.models.functions import Distance as DistanceFunction
2223
from django.contrib.gis.geos import GEOSGeometry
2324
from django.contrib.gis.measure import Distance as DistanceMeasure
25+
from django.contrib.postgres.fields import JSONField
2426
from django.db.models import Count, Q
2527
from django.db.models.signals import post_save
2628
from django.dispatch import receiver
2729
from django.forms.models import model_to_dict
2830
from django.template.loader import render_to_string, TemplateDoesNotExist
2931
from django.urls import reverse
30-
from django.utils import translation
32+
from django.utils import translation, timezone
3133
from django.utils.deconstruct import deconstructible
32-
from django.utils import timezone
33-
from django.utils.timezone import utc
3434
from django.utils.translation import ugettext_lazy as _
3535

3636
from simple_history.models import HistoricalRecords
@@ -222,7 +222,9 @@ class TigaUser(models.Model):
222222

223223
profile = models.ForeignKey(TigaProfile, related_name='profile_devices', null=True, blank=True, on_delete=models.SET_NULL, )
224224

225-
score_v2_struct = models.TextField(help_text="Full cached score data", null=True, blank=True)
225+
# NOTE using NumpyEncoder since compute_user_score_in_xp_v2 function get result from pandas dataframe
226+
# and some integer are np.int64, which can not be encoded with the regular json library setup.
227+
score_v2_struct = JSONField(encoder=NumpyEncoder, help_text="Full cached score data", null=True, blank=True)
226228

227229
last_score_update = models.DateTimeField(help_text="Last time score was updated", null=True, blank=True)
228230

@@ -251,6 +253,34 @@ def get_identicon(self):
251253
f.close()
252254
return settings.MEDIA_URL + "identicons/" + self.user_UUID + ".png"
253255

256+
def update_score(self, commit: bool = True) -> None:
257+
# NOTE: placing import here due to circular import
258+
from tigascoring.xp_scoring import compute_user_score_in_xp_v2
259+
260+
score_dict = compute_user_score_in_xp_v2(user_uuid=self.pk)
261+
self.score_v2_struct = score_dict
262+
263+
try:
264+
self.score_v2_adult = score_dict['score_detail']['adult']['score']
265+
except (KeyError, TypeError):
266+
self.score_v2_adult = 0
267+
268+
try:
269+
self.score_v2_bite = score_dict['score_detail']['bite']['score']
270+
except (KeyError, TypeError):
271+
self.score_v2_bite = 0
272+
273+
try:
274+
self.score_v2_site = score_dict['score_detail']['site']['score']
275+
except (KeyError, TypeError):
276+
self.score_v2_site = 0
277+
278+
self.score_v2 = sum([self.score_v2_adult, self.score_v2_bite, self.score_v2_site])
279+
self.last_score_update = timezone.now()
280+
281+
if commit:
282+
self.save()
283+
254284
n_reports = property(number_of_reports_uploaded)
255285
ios_user = property(is_ios)
256286

@@ -345,7 +375,7 @@ def __unicode__(self):
345375
return self.title_catalan
346376

347377
def active_missions(self):
348-
return self.expiration_time >= datetime.utcnow().replace(tzinfo=utc)
378+
return self.expiration_time >= datetime.utcnow().replace(tzinfo=timezone.utc)
349379

350380

351381
class MissionTrigger(models.Model):

tigaserver_app/views.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
from django.views.decorators.cache import cache_page
3333
from tigacrafting.criteria import users_with_pictures,users_with_storm_drain_pictures, users_with_score, users_with_score_range, users_with_topic
3434
from tigascoring.maUsers import smmry
35-
from tigascoring.xp_scoring import compute_user_score_in_xp_v2
3635
from tigaserver_app.serializers import custom_render_notification,score_label
3736
import tigaserver_project.settings as conf
3837
import copy
@@ -1219,8 +1218,8 @@ def user_score_v2(request):
12191218
if user_id == -1:
12201219
raise ParseError(detail='user_id is mandatory')
12211220
user = get_object_or_404(TigaUser.objects.all(), pk=user_id)
1222-
result = compute_user_score_in_xp_v2(user_id, update=True)
1223-
return Response(result)
1221+
user.update_score(commit=True)
1222+
return Response(user.score_v2_struct)
12241223

12251224

12261225
@api_view(['GET', 'POST'])

0 commit comments

Comments
 (0)