Reformat using black

This commit is contained in:
cuom1999 2022-05-14 12:57:27 -05:00
parent efee4ad081
commit a87fb49918
221 changed files with 19127 additions and 7310 deletions

View file

@ -14,7 +14,14 @@ from django.db.models import Count, Max, Min
from django.db.models.fields import DateField
from django.db.models.functions import Cast, ExtractYear
from django.forms import Form
from django.http import Http404, HttpResponseRedirect, JsonResponse, HttpResponseForbidden, HttpResponseBadRequest, HttpResponse
from django.http import (
Http404,
HttpResponseRedirect,
JsonResponse,
HttpResponseForbidden,
HttpResponseBadRequest,
HttpResponse,
)
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.utils import timezone
@ -36,10 +43,16 @@ from judge.utils.problems import contest_completed_ids, user_completed_ids
from judge.utils.ranker import ranker
from judge.utils.subscription import Subscription
from judge.utils.unicode import utf8text
from judge.utils.views import DiggPaginatorMixin, QueryStringSortMixin, TitleMixin, generic_message, SingleObjectFormView
from judge.utils.views import (
DiggPaginatorMixin,
QueryStringSortMixin,
TitleMixin,
generic_message,
SingleObjectFormView,
)
from .contests import ContestRanking
__all__ = ['UserPage', 'UserAboutPage', 'UserProblemsPage', 'users', 'edit_profile']
__all__ = ["UserPage", "UserAboutPage", "UserProblemsPage", "users", "edit_profile"]
def remap_keys(iterable, mapping):
@ -48,16 +61,16 @@ def remap_keys(iterable, mapping):
class UserMixin(object):
model = Profile
slug_field = 'user__username'
slug_url_kwarg = 'user'
context_object_name = 'user'
slug_field = "user__username"
slug_url_kwarg = "user"
context_object_name = "user"
def render_to_response(self, context, **response_kwargs):
return super(UserMixin, self).render_to_response(context, **response_kwargs)
class UserPage(TitleMixin, UserMixin, DetailView):
template_name = 'user/user-base.html'
template_name = "user/user-base.html"
def get_object(self, queryset=None):
if self.kwargs.get(self.slug_url_kwarg, None) is None:
@ -71,12 +84,18 @@ class UserPage(TitleMixin, UserMixin, DetailView):
try:
return super(UserPage, self).dispatch(request, *args, **kwargs)
except Http404:
return generic_message(request, _('No such user'), _('No user handle "%s".') %
self.kwargs.get(self.slug_url_kwarg, None))
return generic_message(
request,
_("No such user"),
_('No user handle "%s".') % self.kwargs.get(self.slug_url_kwarg, None),
)
def get_title(self):
return (_('My account') if self.request.user == self.object.user else
_('User %s') % self.object.user.username)
return (
_("My account")
if self.request.user == self.object.user
else _("User %s") % self.object.user.username
)
def get_content_title(self):
username = self.object.user.username
@ -92,8 +111,11 @@ class UserPage(TitleMixin, UserMixin, DetailView):
@cached_property
def in_contest(self):
return self.profile is not None and self.profile.current_contest is not None \
return (
self.profile is not None
and self.profile.current_contest is not None
and self.request.in_contest_mode
)
def get_completed_problems(self):
if self.in_contest:
@ -104,29 +126,49 @@ class UserPage(TitleMixin, UserMixin, DetailView):
def get_context_data(self, **kwargs):
context = super(UserPage, self).get_context_data(**kwargs)
context['followed'] = Friend.is_friend(self.request.profile, self.object)
context['hide_solved'] = int(self.hide_solved)
context['authored'] = self.object.authored_problems.filter(is_public=True, is_organization_private=False) \
.order_by('code')
context["followed"] = Friend.is_friend(self.request.profile, self.object)
context["hide_solved"] = int(self.hide_solved)
context["authored"] = self.object.authored_problems.filter(
is_public=True, is_organization_private=False
).order_by("code")
rating = self.object.ratings.order_by('-contest__end_time')[:1]
context['rating'] = rating[0] if rating else None
rating = self.object.ratings.order_by("-contest__end_time")[:1]
context["rating"] = rating[0] if rating else None
context['rank'] = Profile.objects.filter(
is_unlisted=False, performance_points__gt=self.object.performance_points,
).count() + 1
context["rank"] = (
Profile.objects.filter(
is_unlisted=False,
performance_points__gt=self.object.performance_points,
).count()
+ 1
)
if rating:
context['rating_rank'] = Profile.objects.filter(
is_unlisted=False, rating__gt=self.object.rating,
).count() + 1
context['rated_users'] = Profile.objects.filter(is_unlisted=False, rating__isnull=False).count()
context.update(self.object.ratings.aggregate(min_rating=Min('rating'), max_rating=Max('rating'),
contests=Count('contest')))
context["rating_rank"] = (
Profile.objects.filter(
is_unlisted=False,
rating__gt=self.object.rating,
).count()
+ 1
)
context["rated_users"] = Profile.objects.filter(
is_unlisted=False, rating__isnull=False
).count()
context.update(
self.object.ratings.aggregate(
min_rating=Min("rating"),
max_rating=Max("rating"),
contests=Count("contest"),
)
)
return context
def get(self, request, *args, **kwargs):
self.hide_solved = request.GET.get('hide_solved') == '1' if 'hide_solved' in request.GET else False
self.hide_solved = (
request.GET.get("hide_solved") == "1"
if "hide_solved" in request.GET
else False
)
return super(UserPage, self).get(request, *args, **kwargs)
@ -134,20 +176,27 @@ EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
class UserAboutPage(UserPage):
template_name = 'user/user-about.html'
template_name = "user/user-about.html"
def get_awards(self, ratings):
result = {}
sorted_ratings = sorted(ratings,
key=lambda x: (x.rank, -x.contest.end_time.timestamp()))
sorted_ratings = sorted(
ratings, key=lambda x: (x.rank, -x.contest.end_time.timestamp())
)
result['medals'] = [{
'label': rating.contest.name,
'ranking': rating.rank,
'link': reverse('contest_ranking', args=(rating.contest.key,)) + '#!' + self.object.username,
'date': date_format(rating.contest.end_time, _('M j, Y')),
} for rating in sorted_ratings if rating.rank <= 3]
result["medals"] = [
{
"label": rating.contest.name,
"ranking": rating.rank,
"link": reverse("contest_ranking", args=(rating.contest.key,))
+ "#!"
+ self.object.username,
"date": date_format(rating.contest.end_time, _("M j, Y")),
}
for rating in sorted_ratings
if rating.rank <= 3
]
num_awards = 0
for i in result:
@ -160,60 +209,86 @@ class UserAboutPage(UserPage):
def get_context_data(self, **kwargs):
context = super(UserAboutPage, self).get_context_data(**kwargs)
ratings = context['ratings'] = self.object.ratings.order_by('-contest__end_time').select_related('contest') \
.defer('contest__description')
context['rating_data'] = mark_safe(json.dumps([{
'label': rating.contest.name,
'rating': rating.rating,
'ranking': rating.rank,
'link': reverse('contest_ranking', args=(rating.contest.key,)),
'timestamp': (rating.contest.end_time - EPOCH).total_seconds() * 1000,
'date': date_format(timezone.localtime(rating.contest.end_time), _('M j, Y, G:i')),
'class': rating_class(rating.rating),
'height': '%.3fem' % rating_progress(rating.rating),
} for rating in ratings]))
context['awards'] = self.get_awards(ratings)
if ratings:
user_data = self.object.ratings.aggregate(Min('rating'), Max('rating'))
global_data = Rating.objects.aggregate(Min('rating'), Max('rating'))
min_ever, max_ever = global_data['rating__min'], global_data['rating__max']
min_user, max_user = user_data['rating__min'], user_data['rating__max']
delta = max_user - min_user
ratio = (max_ever - max_user) / (max_ever - min_ever) if max_ever != min_ever else 1.0
context['max_graph'] = max_user + ratio * delta
context['min_graph'] = min_user + ratio * delta - delta
submissions = (
self.object.submission_set
.annotate(date_only=Cast('date', DateField()))
.values('date_only').annotate(cnt=Count('id'))
ratings = context["ratings"] = (
self.object.ratings.order_by("-contest__end_time")
.select_related("contest")
.defer("contest__description")
)
context["rating_data"] = mark_safe(
json.dumps(
[
{
"label": rating.contest.name,
"rating": rating.rating,
"ranking": rating.rank,
"link": reverse("contest_ranking", args=(rating.contest.key,)),
"timestamp": (rating.contest.end_time - EPOCH).total_seconds()
* 1000,
"date": date_format(
timezone.localtime(rating.contest.end_time),
_("M j, Y, G:i"),
),
"class": rating_class(rating.rating),
"height": "%.3fem" % rating_progress(rating.rating),
}
for rating in ratings
]
)
)
context["awards"] = self.get_awards(ratings)
if ratings:
user_data = self.object.ratings.aggregate(Min("rating"), Max("rating"))
global_data = Rating.objects.aggregate(Min("rating"), Max("rating"))
min_ever, max_ever = global_data["rating__min"], global_data["rating__max"]
min_user, max_user = user_data["rating__min"], user_data["rating__max"]
delta = max_user - min_user
ratio = (
(max_ever - max_user) / (max_ever - min_ever)
if max_ever != min_ever
else 1.0
)
context["max_graph"] = max_user + ratio * delta
context["min_graph"] = min_user + ratio * delta - delta
submissions = (
self.object.submission_set.annotate(date_only=Cast("date", DateField()))
.values("date_only")
.annotate(cnt=Count("id"))
)
context["submission_data"] = mark_safe(
json.dumps(
{
date_counts["date_only"].isoformat(): date_counts["cnt"]
for date_counts in submissions
}
)
)
context["submission_metadata"] = mark_safe(
json.dumps(
{
"min_year": (
self.object.submission_set.annotate(
year_only=ExtractYear("date")
).aggregate(min_year=Min("year_only"))["min_year"]
),
}
)
)
context['submission_data'] = mark_safe(json.dumps({
date_counts['date_only'].isoformat(): date_counts['cnt'] for date_counts in submissions
}))
context['submission_metadata'] = mark_safe(json.dumps({
'min_year': (
self.object.submission_set
.annotate(year_only=ExtractYear('date'))
.aggregate(min_year=Min('year_only'))['min_year']
),
}))
return context
# follow/unfollow user
def post(self, request, user, *args, **kwargs):
try:
if not request.profile:
raise Exception('You have to login')
if (request.profile.username == user):
raise Exception('Cannot make friend with yourself')
raise Exception("You have to login")
if request.profile.username == user:
raise Exception("Cannot make friend with yourself")
following_profile = Profile.objects.get(user__username=user)
Friend.toggle_friend(request.profile, following_profile)
finally:
@ -221,60 +296,86 @@ class UserAboutPage(UserPage):
class UserProblemsPage(UserPage):
template_name = 'user/user-problems.html'
template_name = "user/user-problems.html"
def get_context_data(self, **kwargs):
context = super(UserProblemsPage, self).get_context_data(**kwargs)
result = Submission.objects.filter(user=self.object, points__gt=0, problem__is_public=True,
problem__is_organization_private=False) \
.exclude(problem__in=self.get_completed_problems() if self.hide_solved else []) \
.values('problem__id', 'problem__code', 'problem__name', 'problem__points', 'problem__group__full_name') \
.distinct().annotate(points=Max('points')).order_by('problem__group__full_name', 'problem__code')
result = (
Submission.objects.filter(
user=self.object,
points__gt=0,
problem__is_public=True,
problem__is_organization_private=False,
)
.exclude(
problem__in=self.get_completed_problems() if self.hide_solved else []
)
.values(
"problem__id",
"problem__code",
"problem__name",
"problem__points",
"problem__group__full_name",
)
.distinct()
.annotate(points=Max("points"))
.order_by("problem__group__full_name", "problem__code")
)
def process_group(group, problems_iter):
problems = list(problems_iter)
points = sum(map(itemgetter('points'), problems))
return {'name': group, 'problems': problems, 'points': points}
points = sum(map(itemgetter("points"), problems))
return {"name": group, "problems": problems, "points": points}
context['best_submissions'] = [
process_group(group, problems) for group, problems in itertools.groupby(
remap_keys(result, {
'problem__code': 'code', 'problem__name': 'name', 'problem__points': 'total',
'problem__group__full_name': 'group',
}), itemgetter('group'))
context["best_submissions"] = [
process_group(group, problems)
for group, problems in itertools.groupby(
remap_keys(
result,
{
"problem__code": "code",
"problem__name": "name",
"problem__points": "total",
"problem__group__full_name": "group",
},
),
itemgetter("group"),
)
]
breakdown, has_more = get_pp_breakdown(self.object, start=0, end=10)
context['pp_breakdown'] = breakdown
context['pp_has_more'] = has_more
context["pp_breakdown"] = breakdown
context["pp_has_more"] = has_more
return context
class UserPerformancePointsAjax(UserProblemsPage):
template_name = 'user/pp-table-body.html'
template_name = "user/pp-table-body.html"
def get_context_data(self, **kwargs):
context = super(UserPerformancePointsAjax, self).get_context_data(**kwargs)
try:
start = int(self.request.GET.get('start', 0))
end = int(self.request.GET.get('end', settings.DMOJ_PP_ENTRIES))
start = int(self.request.GET.get("start", 0))
end = int(self.request.GET.get("end", settings.DMOJ_PP_ENTRIES))
if start < 0 or end < 0 or start > end:
raise ValueError
except ValueError:
start, end = 0, 100
breakdown, self.has_more = get_pp_breakdown(self.object, start=start, end=end)
context['pp_breakdown'] = breakdown
context["pp_breakdown"] = breakdown
return context
def get(self, request, *args, **kwargs):
httpresp = super(UserPerformancePointsAjax, self).get(request, *args, **kwargs)
httpresp.render()
return JsonResponse({
'results': utf8text(httpresp.content),
'has_more': self.has_more,
})
return JsonResponse(
{
"results": utf8text(httpresp.content),
"has_more": self.has_more,
}
)
@login_required
@ -282,26 +383,39 @@ def edit_profile(request):
profile = Profile.objects.get(user=request.user)
if profile.mute:
raise Http404()
if request.method == 'POST':
if request.method == "POST":
form = ProfileForm(request.POST, instance=profile, user=request.user)
if form.is_valid():
with transaction.atomic(), revisions.create_revision():
form.save()
revisions.set_user(request.user)
revisions.set_comment(_('Updated on site'))
revisions.set_comment(_("Updated on site"))
if newsletter_id is not None:
try:
subscription = Subscription.objects.get(user=request.user, newsletter_id=newsletter_id)
subscription = Subscription.objects.get(
user=request.user, newsletter_id=newsletter_id
)
except Subscription.DoesNotExist:
if form.cleaned_data['newsletter']:
Subscription(user=request.user, newsletter_id=newsletter_id, subscribed=True).save()
if form.cleaned_data["newsletter"]:
Subscription(
user=request.user,
newsletter_id=newsletter_id,
subscribed=True,
).save()
else:
if subscription.subscribed != form.cleaned_data['newsletter']:
subscription.update(('unsubscribe', 'subscribe')[form.cleaned_data['newsletter']])
if subscription.subscribed != form.cleaned_data["newsletter"]:
subscription.update(
("unsubscribe", "subscribe")[
form.cleaned_data["newsletter"]
]
)
perm = Permission.objects.get(codename='test_site', content_type=ContentType.objects.get_for_model(Profile))
if form.cleaned_data['test_site']:
perm = Permission.objects.get(
codename="test_site",
content_type=ContentType.objects.get_for_model(Profile),
)
if form.cleaned_data["test_site"]:
request.user.user_permissions.add(perm)
else:
request.user.user_permissions.remove(perm)
@ -311,34 +425,42 @@ def edit_profile(request):
form = ProfileForm(instance=profile, user=request.user)
if newsletter_id is not None:
try:
subscription = Subscription.objects.get(user=request.user, newsletter_id=newsletter_id)
subscription = Subscription.objects.get(
user=request.user, newsletter_id=newsletter_id
)
except Subscription.DoesNotExist:
form.fields['newsletter'].initial = False
form.fields["newsletter"].initial = False
else:
form.fields['newsletter'].initial = subscription.subscribed
form.fields['test_site'].initial = request.user.has_perm('judge.test_site')
form.fields["newsletter"].initial = subscription.subscribed
form.fields["test_site"].initial = request.user.has_perm("judge.test_site")
tzmap = settings.TIMEZONE_MAP
print(settings.REGISTER_NAME_URL)
return render(request, 'user/edit-profile.html', {
'edit_name_url': settings.REGISTER_NAME_URL,
'require_staff_2fa': settings.DMOJ_REQUIRE_STAFF_2FA,
'form': form, 'title': _('Edit profile'), 'profile': profile,
'has_math_config': bool(settings.MATHOID_URL),
'TIMEZONE_MAP': tzmap or 'http://momentjs.com/static/img/world.png',
'TIMEZONE_BG': settings.TIMEZONE_BG if tzmap else '#4E7CAD',
})
return render(
request,
"user/edit-profile.html",
{
"edit_name_url": settings.REGISTER_NAME_URL,
"require_staff_2fa": settings.DMOJ_REQUIRE_STAFF_2FA,
"form": form,
"title": _("Edit profile"),
"profile": profile,
"has_math_config": bool(settings.MATHOID_URL),
"TIMEZONE_MAP": tzmap or "http://momentjs.com/static/img/world.png",
"TIMEZONE_BG": settings.TIMEZONE_BG if tzmap else "#4E7CAD",
},
)
class UserList(QueryStringSortMixin, DiggPaginatorMixin, TitleMixin, ListView):
model = Profile
title = gettext_lazy('Leaderboard')
context_object_name = 'users'
template_name = 'user/list.html'
title = gettext_lazy("Leaderboard")
context_object_name = "users"
template_name = "user/list.html"
paginate_by = 100
all_sorts = frozenset(('points', 'problem_count', 'rating', 'performance_points'))
all_sorts = frozenset(("points", "problem_count", "rating", "performance_points"))
default_desc = all_sorts
default_sort = '-performance_points'
default_sort = "-performance_points"
def filter_friend_queryset(self, queryset):
friends = list(self.request.profile.get_friends())
@ -346,18 +468,30 @@ class UserList(QueryStringSortMixin, DiggPaginatorMixin, TitleMixin, ListView):
return ret
def get_queryset(self):
ret = Profile.objects.filter(is_unlisted=False).order_by(self.order, 'id').select_related('user') \
.only('display_rank', 'user__username', 'points', 'rating', 'performance_points',
'problem_count')
ret = (
Profile.objects.filter(is_unlisted=False)
.order_by(self.order, "id")
.select_related("user")
.only(
"display_rank",
"user__username",
"points",
"rating",
"performance_points",
"problem_count",
)
)
if (self.request.GET.get('friend') == 'true') and self.request.profile:
if (self.request.GET.get("friend") == "true") and self.request.profile:
ret = self.filter_friend_queryset(ret)
return ret
def get_context_data(self, **kwargs):
context = super(UserList, self).get_context_data(**kwargs)
context['users'] = ranker(context['users'], rank=self.paginate_by * (context['page_obj'].number - 1))
context['first_page_href'] = '.'
context["users"] = ranker(
context["users"], rank=self.paginate_by * (context["page_obj"].number - 1)
)
context["first_page_href"] = "."
context.update(self.get_sort_context())
context.update(self.get_sort_paginate_context())
return context
@ -378,27 +512,36 @@ def users(request):
if request.in_contest_mode:
participation = request.profile.current_contest
contest = participation.contest
return FixedContestRanking.as_view(contest=contest)(request, contest=contest.key)
return FixedContestRanking.as_view(contest=contest)(
request, contest=contest.key
)
return user_list_view(request)
def user_ranking_redirect(request):
try:
username = request.GET['handle']
username = request.GET["handle"]
except KeyError:
raise Http404()
user = get_object_or_404(Profile, user__username=username)
rank = Profile.objects.filter(is_unlisted=False, performance_points__gt=user.performance_points).count()
rank = Profile.objects.filter(
is_unlisted=False, performance_points__gt=user.performance_points
).count()
rank += Profile.objects.filter(
is_unlisted=False, performance_points__exact=user.performance_points, id__lt=user.id,
is_unlisted=False,
performance_points__exact=user.performance_points,
id__lt=user.id,
).count()
page = rank // UserList.paginate_by
return HttpResponseRedirect('%s%s#!%s' % (reverse('user_list'), '?page=%d' % (page + 1) if page else '', username))
return HttpResponseRedirect(
"%s%s#!%s"
% (reverse("user_list"), "?page=%d" % (page + 1) if page else "", username)
)
class UserLogoutView(TitleMixin, TemplateView):
template_name = 'registration/logout.html'
title = 'You have been successfully logged out.'
template_name = "registration/logout.html"
title = "You have been successfully logged out."
def post(self, request, *args, **kwargs):
auth_logout(request)
@ -406,8 +549,8 @@ class UserLogoutView(TitleMixin, TemplateView):
class ImportUsersView(TitleMixin, TemplateView):
template_name = 'user/import/index.html'
title = _('Import Users')
template_name = "user/import/index.html"
title = _("Import Users")
def get(self, *args, **kwargs):
if self.request.user.is_superuser:
@ -416,43 +559,38 @@ class ImportUsersView(TitleMixin, TemplateView):
def import_users_post_file(request):
if not request.user.is_superuser or request.method != 'POST':
if not request.user.is_superuser or request.method != "POST":
return HttpResponseForbidden()
users = import_users.csv_to_dict(request.FILES['csv_file'])
users = import_users.csv_to_dict(request.FILES["csv_file"])
if not users:
return JsonResponse({
'done': False,
'msg': 'No valid row found. Make sure row containing username.'
})
table_html = render_to_string('user/import/table_csv.html', {
'data': users
})
return JsonResponse({
'done': True,
'html': table_html,
'data': users
})
return JsonResponse(
{
"done": False,
"msg": "No valid row found. Make sure row containing username.",
}
)
table_html = render_to_string("user/import/table_csv.html", {"data": users})
return JsonResponse({"done": True, "html": table_html, "data": users})
def import_users_submit(request):
import json
if not request.user.is_superuser or request.method != 'POST':
if not request.user.is_superuser or request.method != "POST":
return HttpResponseForbidden()
users = json.loads(request.body)['users']
users = json.loads(request.body)["users"]
log = import_users.import_users(users)
return JsonResponse({
'msg': log
})
return JsonResponse({"msg": log})
def sample_import_users(request):
if not request.user.is_superuser or request.method != 'GET':
if not request.user.is_superuser or request.method != "GET":
return HttpResponseForbidden()
filename = 'import_sample.csv'
content = ','.join(import_users.fields) + '\n' + ','.join(import_users.descriptions)
response = HttpResponse(content, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename={0}'.format(filename)
return response
filename = "import_sample.csv"
content = ",".join(import_users.fields) + "\n" + ",".join(import_users.descriptions)
response = HttpResponse(content, content_type="text/plain")
response["Content-Disposition"] = "attachment; filename={0}".format(filename)
return response