コード例 #1
0
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)
コード例 #2
0
ファイル: views.py プロジェクト: guptaarth87/clist
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
コード例 #3
0
ファイル: views.py プロジェクト: guptaarth87/clist
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)
コード例 #4
0
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)
コード例 #5
0
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)
コード例 #6
0
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)
コード例 #7
0
ファイル: views.py プロジェクト: aropan/clist
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)
コード例 #8
0
ファイル: views.py プロジェクト: VadVergasov/clist
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")
コード例 #9
0
ファイル: views.py プロジェクト: VadVergasov/clist
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
コード例 #10
0
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")
コード例 #11
0
ファイル: views.py プロジェクト: guptaarth87/clist
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)
コード例 #12
0
ファイル: views.py プロジェクト: aropan/clist
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