Add caching for user basic info
This commit is contained in:
parent
7f854c40dd
commit
ed287b6ff3
15 changed files with 110 additions and 33 deletions
|
@ -8,6 +8,8 @@ from django.db.models.functions import Coalesce
|
|||
|
||||
from chat_box.models import Ignore, Message, UserRoom, Room
|
||||
|
||||
from judge.caching import cache_wrapper
|
||||
|
||||
secret_key = settings.CHAT_SECRET_KEY
|
||||
fernet = Fernet(secret_key)
|
||||
|
||||
|
@ -37,6 +39,7 @@ def encrypt_channel(channel):
|
|||
)
|
||||
|
||||
|
||||
@cache_wrapper(prefix="gub")
|
||||
def get_unread_boxes(profile):
|
||||
ignored_rooms = Ignore.get_ignored_rooms(profile)
|
||||
unread_boxes = (
|
||||
|
|
|
@ -36,7 +36,7 @@ from judge.jinja2.gravatar import gravatar
|
|||
from judge.models import Friend
|
||||
|
||||
from chat_box.models import Message, Profile, Room, UserRoom, Ignore
|
||||
from chat_box.utils import encrypt_url, decrypt_url, encrypt_channel
|
||||
from chat_box.utils import encrypt_url, decrypt_url, encrypt_channel, get_unread_boxes
|
||||
|
||||
import json
|
||||
|
||||
|
@ -208,6 +208,7 @@ def post_message(request):
|
|||
)
|
||||
else:
|
||||
Room.last_message_body.dirty(room)
|
||||
|
||||
for user in room.users():
|
||||
event.post(
|
||||
encrypt_channel("chat_" + str(user.id)),
|
||||
|
@ -223,6 +224,7 @@ def post_message(request):
|
|||
UserRoom.objects.filter(user=user, room=room).update(
|
||||
unread_count=F("unread_count") + 1
|
||||
)
|
||||
get_unread_boxes.dirty(user)
|
||||
|
||||
return JsonResponse(ret)
|
||||
|
||||
|
@ -285,6 +287,8 @@ def update_last_seen(request, **kwargs):
|
|||
user_room.unread_count = 0
|
||||
user_room.save()
|
||||
|
||||
get_unread_boxes.dirty(profile)
|
||||
|
||||
return JsonResponse({"msg": "updated"})
|
||||
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ class ProfileAdmin(VersionAdmin):
|
|||
admin_user_admin.short_description = _("User")
|
||||
|
||||
def email(self, obj):
|
||||
return obj.user.email
|
||||
return obj.email
|
||||
|
||||
email.admin_order_field = "user__email"
|
||||
email.short_description = _("Email")
|
||||
|
|
|
@ -40,9 +40,9 @@ def cache_wrapper(prefix, timeout=None):
|
|||
if result == NONE_RESULT:
|
||||
result = None
|
||||
return result
|
||||
result = func(*args, **kwargs)
|
||||
if result is None:
|
||||
result = NONE_RESULT
|
||||
result = func(*args, **kwargs)
|
||||
cache.set(cache_key, result, timeout)
|
||||
return result
|
||||
|
||||
|
|
|
@ -12,12 +12,12 @@ from . import registry
|
|||
def gravatar(profile, size=80, default=None, profile_image=None, email=None):
|
||||
if profile_image:
|
||||
return profile_image
|
||||
if profile and profile.profile_image:
|
||||
return profile.profile_image.url
|
||||
if profile and profile.cached_profile_image:
|
||||
return profile.cached_profile_image.url
|
||||
if profile:
|
||||
email = email or profile.user.email
|
||||
email = email or profile.email
|
||||
if default is None:
|
||||
default = profile.mute
|
||||
default = profile.is_muted
|
||||
gravatar_url = (
|
||||
"//www.gravatar.com/avatar/"
|
||||
+ hashlib.md5(utf8bytes(email.strip().lower())).hexdigest()
|
||||
|
|
|
@ -157,14 +157,14 @@ def item_title(item):
|
|||
@registry.render_with("user/link.html")
|
||||
def link_user(user):
|
||||
if isinstance(user, Profile):
|
||||
user, profile = user.user, user
|
||||
profile = user
|
||||
elif isinstance(user, AbstractUser):
|
||||
profile = user.profile
|
||||
elif type(user).__name__ == "ContestRankingProfile":
|
||||
user, profile = user.user, user
|
||||
profile = user
|
||||
else:
|
||||
raise ValueError("Expected profile or user, got %s" % (type(user),))
|
||||
return {"user": user, "profile": profile}
|
||||
return {"profile": profile}
|
||||
|
||||
|
||||
@registry.function
|
||||
|
|
18
judge/migrations/0172_index_rating.py
Normal file
18
judge/migrations/0172_index_rating.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.18 on 2023-10-10 23:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("judge", "0171_update_notification"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="profile",
|
||||
name="rating",
|
||||
field=models.IntegerField(db_index=True, default=None, null=True),
|
||||
),
|
||||
]
|
|
@ -10,6 +10,9 @@ from django.urls import reverse
|
|||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.dispatch import receiver
|
||||
from django.db.models.signals import post_save, pre_save
|
||||
|
||||
from fernet_fields import EncryptedCharField
|
||||
from sortedm2m.fields import SortedManyToManyField
|
||||
|
||||
|
@ -202,7 +205,7 @@ class Profile(models.Model):
|
|||
help_text=_("User will not be able to vote on problems' point values."),
|
||||
default=False,
|
||||
)
|
||||
rating = models.IntegerField(null=True, default=None)
|
||||
rating = models.IntegerField(null=True, default=None, db_index=True)
|
||||
user_script = models.TextField(
|
||||
verbose_name=_("user script"),
|
||||
default="",
|
||||
|
@ -256,6 +259,21 @@ class Profile(models.Model):
|
|||
max_length=300,
|
||||
)
|
||||
|
||||
@cache_wrapper(prefix="Pgbi")
|
||||
def _get_basic_info(self):
|
||||
return {
|
||||
"first_name": self.user.first_name,
|
||||
"last_name": self.user.last_name,
|
||||
"email": self.user.email,
|
||||
"username": self.user.username,
|
||||
"mute": self.mute,
|
||||
"profile_image": self.profile_image,
|
||||
}
|
||||
|
||||
@cached_property
|
||||
def _cached_info(self):
|
||||
return self._get_basic_info()
|
||||
|
||||
@cached_property
|
||||
def organization(self):
|
||||
# We do this to take advantage of prefetch_related
|
||||
|
@ -264,7 +282,27 @@ class Profile(models.Model):
|
|||
|
||||
@cached_property
|
||||
def username(self):
|
||||
return self.user.username
|
||||
return self._cached_info["username"]
|
||||
|
||||
@cached_property
|
||||
def first_name(self):
|
||||
return self._cached_info["first_name"]
|
||||
|
||||
@cached_property
|
||||
def last_name(self):
|
||||
return self._cached_info["last_name"]
|
||||
|
||||
@cached_property
|
||||
def email(self):
|
||||
return self._cached_info["email"]
|
||||
|
||||
@cached_property
|
||||
def is_muted(self):
|
||||
return self._cached_info["mute"]
|
||||
|
||||
@cached_property
|
||||
def cached_profile_image(self):
|
||||
return self._cached_info["profile_image"]
|
||||
|
||||
@cached_property
|
||||
def count_unseen_notifications(self):
|
||||
|
@ -499,3 +537,18 @@ class OrganizationProfile(models.Model):
|
|||
@classmethod
|
||||
def get_most_recent_organizations(self, users):
|
||||
return self.objects.filter(users=users).order_by("-last_visit")[:5]
|
||||
|
||||
|
||||
@receiver([post_save], sender=User)
|
||||
def on_user_save(sender, instance, **kwargs):
|
||||
profile = instance.profile
|
||||
profile._get_user.dirty(profile)
|
||||
|
||||
|
||||
@receiver([pre_save], sender=Profile)
|
||||
def on_profile_save(sender, instance, **kwargs):
|
||||
if instance.id is None:
|
||||
return
|
||||
prev = sender.objects.get(id=instance.id)
|
||||
if prev.mute != instance.mute or prev.profile_image != instance.profile_image:
|
||||
instance._get_user.dirty(instance)
|
||||
|
|
|
@ -31,10 +31,9 @@ class Resolver(TemplateView):
|
|||
for participation in self.contest.users.filter(virtual=0):
|
||||
cnt_user += 1
|
||||
users[str(cnt_user)] = {
|
||||
"username": participation.user.user.username,
|
||||
"name": participation.user.user.first_name
|
||||
or participation.user.user.username,
|
||||
"school": participation.user.user.last_name,
|
||||
"username": participation.user.username,
|
||||
"name": participation.user.first_name or participation.user.username,
|
||||
"school": participation.user.last_name,
|
||||
"last_submission": participation.cumtime_final,
|
||||
"problems": {},
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ a {
|
|||
.comment-img {
|
||||
display: flex;
|
||||
margin-right: 4px;
|
||||
height: 1.5em;
|
||||
width: 1.5em;
|
||||
}
|
||||
|
||||
.new-comments .comment-display {
|
||||
|
|
|
@ -49,9 +49,9 @@
|
|||
</td>
|
||||
<td>
|
||||
<div>
|
||||
<span class="username {{ item.css_class }} wrapline" href="{{url('user_page', item.user.username)}}" >{{item.user.username}}</span>
|
||||
<span class="username {{ item.css_class }} wrapline" href="{{url('user_page', item.username)}}" >{{item.username}}</span>
|
||||
</div>
|
||||
<div>{{item.user.first_name}}</div>
|
||||
<div>{{item.first_name}}</div>
|
||||
</td>
|
||||
{% for point_contest, rank_contest in item.point_contests %}
|
||||
<td>
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block user_footer %}
|
||||
{% if user.user.first_name %}
|
||||
{% if user.first_name %}
|
||||
<div style="font-weight: 600; display: none" class="fullname gray">
|
||||
{{ user.user.first_name if user.user.first_name else ''}}
|
||||
{{ user.first_name if user.first_name else ''}}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if user.user.last_name %}
|
||||
{% if user.last_name %}
|
||||
<div class="school gray" style="display: none"><a style="font-weight: 600">
|
||||
{{- user.user.last_name -}}
|
||||
{{- user.last_name -}}
|
||||
</a></div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1 +1 @@
|
|||
<span class="{{ profile.css_class }}"><a href="{{ url('user_page', user.username) }}">{{ user.username }}</a></span>
|
||||
<span class="{{ profile.css_class }}"><a href="{{ url('user_page', profile.username) }}">{{ profile.username }}</a></span>
|
||||
|
|
|
@ -54,9 +54,9 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if user.user.first_name %}
|
||||
{% if user.first_name %}
|
||||
<p style="font-size:1.4em; text-align: center;">
|
||||
{{user.user.first_name}}{% if user.user.last_name %} ({{user.user.last_name}}){% endif %}
|
||||
{{user.first_name}}{% if user.last_name %} ({{user.last_name}}){% endif %}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if perms.judge.change_profile %}
|
||||
|
@ -70,9 +70,7 @@
|
|||
{% endif%}
|
||||
{% if user.about %}
|
||||
<h4>{{ _('About') }}</h4>
|
||||
{% cache 86400 'user_about' user.id MATH_ENGINE %}
|
||||
{{ user.about|markdown(lazy_load=True)|reference|str|safe }}
|
||||
{% endcache %}
|
||||
{{ user.about|markdown(lazy_load=True)|reference|str|safe }}
|
||||
{% else %}
|
||||
<i>
|
||||
{% if user.user == request.user %}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
{% block user_footer %}
|
||||
<span style="margin-left: 0.5em">{% if user.rating %}{{ rating_number(user) }}{% endif %}</span>
|
||||
<div class="gray" style="font-weight: 600; margin-top: 0.2em">{{ user.user.first_name if user.user.first_name else ''}}</div>
|
||||
<div class="gray" style="font-weight: 600; margin-top: 0.2em">{{ user.first_name or ''}}</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block after_point_head %}
|
||||
|
@ -39,11 +39,11 @@
|
|||
<td class="user-problem-count">{{ user.problem_count }}</td>
|
||||
<td>
|
||||
<div class="about-td">
|
||||
{% if user.about %}
|
||||
{% cache 86400 'user_about' user.id MATH_ENGINE %}
|
||||
{% cache 86400 'user_about' user.id MATH_ENGINE %}
|
||||
{% if user.about %}
|
||||
{{ user.about|markdown(lazy_load=True)|reference|str|safe }}
|
||||
{% endcache %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endcache %}
|
||||
</div>
|
||||
</td>
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in a new issue