def problems(request, template='problems.html', extra_context=None): problems = Problem.objects.all() problems = problems.select_related('contest', 'resource') problems = problems.prefetch_related('tags') problems = problems.order_by('-time', 'contest_id', 'index') problems = problems.filter(contest__end_time__lt=timezone.now(), visible=True) search = request.GET.get('search') if search: cond, problems = get_iregex_filter( search, 'name', 'contest__title', 'contest__host', logger=request.logger, mapping={ 'name': { 'fields': ['name__iregex'] }, 'contest': { 'fields': ['contest__title__iregex'] }, 'resource': { 'fields': ['resource__host__iregex'] }, 'tag': { 'fields': ['problemtag__name__iregex'], 'exists': 'tags' }, 'cid': { 'fields': ['contest_id'], 'func': lambda v: int(v) }, 'rid': { 'fields': ['resource_id'], 'func': lambda v: int(v) }, 'pid': { 'fields': ['id'], 'func': lambda v: int(v) }, }, queryset=problems) problems = problems.filter(cond) context = { 'problems': problems, 'timeformat': get_timeformat(request), 'timezone': get_timezone(request), } if extra_context is not None: context.update(extra_context) return render(request, template, context)
def coders(request, template='coders.html'): coders = Coder.objects.select_related('user') params = {} search = request.GET.get('search') if search: filt = get_iregex_filter(search, 'username', logger=request.logger) coders = coders.filter(filt) countries = request.GET.getlist('country') countries = set([c for c in countries if c]) if countries: coders = coders.annotate(filter_country=Exists('account', filter=Q(account__country__in=countries))) coders = coders.filter(Q(country__in=countries) | Q(filter_country=True)) params['countries'] = countries resources = request.GET.getlist('resource') if resources: resources = [r for r in resources if r] resources = list(Resource.objects.filter(pk__in=resources)) for r in resources: coders = coders.annotate(**{f'{r.pk}_rating': SubqueryMax('account__rating', filter=Q(resource=r))}) coders = coders.annotate(**{f'{r.pk}_n_contests': SubquerySum('account__n_contests', filter=Q(resource=r))}) params['resources'] = resources # ordering orderby = request.GET.get('sort_column') if orderby in ['username', 'created', 'n_accounts']: pass elif orderby and orderby.startswith('resource_'): _, pk = orderby.split('_') orderby = [f'{pk}_rating', f'{pk}_n_contests'] elif orderby: request.logger.error(f'Not found `{orderby}` column for sorting') orderby = [] orderby = orderby if not orderby or isinstance(orderby, list) else [orderby] order = request.GET.get('sort_order') if order in ['asc', 'desc']: orderby = [getattr(F(o), order)(nulls_last=True) for o in orderby] elif order: request.logger.error(f'Not found `{order}` order for sorting') orderby = orderby or ['-created'] coders = coders.order_by(*orderby) context = { 'coders': coders, 'params': params, } return template, context
def standings_list(request, template='standings_list.html', extra_context=None): contests = Contest.objects \ .select_related('timing') \ .annotate(has_statistics=Exists(Statistics.objects.filter(contest=OuterRef('pk')))) \ .annotate(has_module=Exists(Module.objects.filter(resource=OuterRef('resource_id')))) \ .filter(Q(has_statistics=True) | Q(end_time__lte=timezone.now())) \ .order_by('-end_time') all_standings = False if request.user.is_authenticated: all_standings = request.user.coder.settings.get('all_standings') switch = 'switch' in request.GET if bool(all_standings) == bool(switch): contests = contests.filter(has_statistics=True, has_module=True) if request.user.is_authenticated: contests = contests.filter(request.user.coder.get_contest_filter(['list'])) search = request.GET.get('search') if search is not None: contests = contests.filter(get_iregex_filter(search, 'title', 'host', 'resource__host', mapping={ 'slug': {'fields': ['slug']}, 'writer': {'fields': ['info__writers__contains']}, 'medal': {'fields': ['info__standings__medals'], 'suff': '__isnull', 'func': lambda v: False}, }, logger=request.logger)) context = { 'contests': contests, 'timezone': get_timezone(request), 'timeformat': get_timeformat(request), 'all_standings': all_standings, 'switch': switch, } if extra_context is not None: context.update(extra_context) return render(request, template, context)
def standings_list(request, template='standings_list.html', extra_context=None): contests = Contest.objects \ .select_related('timing') \ .annotate(has_statistics=Exists(Statistics.objects.filter(contest=OuterRef('pk')))) \ .annotate(has_module=Exists(Module.objects.filter(resource=OuterRef('resource_id')))) \ .filter(Q(has_statistics=True) | Q(end_time__lte=timezone.now())) \ .order_by('-end_time', 'pk') has_perm_reset_statistic_timing = False all_standings = False if request.user.is_authenticated: all_standings = request.user.coder.settings.get('all_standings') has_perm_reset_statistic_timing = request.user.has_perm( 'reset_contest_statistic_timing') switch = 'switch' in request.GET if bool(all_standings) == bool(switch): contests = contests.filter(has_statistics=True, has_module=True) if request.user.is_authenticated: contests = contests.filter( request.user.coder.get_contest_filter(['list'])) search = request.GET.get('search') if search is not None: contests = contests.filter( get_iregex_filter(search, 'title', 'resource__host')) context = { 'contests': contests, 'timezone': get_timezone(request), 'timeformat': get_timeformat(request), 'all_standings': all_standings, 'has_perm_reset_statistic_timing': has_perm_reset_statistic_timing, 'switch': switch, } if extra_context is not None: context.update(extra_context) return render(request, template, context)
def standings(request, title_slug=None, contest_id=None, template='standings.html', extra_context=None): context = {} groupby = request.GET.get('groupby') if groupby == 'none': groupby = None search = request.GET.get('search') if search == '': url = request.get_full_path() url = re.sub('search=&?', '', url) url = re.sub(r'\?$', '', url) return redirect(url) orderby = request.GET.getlist('orderby') if orderby: if '--' in orderby: updated_orderby = [] else: orderby_set = set() unique_orderby = reversed([ f for k, f in [(f.lstrip('-'), f) for f in reversed(orderby)] if k not in orderby_set and not orderby_set.add(k) ]) updated_orderby = [ f for f in unique_orderby if not f.startswith('--') ] if updated_orderby != orderby: query = request.GET.copy() query.setlist('orderby', updated_orderby) return redirect(f'{request.path}?{query.urlencode()}') contests = Contest.objects to_redirect = False contest = None if contest_id is not None: contest = contests.filter(pk=contest_id).first() if title_slug is None: to_redirect = True else: if contest is None or slug(contest.title) != title_slug: contest = None title_slug += f'-{contest_id}' if contest is None and title_slug is not None: contests_iterator = contests.filter(slug=title_slug).iterator() contest = None try: contest = next(contests_iterator) another = next(contests_iterator) except StopIteration: another = None if contest is None: return HttpResponseNotFound() if another is None: to_redirect = True else: return redirect( reverse('ranking:standings_list') + f'?search=slug:{title_slug}') if contest is None: return HttpResponseNotFound() if to_redirect: query = query_transform(request) url = reverse('ranking:standings', kwargs={ 'title_slug': slug(contest.title), 'contest_id': str(contest.pk) }) if query: query = '?' + query return redirect(url + query) with_detail = request.GET.get('detail', 'true') in ['true', 'on'] if request.user.is_authenticated: coder = request.user.coder if 'detail' in request.GET: coder.settings['standings_with_detail'] = with_detail coder.save() else: with_detail = coder.settings.get('standings_with_detail', False) else: coder = None with_row_num = False contest_fields = list(contest.info.get('fields', [])) hidden_fields = list(contest.info.get('hidden_fields', [])) statistics = Statistics.objects.filter(contest=contest) options = contest.info.get('standings', {}) order = None resource_standings = contest.resource.info.get('standings', {}) order = copy.copy(options.get('order', resource_standings.get('order'))) if order: for f in order: if f.startswith('addition__') and f.split( '__', 1)[1] not in contest_fields: order = None break if order is None: order = ['place_as_int', '-solving'] # fixed fields fixed_fields = ( ('penalty', 'Penalty'), ('total_time', 'Time'), ('advanced', 'Advance'), ) fixed_fields += tuple(options.get('fixed_fields', [])) if not with_detail: fixed_fields += (('rating_change', 'Rating change'), ) statistics = statistics \ .select_related('account') \ .select_related('account__resource') \ .prefetch_related('account__coders') has_country = ('country' in contest_fields or '_countries' in contest_fields or statistics.filter(account__country__isnull=False).exists()) division = request.GET.get('division') if division == 'any': with_row_num = True if 'place_as_int' in order: order.remove('place_as_int') order.append('place_as_int') fixed_fields += (('division', 'Division'), ) if 'team_id' in contest_fields and not groupby: order.append('addition__name') statistics = statistics.distinct(*[f.lstrip('-') for f in order]) # host = resource_standings.get('account_team_resource', contest.resource.host) # account_team_resource = Resource.objects.get(host=host) # context['account_team_resource'] = account_team_resource # statistics = statistics.annotate( # accounts=RawSQL( # ''' # SELECT array_agg(array[u2.key, u3.rating::text, u3.url]) # FROM "ranking_statistics" U0 # INNER JOIN "ranking_account" U2 # ON (u0."account_id" = u2."id") # INNER JOIN "ranking_account" U3 # ON (u2."key" = u3."key" AND u3."resource_id" = %s) # WHERE ( # u0."contest_id" = %s # AND ("u0"."addition" -> 'team_id') = ("ranking_statistics"."addition" -> 'team_id') # ) # ''', # [account_team_resource.pk, contest.pk] # ) # ) order.append('pk') statistics = statistics.order_by(*order) fields = OrderedDict() for k, v in fixed_fields: if k in contest_fields: fields[k] = v n_highlight_context = _standings_highlight(statistics, options) # field to select fields_to_select_defaults = { 'rating': { 'options': ['rated', 'unrated'], 'noajax': True, 'nomultiply': True, 'nourl': True }, 'advanced': { 'options': ['true', 'false'], 'noajax': True, 'nomultiply': True }, 'highlight': { 'options': ['true', 'false'], 'noajax': True, 'nomultiply': True }, } fields_to_select = OrderedDict() map_fields_to_select = {'rating_change': 'rating'} for f in sorted(contest_fields): f = f.strip('_') if f.lower() in [ 'institution', 'room', 'affiliation', 'city', 'languages', 'school', 'class', 'job', 'region', 'rating_change', 'advanced', 'company', 'language', 'league', 'onsite', 'degree', 'university', 'list', ]: f = map_fields_to_select.get(f, f) field_to_select = fields_to_select.setdefault(f, {}) field_to_select['values'] = [ v for v in request.GET.getlist(f) if v ] field_to_select.update(fields_to_select_defaults.get(f, {})) if n_highlight_context.get('statistics_ids'): f = 'highlight' field_to_select = fields_to_select.setdefault(f, {}) field_to_select['values'] = [v for v in request.GET.getlist(f) if v] field_to_select.update(fields_to_select_defaults.get(f, {})) chats = coder.chats.all() if coder else None if chats: options_values = {c.chat_id: c.title for c in chats} fields_to_select['chat'] = { 'values': [ v for v in request.GET.getlist('chat') if v and v in options_values ], 'options': options_values, 'noajax': True, 'nogroupby': True, 'nourl': True, } hidden_fields_values = [v for v in request.GET.getlist('field') if v] for v in hidden_fields_values: if v not in hidden_fields: hidden_fields.append(v) for k in contest_fields: if (k in fields or k in [ 'problems', 'team_id', 'solved', 'hack', 'challenges', 'url', 'participant_type', 'division' ] or k == 'medal' and '_medal_title_field' in contest_fields or 'country' in k and k not in hidden_fields_values or k in ['name'] and k not in hidden_fields_values or k.startswith('_') or k in hidden_fields and k not in hidden_fields_values): continue if with_detail or k in hidden_fields_values: fields[k] = k else: hidden_fields.append(k) for k, field in fields.items(): if k != field: continue field = ' '.join(k.split('_')) if field and not field[0].isupper(): field = field.title() fields[k] = field if hidden_fields: fields_to_select['field'] = { 'values': hidden_fields_values, 'options': hidden_fields, 'noajax': True, 'nogroupby': True, 'nourl': True, 'nofilter': True, } per_page = options.get('per_page', 50) if per_page is None: per_page = 100500 elif contest.n_statistics and contest.n_statistics < 500: per_page = contest.n_statistics mod_penalty = {} first = statistics.first() if first and all('time' not in k for k in contest_fields): penalty = first.addition.get('penalty') if penalty and isinstance(penalty, int) and 'solved' not in first.addition: mod_penalty.update({'solving': first.solving, 'penalty': penalty}) params = {} problems = contest.info.get('problems', {}) if 'division' in problems: divisions_order = list( problems.get('divisions_order', sorted(contest.info['problems']['division'].keys()))) elif 'divisions_order' in contest.info: divisions_order = contest.info['divisions_order'] else: divisions_order = [] if divisions_order: divisions_order.append('any') if division not in divisions_order: division = divisions_order[0] params['division'] = division if 'division' in problems: if division == 'any': _problems = OrderedDict() for div in reversed(divisions_order): for p in problems['division'].get(div, []): k = get_problem_short(p) if k not in _problems: _problems[k] = p else: for f in 'n_accepted', 'n_teams', 'n_partial', 'n_total': if f in p: _problems[k][f] = _problems[k].get( f, 0) + p[f] problems = list(_problems.values()) else: problems = problems['division'][division] if division != 'any': statistics = statistics.filter(addition__division=division) for p in problems: if 'full_score' in p and isinstance( p['full_score'], (int, float)) and abs(p['full_score'] - 1) > 1e-9: mod_penalty = {} break last = None merge_problems = False for p in problems: if last and (last.get('full_score') or last.get('subname')) and ( 'name' in last and last.get('name') == p.get('name') or 'group' in last and last.get('group') == p.get('group')): merge_problems = True last['colspan'] = last.get('colspan', 1) + 1 p['skip'] = True else: last = p last['colspan'] = 1 # own_stat = statistics.filter(account__coders=coder).first() if coder else None # filter by search search = request.GET.get('search') if search: with_row_num = True if search.startswith('party:'): _, party_slug = search.split(':') party = get_object_or_404(Party.objects.for_user(request.user), slug=party_slug) statistics = statistics.filter( Q(account__coders__in=party.coders.all()) | Q(account__coders__in=party.admins.all()) | Q(account__coders=party.author)) else: cond = get_iregex_filter(search, 'account__key', 'addition__name', logger=request.logger) statistics = statistics.filter(cond) # filter by country countries = request.GET.getlist('country') countries = set([c for c in countries if c]) if countries: with_row_num = True cond = Q(account__country__in=countries) if 'None' in countries: cond |= Q(account__country__isnull=True) if '_countries' in contest_fields: for code in countries: name = get_country_name(code) if name: cond |= Q(addition___countries__icontains=name) statistics = statistics.filter(cond) params['countries'] = countries # filter by field to select for field, field_to_select in fields_to_select.items(): values = field_to_select.get('values') if not values or field_to_select.get('nofilter'): continue with_row_num = True filt = Q() if field == 'languages': for lang in values: if lang == 'any': filt = Q(**{'addition___languages__isnull': False}) break filt |= Q(**{'addition___languages__contains': [lang]}) elif field == 'rating': for q in values: if q not in field_to_select['options']: continue q = q == 'unrated' if q: filt |= Q(addition__rating_change__isnull=True) & Q( addition__new_rating__isnull=True) else: filt |= Q(addition__rating_change__isnull=False) | Q( addition__new_rating__isnull=False) elif field == 'advanced': for q in values: if q not in field_to_select['options']: continue filt |= Q(addition__advanced=q == 'true') elif field == 'highlight': for q in values: if q not in field_to_select['options']: continue filt = Q(pk__in=n_highlight_context.get('statistics_ids', {})) if q == 'false': filt = ~filt elif field == 'chat': for q in values: if q not in field_to_select['options']: continue chat = Chat.objects.filter(chat_id=q, is_group=True).first() if chat: filt |= Q(account__coders__in=chat.coders.all()) # subquery = Chat.objects.filter(coder=OuterRef('account__coders'), is_group=False).values('name')[:1] # statistics = statistics.annotate(chat_name=Subquery(subquery)) else: query_field = f'addition__{field}' statistics = statistics.annotate(**{ f'{query_field}_str': Cast(JSONF(query_field), models.TextField()) }) for q in values: if q == 'None': filt |= Q(**{f'{query_field}__isnull': True}) else: filt |= Q(**{f'{query_field}_str': q}) statistics = statistics.filter(filt) # groupby if groupby == 'country' or groupby in fields_to_select: statistics = statistics.order_by('pk') participants_info = n_highlight_context.get('participants_info') n_highlight = options.get('n_highlight') advanced_by_participants_info = participants_info and n_highlight and groupby != 'languages' fields = OrderedDict() fields['groupby'] = groupby.title() fields['n_accounts'] = 'Num' fields['avg_score'] = 'Avg' medals = {m['name']: m for m in options.get('medals', [])} if 'medal' in contest_fields: for medal in settings.ORDERED_MEDALS_: fields[f'n_{medal}'] = medals.get(medal, {}).get( 'value', medal[0].upper()) if 'advanced' in contest_fields or advanced_by_participants_info: fields['n_advanced'] = 'Adv' orderby = [f for f in orderby if f.lstrip('-') in fields ] or ['-n_accounts', '-avg_score'] if groupby == 'languages': _, before_params = statistics.query.sql_with_params() querysets = [] for problem in problems: key = get_problem_short(problem) field = f'addition__problems__{key}__language' score = f'addition__problems__{key}__result' qs = statistics \ .filter(**{f'{field}__isnull': False, f'{score}__isnull': False}) \ .annotate(language=Cast(JSONF(field), models.TextField())) \ .annotate(score=Case( When(**{f'{score}__startswith': '+'}, then=1), When(**{f'{score}__startswith': '-'}, then=0), When(**{f'{score}__startswith': '?'}, then=0), default=Cast(JSONF(score), models.FloatField()), output_field=models.FloatField(), )) \ .annotate(sid=F('pk')) querysets.append(qs) merge_statistics = querysets[0].union(*querysets[1:], all=True) language_query, language_params = merge_statistics.query.sql_with_params( ) field = 'solving' statistics = statistics.annotate(groupby=F(field)) elif groupby == 'rating': statistics = statistics.annotate(groupby=Case( When(addition__rating_change__isnull=False, then=Value('Rated')), default=Value('Unrated'), output_field=models.TextField(), )) elif groupby == 'country': if '_countries' in contest_fields: statistics = statistics.annotate(country=RawSQL( '''json_array_elements((("addition" ->> '_countries'))::json)::jsonb''', [])) field = 'country' else: field = 'account__country' statistics = statistics.annotate(groupby=F(field)) else: field = f'addition__{groupby}' types = contest.info.get('fields_types', {}).get(groupby, []) if 'int' in types: field_type = models.IntegerField() elif 'float' in types: field_type = models.FloatField() else: field_type = models.TextField() statistics = statistics.annotate( groupby=Cast(JSONF(field), field_type)) statistics = statistics.order_by('groupby') statistics = statistics.values('groupby') statistics = statistics.annotate(n_accounts=Count('id')) statistics = statistics.annotate(avg_score=Avg('solving')) if 'medal' in contest_fields: for medal in settings.ORDERED_MEDALS_: n_medal = f'n_{medal}' statistics = statistics.annotate( **{ f'{n_medal}': Count(Case(When(addition__medal__iexact=medal, then=1))) }) if 'advanced' in contest_fields: statistics = statistics.annotate(n_advanced=Count( Case( When(addition__advanced=True, then=1), When(~Q(addition__advanced=False) & ~Q(addition__advanced=''), then=1), ))) elif advanced_by_participants_info: pks = list() for pk, info in participants_info.items(): if 'n' not in info or info['n'] > info.get( 'n_highlight', n_highlight): continue pks.append(pk) statistics = statistics.annotate( n_advanced=Count(Case(When(pk__in=set(pks), then=1)))) statistics = statistics.order_by(*orderby) if groupby == 'languages': query, sql_params = statistics.query.sql_with_params() query = query.replace( f'"ranking_statistics"."{field}" AS "groupby"', '"language" AS "groupby"') query = query.replace(f'GROUP BY "ranking_statistics"."{field}"', 'GROUP BY "language"') query = query.replace('"ranking_statistics".', '') query = query.replace('AVG("solving") AS "avg_score"', 'AVG("score") AS "avg_score"') query = query.replace('COUNT("id") AS "n_accounts"', 'COUNT("sid") AS "n_accounts"') query = re.sub('FROM "ranking_statistics".*GROUP BY', f'FROM ({language_query}) t1 GROUP BY', query) sql_params = sql_params[:-len(before_params)] + language_params with connection.cursor() as cursor: cursor.execute(query, sql_params) columns = [col[0] for col in cursor.description] statistics = [ dict(zip(columns, row)) for row in cursor.fetchall() ] statistics = ListAsQueryset(statistics) problems = [] labels_groupby = { 'n_accounts': 'Number of participants', 'avg_score': 'Average score', 'n_advanced': 'Number of advanced', } for medal in settings.ORDERED_MEDALS_: labels_groupby[f'n_{medal}'] = 'Number of ' + medals.get( medal, {}).get('value', medal) num_rows_groupby = statistics.count() map_colors_groupby = { s['groupby']: idx for idx, s in enumerate(statistics) } else: groupby = 'none' labels_groupby = None num_rows_groupby = None map_colors_groupby = None my_statistics = [] if groupby == 'none' and coder: statistics = statistics.annotate( my_stat=SubqueryExists('account__coders', filter=Q(coder=coder))) my_statistics = statistics.filter(account__coders=coder).extra( select={'floating': True}) context.update({ 'standings_options': options, 'mod_penalty': mod_penalty, 'colored_by_group_score': mod_penalty or options.get('colored_by_group_score'), 'contest': contest, 'statistics': statistics, 'my_statistics': my_statistics, 'problems': problems, 'params': params, 'fields': fields, 'fields_types': contest.info.get('fields_types', {}), 'divisions_order': divisions_order, 'has_country': has_country, 'per_page': per_page, 'with_row_num': with_row_num, 'merge_problems': merge_problems, 'fields_to_select': fields_to_select, 'truncatechars_name_problem': 10 * (2 if merge_problems else 1), 'with_detail': with_detail, 'groupby': groupby, 'pie_limit_rows_groupby': 50, 'labels_groupby': labels_groupby, 'num_rows_groupby': num_rows_groupby, 'map_colors_groupby': map_colors_groupby, 'advance': contest.info.get('advance'), 'timezone': get_timezone(request), 'timeformat': get_timeformat(request), 'with_neighbors': request.GET.get('neighbors') == 'on', 'with_table_inner_scroll': not request.user_agent.is_mobile, }) context.update(n_highlight_context) if extra_context is not None: context.update(extra_context) return render(request, template, context)
def versus(request, query): if request.GET.get('coder'): coder = get_object_or_404(Coder, pk=request.GET.get('coder')) return redirect(f'{request.path}vs/{coder.username}') if request.GET.get('remove'): idx = int(request.GET.get('remove')) parts = query.split('/vs/') if 0 <= idx < len(parts): parts = parts[:idx] + parts[idx + 1:] query = '/vs/'.join(parts) return redirect(reverse('ranking:versus', args=[query])) # filtration data params = {} fields_to_select = {} for data in [ { 'field': 'rating', 'options': ['rated', 'unrated'] }, { 'field': 'score_in_row', 'options': ['show', 'hide'], 'title': 'score' }, { 'field': 'medal', 'options': ['yes', 'no'] }, ]: field = data.pop('field') fields_to_select[field] = { 'noajax': True, 'nomultiply': True, 'nourl': True, 'nogroupby': True, 'values': [v for v in request.GET.getlist(field) if v], } fields_to_select[field].update(data) versus_data = get_versus_data(request, query, fields_to_select) # filter contests contests = Contest.visible.filter( pk__in=versus_data['contests_ids']).order_by('-end_time') contests = contests.select_related('resource') search = request.GET.get('search') if search is not None: with_medal = False def set_medal(v): nonlocal with_medal with_medal = True return False contests_filter = get_iregex_filter( search, 'title', 'host', 'resource__host', mapping={ 'contest': { 'fields': ['title__iregex'] }, 'resource': { 'fields': ['host__iregex'] }, 'slug': { 'fields': ['slug'] }, 'writer': { 'fields': ['info__writers__contains'] }, 'medal': { 'fields': ['info__standings__medals'], 'suff': '__isnull', 'func': set_medal }, }, logger=request.logger) if with_medal: contests_filter |= Q(pk__in=versus_data['medal_contests_ids']) contests = contests.filter(contests_filter) medal = request.GET.get('medal') if medal: contests_filter = Q(info__standings__medals__isnull=False) contests_filter |= Q(pk__in=versus_data['medal_contests_ids']) if medal == 'no': contests_filter = ~contests_filter contests = contests.filter(contests_filter) daterange = request.GET.get('daterange') if daterange: date_from, date_to = [ arrow.get(x).datetime for x in daterange.split(' - ') ] contests = contests.filter(start_time__gte=date_from, end_time__lte=date_to) resources = [r for r in request.GET.getlist('resource') if r] if resources: resources = list(Resource.objects.filter(pk__in=resources)) params['resources'] = resources rids = set([r.pk for r in resources]) contests = contests.filter(resource_id__in=rids) # scoring by contests scores = versus_data.setdefault('scores', {}) for contest in reversed(contests): best = None indices = [] for idx, info in enumerate(versus_data['infos']): stat = info['contests'][contest.pk] score = (stat.place_as_int, -stat.solving) if best is None or score < best: best = score indices = [] if score == best: indices.append(idx) for idx in indices: info = versus_data['infos'][idx] info['score'] += 1 setattr(info['contests'][contest.pk], 'scored_', True) scores[contest.pk] = { 'score': [info['score'] for info in versus_data['infos']], 'indices': indices, } ratings_resources = None for idx, info in enumerate(versus_data['infos']): rdata = info['ratings']['data'] rdata_resources = { k: sum([len(d) for d in v['data']]) for k, v in rdata['resources'].items() } if ratings_resources is None: ratings_resources = rdata_resources else: ratings_resources = { k: v + ratings_resources[k] for k, v in rdata_resources.items() if k in ratings_resources } ratings_resources = sorted([(v, k) for k, v in ratings_resources.items()], reverse=True) ratings_data = {'resources': {}} ratings_dates = [] ignore_colors = {} rdata = versus_data['infos'][0]['ratings']['data'] for _, resource in ratings_resources: rinfo = rdata['resources'][resource] for color in rinfo['colors']: H, S, L = color['hsl'] rgb = colorsys.hls_to_rgb(H, L, S) ignore_colors[color['hex_rgb']] = rgb ignore_colors = list(ignore_colors.values()) datasets_colors = get_n_colors(n=len(versus_data['infos']), ignore_colors=ignore_colors) for idx, info in enumerate(versus_data['infos']): rdata = info['ratings']['data'] for _, resource in ratings_resources: rinfo = rdata['resources'][resource] resource_info = ratings_data['resources'].setdefault( resource, { 'data': [], 'colors': rinfo['colors'], 'min': rinfo['min'], 'max': rinfo['max'], 'point_radius': 0, 'point_hit_radius': 5, 'border_width': 1, 'outline': True, 'datasets': { 'colors': datasets_colors, 'labels': versus_data['opponents'], }, 'x_axes_unit': rinfo.get('x_axes_unit'), }) resource_info['data'].extend(rinfo['data']) resource_info['min'] = min(resource_info['min'], rinfo['min']) resource_info['max'] = max(resource_info['max'], rinfo['max']) for data in rinfo['data']: for stat in data: stat['date'] = str(stat['date']) ratings_dates.append(stat['date']) ratings_data['dates'] = list(sorted(set(ratings_dates))) versus_data['ratings'] = ratings_data context = { 'contests': contests, 'versus_data': versus_data, 'params': params, 'fields_to_select': fields_to_select, 'rated': 'rated' in fields_to_select['rating']['values'], 'scored': 'show' in fields_to_select['score_in_row']['values'], } return render(request, 'versus.html', context)
def event(request, slug, tab=None, template='event.html', extra_context=None): event = get_object_or_404(Event, slug=slug) if tab is not None and tab not in [ 'information', 'registration', 'teams', 'participants', 'admin' ]: return HttpResponseNotFound() user = request.user coder = None if user.is_anonymous else user.coder participant = event.participant_set.filter(coder=coder, coder__isnull=False).first() if participant: join_requests = participant.joinrequest_set.all() team = event.team_set \ .filter(participants__pk=participant.pk) \ .prefetch_related('joinrequest_set', 'participants') \ .first() else: join_requests = None team = None has_join_requests = join_requests is not None and join_requests.exists() end_registration = event.registration_deadline < now() registration_timeleft = event.registration_deadline - now() if coder and coder.settings.get('unlimited_deadline'): registration_timeleft = timedelta(minutes=42) end_registration = False query = request.POST.get('query') or request.GET.get('query') if query is not None and not end_registration and coder: if not request.META.get('HTTP_REFERER'): return redirect( resolve_url('events:event-tab', slug=event.slug, tab='registration')) if query == 'skip-coach': if not team or team.author != participant: messages.error(request, 'First you need to create a team') elif team.status != TeamStatus.ADD_COACH: messages.error(request, 'Not necessary skip coach') else: team.status = TeamStatus.PENDING team.save() elif query in ['join', 'add-coach']: # 'join-as-coach' is_coach = query == 'add-coach' ok = True if not is_coach and participant: messages.info(request, 'You have already joined the event') ok = False if is_coach and (not team or team.status != TeamStatus.ADD_COACH): messages.error(request, 'First you need to create a team') ok = False else: active_fields = [ 'first-name', 'last-name', 'email', 'first-name-native', 'last-name-native', 'phone-number', 'tshirt-size', ] if not is_coach: active_fields.append('date-of-birth') active_fields.append('organization') active_fields.append('country') for field in event.fields_info.get('addition_fields', []): active_fields.append(field['name']) active_fields = [ f for f in active_fields if f not in event.fields_info.get('disabled_fields', []) ] for field in active_fields: if not request.POST.get(field, ''): messages.error(request, 'You must specify all the information') ok = False break else: if not is_coach and not coder.token_set.filter( email=request.POST['email']).exists(): messages.error( request, 'Invalid email. Check that the account with this email is connected' ) ok = False active_fields.append('middle-name-native') if 'phone-number' in active_fields: try: phone_number = PhoneNumber.from_string( phone_number=request.POST.get('phone-number')) assert phone_number.is_valid() except Exception: messages.error(request, 'Invalid phone number') ok = False handle = request.POST.get('codeforces-handle') if handle and not is_coach: error = None resource = Resource.objects.get(host='codeforces.com') account = Account.objects.filter( key=handle, resource=resource).first() if not account: error = f'Codeforces handle {handle} not found' elif coder.account_set.filter(resource=resource).exists(): error = f'Codeforces handle {handle} is already connect' else: module = Module.objects.filter( resource=resource).first() if not module or not module.multi_account_allowed: if coder.account_set.filter( resource=resource).exists(): error = 'Allow only one account for this resource' elif account.coders.count(): error = 'Account is already connect' if error: messages.error(request, error) ok = False else: account.coders.add(coder) account.save() if is_coach: participant = Participant.objects.create(event=event, is_coach=True) else: participant, _ = Participant.objects.get_or_create(coder=coder, event=event) org_created = False try: data = dict(list(request.POST.items())) for field in active_fields: if data.get(field): data[field] = data[field].strip() if 'phone-number' in active_fields: data['phone-number'] = phone_number.as_e164 if 'tshirt-size' in active_fields: data['tshirt-size'] = int(data['tshirt-size']) if not is_coach and 'organization' in data: organization_name = data['organization'] organization, org_created = Organization.objects.get_or_create( name=organization_name) if org_created: organization.name_ru = organization_name organization.author = coder organization.save() data['organization'] = organization for object_, attr in ( (user, 'first_name'), (user, 'last_name'), (user, 'email'), (coder, 'first_name_native'), (coder, 'last_name_native'), (coder, 'middle_name_native'), (coder, 'phone_number'), (coder, 'country'), (coder, 'date_of_birth'), (coder, 'organization'), (coder, 'tshirt_size'), ): field = attr.replace('_', '-') if field not in active_fields: continue value = data[field] setattr(participant, attr, value) if not is_coach and object_: if attr == 'tshirt_size': value = participant.tshirt_size_value setattr(object_, attr, value or getattr(object_, attr)) for field in event.fields_info.get('addition_fields', []): field = field['name'] if field not in active_fields: continue value = data[field] coder.addition_fields[field] = value participant.addition_fields[field] = value participant.save() user.save() coder.save() if is_coach: team.coach = participant team.status = TeamStatus.PENDING team.save() except Exception as e: messages.error(request, str(e)) ok = False if not ok: participant.delete() if org_created: organization.delete() elif query == 'create-team': team_name = request.POST.get('team') team_name_limit = event.limits.get('team_name_length') if not team_name: messages.error(request, 'You must specify team name') elif team_name_limit and len(team_name) > team_name_limit: messages.error( request, f'The team name is too long (limit is {team_name_limit})') elif participant and participant.is_coach: team = Team.objects.create(event=event, name=team_name, author=participant) team.coach = participant team.save() elif team or has_join_requests: messages.error(request, 'You have already committed an action') else: team = Team.objects.create(event=event, name=team_name, author=participant) team.participants.add(participant) team.save() elif query == 'join-team': is_coach = participant and participant.is_coach if not is_coach and (team or has_join_requests): messages.error(request, 'You have already committed an action') else: team_id = int(request.POST.get('team')) team = Team.objects.get(pk=team_id, event=event, status=TeamStatus.NEW) if not JoinRequest.objects.filter( team=team, participant=participant).exists(): JoinRequest.objects.create(team=team, participant=participant) elif query == 'cancel-request': if not has_join_requests: messages.error(request, 'Join request not found') else: join_request_id = int(request.GET.get('request_id')) JoinRequest.objects.filter(pk=join_request_id, participant=participant).delete() elif query in ['accept-team', 'reject-team']: request_id = int(request.POST.get('request_id')) join_request = JoinRequest.objects \ .filter(pk=request_id) \ .filter(Q(team__author=participant) | Q(team__coach=participant)) \ .first() if not join_request: messages.error(request, 'First you need to create a join request') else: participant = join_request.participant team = join_request.team if query == 'accept-team': if participant.is_coach: if team.coach: messages.error(request, 'Team already has coach') else: team.coach = participant team.save() join_request.delete() else: if team.participants.count() >= event.team_size: messages.error(request, 'Too many team participants') else: team.participants.add(participant) join_request.delete() elif query in ['register', 'delete-team']: team_id = int(request.POST.get('team_id')) team = Team.objects \ .filter(pk=team_id) \ .filter(Q(author=participant) | Q(coach=participant)) \ .first() if not team: messages.error(request, 'First you need to create a team') elif team.status != TeamStatus.NEW: messages.error(request, 'Team already registered') elif query == 'delete-team': team.delete() elif not 0 < team.participants.count() <= event.team_size: messages.error( request, 'Team should be consists of one to three participants') else: if team.coach: team.status = TeamStatus.PENDING else: team.status = TeamStatus.ADD_COACH team.save() elif query == 'cancel-registration': if has_join_requests: request.logger.error( 'Cancel join requests before cancel registration') elif team: request.logger.error('Remove team before cancel registration') elif not participant: request.logger.error('Register before cancel registration') else: participant.delete() elif query == 'looking-for': if has_join_requests: request.logger.error('Cancel join requests') elif team: request.logger.error('Remove team before') elif not participant: request.logger.error('Register before') else: participant.looking_for = not participant.looking_for participant.save() else: request.logger.error(f'Unknown query "{query}"') return redirect( resolve_url('events:event-tab', slug=event.slug, tab='registration')) teams = Team.objects.filter(event=event).order_by('-modified') teams = teams.prefetch_related( 'participants__coder__user', 'participants__organization', ) teams = teams.select_related( 'author__coder__user', 'author__organization', 'coach__coder__user', 'coach__organization', ) codeforces_resource = Resource.objects.get(host='codeforces.com') teams = teams.prefetch_related( Prefetch( 'participants__coder__account_set', queryset=Account.objects.filter(resource=codeforces_resource), ), 'participants__coder__account_set__resource', ) approved_statuses = { k for k, v in TeamStatus.descriptions.items() if v in ['approved', 'disqualified'] } team_search = request.GET.get('team_search') if team_search: team_search_filter = get_iregex_filter( team_search, 'name', 'participants__first_name', 'participants__last_name', 'participants__organization__name', 'participants__organization__abbreviation', 'coach__first_name', 'coach__last_name', 'coach__organization__name', 'coach__organization__abbreviation', ) teams = teams.filter(team_search_filter) team_participants = teams.filter(status__in=approved_statuses) participants = Participant.objects.filter( event=event, is_coach=False, ).filter(Q(team=None) | Q(team__status=TeamStatus.NEW), ) participant_search = request.GET.get('participant_search') if participant_search: participant_search_filter = get_iregex_filter( participant_search, 'first_name', 'last_name', 'organization__name', 'organization__abbreviation', 'team__name', ) participants = participants.filter(participant_search_filter) qs = Participant.objects.filter(team__isnull=False).order_by('-created') qs = qs.prefetch_related('team__participants').select_related( 'team__author') participants = participants.prefetch_related( Prefetch('coder__participant_set', queryset=qs)).order_by('-modified') status = request.GET.get('status') if status is not None: teams = teams.filter(status=status) context = { 'slug': slug, 'event': event, 'tab': tab, 'svg_r': 5, 'coder': coder, 'participant': participant, 'team_participants': team_participants, 'participants': participants, 'team': team, 'join_requests': join_requests, 'team_status': TeamStatus, 'tshirt_size': TshirtSize, 'teams': teams, 'timezone': get_timezone(request), 'timeformat': get_timeformat(request), 'defaults': { 'country': { 'code': 'BY', 'name': dict(countries)['BY'] }, }, 'registration': { 'over': end_registration, 'timeleft': humanfriendly.format_timespan(registration_timeleft), }, 'codeforces_resource': codeforces_resource, } if extra_context is not None: context.update(extra_context) return render(request, template, context)
def search(request, **kwargs): query = request.GET.get('query', None) if not query or not isinstance(query, str): return HttpResponseBadRequest('invalid query') count = int(request.GET.get('count', django_settings.DEFAULT_COUNT_QUERY_)) count = min(count, django_settings.DEFAULT_COUNT_LIMIT_) page = int(request.GET.get('page', 1)) if query == 'themes': ret = {} for t in django_settings.THEMES_: ret[t] = t.title() return JsonResponse(ret) elif query == 'timezones': ret = {} for tz in get_timezones(): ret[tz["name"]] = f'{tz["name"]} {tz["repr"]}' return JsonResponse(ret) elif query == 'resources': qs = Resource.objects.all() if 'regex' in request.GET: qs = qs.filter(get_iregex_filter(request.GET['regex'], 'host')) qs = qs.order_by('-n_accounts', 'pk') qs = qs[(page - 1) * count:page * count] ret = [{'id': r.id, 'text': r.host, 'icon': r.icon} for r in qs] elif query == 'resources-for-add-account' and request.user.is_authenticated: coder = request.user.coder coder_accounts = coder.account_set.filter(resource=OuterRef('pk')) qs = Resource.objects \ .annotate(has_coder_account=Exists(coder_accounts)) \ .annotate(has_multi=F('module__multi_account_allowed')) \ .annotate(disabled=Case( When(module__isnull=True, then=Value(True)), When(has_coder_account=True, has_multi=False, then=Value(True)), default=Value(False), output_field=BooleanField(), )) if 'regex' in request.GET: qs = qs.filter(get_iregex_filter(request.GET['regex'], 'host')) qs = qs.order_by('disabled', 'pk') qs = qs[(page - 1) * count:page * count] ret = [{ 'id': r.id, 'text': r.host, 'disabled': r.disabled, } for r in qs] elif query == 'accounts-for-add-account' and request.user.is_authenticated: coder = request.user.coder qs = Account.objects.all() resource = request.GET.get('resource') if resource: qs = qs.filter(resource__id=int(resource)) else: qs = qs.select_related('resource') order = ['disabled'] if 'user' in request.GET: re_search = request.GET.get('user') exact_qs = qs.filter(key__iexact=re_search) if exact_qs.exists(): qs = exact_qs else: qs = qs.filter(get_iregex_filter(re_search, 'key', 'name')) search_striped = re_search.rstrip('$').lstrip('^') qs = qs.annotate(match=Case( When(Q(key__iexact=search_striped) | Q(name__iexact=search_striped), then=Value(True)), default=Value(False), output_field=BooleanField(), )) order.append('-match') qs = qs.annotate( has_multi=F('resource__module__multi_account_allowed')) qs = qs.annotate(disabled=Case( When(coders=coder, then=Value(True)), When(coders__isnull=False, has_multi=False, then=Value(True)), default=Value(False), output_field=BooleanField(), )) qs = qs.order_by(*order, 'pk') qs = qs[(page - 1) * count:page * count] ret = [] for r in qs: fields = { 'id': r.key, 'text': f'{r.key} - {r.name}' if r.name and r.key.find(r.name) == -1 else r.key, 'disabled': r.disabled, } if not resource: fields['text'] += f', {r.resource.host}' fields['resource'] = { 'id': r.resource.pk, 'text': r.resource.host } ret.append(fields) elif query == 'organization': qs = Organization.objects.all() name = request.GET.get('name') if name: qs = qs.filter( Q(name__icontains=name) | Q(name_ru__icontains=name) | Q(abbreviation__icontains=name)) qs = qs[(page - 1) * count:page * count] ret = [{'id': o.name, 'text': o.name} for o in qs] elif query == 'team': qs = Team.objects.all() name = request.GET.get('name') if name: qs = qs.filter(name__icontains=name) event = kwargs.get('event') if event: qs = qs.filter(event=event) qs = qs.annotate( disabled=Case(When(status=TeamStatus.NEW, then=Value(False)), default=Value(True), output_field=BooleanField())).order_by( 'disabled', '-modified', 'pk') qs = qs[(page - 1) * count:page * count] ret = [{ 'id': r.id, 'text': r.name, 'disabled': r.disabled } for r in qs] elif query == 'country': qs = list(countries) name = request.GET.get('name') if name: name = name.lower() qs = [(c, n) for c, n in countries if name in n.lower()] qs = qs[(page - 1) * count:page * count] ret = [{'id': c, 'text': n} for c, n in qs] elif query == 'notpast': title = request.GET.get('title') qs = Contest.objects.filter(title__iregex=verify_regex(title), end_time__gte=timezone.now()) qs = qs[(page - 1) * count:page * count] ret = [{'id': c.id, 'text': c.title} for c in qs] elif query == 'field-to-select': contest = get_object_or_404(Contest, pk=request.GET.get('cid')) text = request.GET.get('text') field = request.GET.get('field') assert '__' not in field if field == 'languages': qs = contest.info.get('languages', []) qs = ['any' ] + [q for q in qs if not text or text.lower() in q.lower()] elif field == 'rating': qs = ['rated', 'unrated'] else: field = f'addition__{field}' qs = contest.statistics_set if text: qs = qs.filter(**{f'{field}__icontains': text}) qs = qs.distinct(field).values_list(field, flat=True) qs = qs[(page - 1) * count:page * count] ret = [{'id': f, 'text': f} for f in qs] elif query == 'coders': qs = Coder.objects.all() if 'regex' in request.GET: qs = qs.filter(get_iregex_filter(request.GET['regex'], 'username')) order = ['-n_accounts', 'pk'] if request.user.is_authenticated: qs = qs.annotate( iam=Case(When(pk=request.user.coder.pk, then=Value(0)), default=Value(1), output_field=IntegerField())) order.insert(0, 'iam') qs = qs.order_by(*order, 'pk') qs = qs[(page - 1) * count:page * count] ret = [{'id': r.id, 'text': r.username} for r in qs] elif query == 'accounts': qs = Account.objects.all() if request.GET.get('resource'): qs = qs.filter(resource_id=int(request.GET.get('resource'))) order = ['-n_contests', 'pk'] if 'regex' in request.GET: re_search = request.GET['regex'] exact_qs = qs.filter(key__iexact=re_search) if exact_qs.exists(): qs = exact_qs else: qs = qs.filter(get_iregex_filter(re_search, 'key', 'name')) search_striped = re_search.rstrip('$').lstrip('^') qs = qs.annotate(match=Case( When(Q(key__iexact=search_striped) | Q(name__iexact=search_striped), then=Value(True)), default=Value(False), output_field=BooleanField(), )) order.insert(0, '-match') qs = qs.select_related('resource') qs = qs.order_by(*order, 'pk') qs = qs[(page - 1) * count:page * count] ret = [{ 'id': r.id, 'text': f'{r.key}, {r.name}, {r.resource.host}' if r.name else f'{r.key}, {r.resource.host}' } for r in qs] else: return HttpResponseBadRequest('invalid query') result = { 'items': ret, 'more': len(ret) and len(ret) == count, } return HttpResponse(json.dumps(result, ensure_ascii=False), content_type="application/json")
def get_profile_context(request, statistics, writers): history_resources = statistics \ .filter(contest__resource__has_rating_history=True) \ .filter(contest__stage__isnull=True) \ .annotate(new_rating=Cast(KeyTextTransform('new_rating', 'addition'), IntegerField())) \ .filter(new_rating__isnull=False) \ .annotate(host=F('contest__resource__host')) \ .values('host') \ .annotate(num_contests=Count('contest')) \ .order_by('-num_contests') stats = statistics \ .select_related('contest', 'account') \ .filter(addition__medal__isnull=False) \ .order_by('-contest__end_time') resource_medals = {} account_medals = {} for stat in stats: resource_medals.setdefault(stat.contest.resource_id, []).append(stat) account_medals.setdefault(stat.account.id, []).append(stat) statistics = statistics \ .select_related('contest', 'contest__resource', 'account') \ .order_by('-contest__end_time') search = request.GET.get('search') filters = {} if search: filt = get_iregex_filter( search, 'contest__resource__host', 'contest__title', mapping={ 'writer': { 'fields': ['contest__info__writers__contains'] }, 'contest': { 'fields': ['contest__title__iregex'] }, 'resource': { 'fields': ['contest__resource__host'] }, 'account': { 'fields': ['account__key'] }, 'medal': { 'fields': ['addition__medal'], 'func': lambda v: False if not v or v == 'any' else v, 'suff': lambda v: '__isnull' if v is False else '', }, 'cid': { 'fields': ['contest_id'], 'func': lambda v: int(v) }, 'rid': { 'fields': ['contest__resource_id'], 'func': lambda v: int(v) }, }, values=filters, logger=request.logger, ) statistics = statistics.filter(filt) filter_resources = filters.pop('resource', []) for val in filter_resources: history_resources = history_resources.filter( contest__resource__host=val) search_resource = filter_resources[0] if len( filter_resources) == 1 else None if search_resource: writers = writers.filter(resource__host=search_resource) writers = writers.order_by('-end_time') writers = writers.annotate(has_statistics=Exists('statistics')) context = { 'statistics': statistics, 'writers': writers, 'history_resources': history_resources, 'show_history_ratings': not filters, 'resource_medals': resource_medals, 'account_medals': account_medals, 'search_resource': search_resource, 'timezone': get_timezone(request), 'timeformat': get_timeformat(request), } return context
def search(request, **kwargs): query = request.GET.get('query', None) if not query or not isinstance(query, str): return HttpResponseBadRequest('invalid query') count = int(request.GET.get('count', 10)) page = int(request.GET.get('page', 1)) if query == 'timezones': ret = {} for tz in get_timezones(): ret[tz["name"]] = f'{tz["name"]} {tz["repr"]}' return JsonResponse(ret) elif query == 'resources-for-add-account': coder = request.user.coder coder_accounts = coder.account_set.filter(resource=OuterRef('pk')) qs = Resource.objects \ .annotate(has_coder_account=Exists(coder_accounts)) \ .annotate(has_multi=F('module__multi_account_allowed')) \ .annotate(disabled=Case( When(module__isnull=True, then=Value(True)), When(has_coder_account=True, has_multi=False, then=Value(True)), default=Value(False), output_field=BooleanField(), )) if 'regex' in request.GET: qs = qs.filter(get_iregex_filter(request.GET['regex'], 'host')) qs = qs.order_by('disabled', 'pk') total = qs.count() qs = qs[(page - 1) * count:page * count] ret = [{ 'id': r.id, 'text': r.host, 'disabled': r.disabled, } for r in qs] elif query == 'accounts-for-add-account': coder = request.user.coder qs = Account.objects.all() resource = request.GET.get('resource') if resource: qs = qs.filter(resource__id=int(resource)) else: qs = qs.select_related('resource') if 'user' in request.GET: qs = qs.filter( get_iregex_filter(request.GET.get('user'), 'key', 'name')) qs = qs.annotate(has_multi=F('resource__module__multi_account_allowed')) \ qs = qs.annotate(disabled=Case( When(coders=coder, then=Value(True)), When(coders__isnull=False, has_multi=False, then=Value(True)), default=Value(False), output_field=BooleanField(), )) qs = qs.order_by('disabled') total = qs.count() qs = qs[(page - 1) * count:page * count] ret = [] for r in qs: fields = { 'id': r.key, 'text': f'{r.key} - {r.name}' if r.name and r.key.find(r.name) == -1 else r.key, 'disabled': r.disabled, } if not resource: fields['text'] += f', {r.resource.host}' fields['resource'] = { 'id': r.resource.pk, 'text': r.resource.host } ret.append(fields) elif query == 'organization': qs = Organization.objects.all() name = request.GET.get('name') if name: qs = qs.filter( Q(name__icontains=name) | Q(name_ru__icontains=name) | Q(abbreviation__icontains=name)) total = qs.count() qs = qs[(page - 1) * count:page * count] ret = [{'id': o.name, 'text': o.name} for o in qs] elif query == 'team': qs = Team.objects.all() name = request.GET.get('name') if name: qs = qs.filter(name__icontains=name) event = kwargs.get('event') if event: qs = qs.filter(event=event) qs = qs.annotate( disabled=Case(When(status=TeamStatus.NEW, then=Value(False)), default=Value(True), output_field=BooleanField())).order_by( 'disabled', '-modified') total = qs.count() qs = qs[(page - 1) * count:page * count] ret = [{ 'id': r.id, 'text': r.name, 'disabled': r.disabled } for r in qs] elif query == 'country': qs = list(countries) name = request.GET.get('name') if name: name = name.lower() qs = [(c, n) for c, n in countries if name in n.lower()] total = len(qs) qs = qs[(page - 1) * count:page * count] ret = [{'id': c, 'text': n} for c, n in qs] elif query == 'notpast': title = request.GET.get('title') qs = Contest.objects.filter(title__iregex=verify_regex(title), end_time__gte=timezone.now()) total = qs.count() qs = qs[(page - 1) * count:page * count] ret = [{'id': c.id, 'text': c.title} for c in qs] elif query == 'field-to-select': contest = get_object_or_404(Contest, pk=request.GET.get('cid')) text = request.GET.get('text') field = request.GET.get('field') assert '__' not in field if field == 'languages': qs = contest.info.get('languages', []) qs = [[q] for q in qs if not text or text.lower() in q.lower()] total = len(qs) else: field = f'addition__{field}' qs = contest.statistics_set if text: qs = qs.filter(**{f'{field}__icontains': text}) qs = qs.distinct(field).values_list(field) total = qs.count() qs = qs[(page - 1) * count:page * count] ret = [{'id': f[0], 'text': f[0]} for f in qs] else: return HttpResponseBadRequest('invalid query') result = { 'items': ret, 'more': page * count <= total, } return HttpResponse(json.dumps(result, ensure_ascii=False), content_type="application/json")
def versus(request, query): # filtration data params = {} fields_to_select = {} for data in [ {'field': 'rating', 'options': ['rated', 'unrated']}, {'field': 'score_in_row', 'options': ['show', 'hide'], 'title': 'score'}, {'field': 'medal', 'options': ['yes', 'no']}, ]: field = data.pop('field') fields_to_select[field] = { 'noajax': True, 'nomultiply': True, 'nourl': True, 'nogroupby': True, 'values': [v for v in request.GET.getlist(field) if v], } fields_to_select[field].update(data) versus_data = get_versus_data(request, query, fields_to_select) # filter contests contests = Contest.visible.filter(pk__in=versus_data['contest_ids']).order_by('-end_time') contests = contests.select_related('resource') search = request.GET.get('search') if search is not None: with_medal = False def set_medal(v): nonlocal with_medal with_medal = True return False contests_filter = get_iregex_filter(search, 'title', 'host', 'resource__host', mapping={ 'contest': {'fields': ['title__iregex']}, 'resource': {'fields': ['host__iregex']}, 'slug': {'fields': ['slug']}, 'writer': {'fields': ['info__writers__contains']}, 'medal': {'fields': ['info__standings__medals'], 'suff': '__isnull', 'func': set_medal}, }, logger=request.logger) if with_medal: contests_filter |= Q(pk__in=versus_data['medal_contest_ids']) contests = contests.filter(contests_filter) medal = request.GET.get('medal') if medal: contests_filter = Q(info__standings__medals__isnull=False) contests_filter |= Q(pk__in=versus_data['medal_contest_ids']) if medal == 'no': contests_filter = ~contests_filter contests = contests.filter(contests_filter) resources = [r for r in request.GET.getlist('resource') if r] if resources: resources = list(Resource.objects.filter(pk__in=resources)) params['resources'] = resources rids = set([r.pk for r in resources]) contests = contests.filter(resource_id__in=rids) # scoring by contests scores = versus_data.setdefault('scores', {}) for contest in reversed(contests): best = None indices = [] for idx, info in enumerate(versus_data['infos']): stat = info['contests'][contest.pk] score = (-stat.place_as_int, stat.solving) if best is None or score > best: best = score indices = [] if score == best: indices.append(idx) for idx in indices: info = versus_data['infos'][idx] info['score'] += 1 setattr(info['contests'][contest.pk], 'scored_', True) scores[contest.pk] = { 'score': [info['score'] for info in versus_data['infos']], 'indices': indices, } context = { 'contests': contests, 'versus_data': versus_data, 'params': params, 'fields_to_select': fields_to_select, 'rated': 'rated' in fields_to_select['rating']['values'], 'scored': 'show' in fields_to_select['score_in_row']['values'], } return render(request, 'versus.html', context)
def problems(request, template='problems.html'): problems = Problem.objects.all() problems = problems.select_related('contest', 'resource') problems = problems.prefetch_related('tags') problems = problems.order_by('-time', 'contest_id', 'index') problems = problems.filter(contest__end_time__lt=timezone.now(), visible=True) search = request.GET.get('search') if search: cond, problems = get_iregex_filter( search, 'name', 'contest__title', 'contest__host', 'contest__resource__host', logger=request.logger, mapping={ 'name': { 'fields': ['name__iregex'] }, 'contest': { 'fields': ['contest__title__iregex'] }, 'resource': { 'fields': ['resource__host__iregex'] }, 'tag': { 'fields': ['problemtag__name__iregex'], 'exists': 'tags' }, 'cid': { 'fields': ['contest_id'], 'func': lambda v: int(v) }, 'rid': { 'fields': ['resource_id'], 'func': lambda v: int(v) }, 'pid': { 'fields': ['id'], 'func': lambda v: int(v) }, }, queryset=problems, ) problems = problems.filter(cond) resources = [r for r in request.GET.getlist('resource') if r] if resources: problems = problems.filter(contest__resource_id__in=resources) resources = list(Resource.objects.filter(pk__in=resources)) tags = [r for r in request.GET.getlist('tag') if r] if tags: problems = problems.annotate( has_tag=Exists('tags', filter=Q(problemtag__pk__in=tags))) problems = problems.filter(has_tag=True) tags = list(ProblemTag.objects.filter(pk__in=tags)) context = { 'problems': problems, 'params': { 'resources': resources, 'tags': tags, }, } return template, context