コード例 #1
0
ファイル: views.py プロジェクト: BenMusch/tabbycat
def update_all_breaking_teams(request, t, category):
    """Generates for all break categories; 'category' is used only for the redirect"""
    breaking.update_all_breaking_teams(t)
    ActionLogEntry.objects.log(type=ActionLogEntry.ACTION_TYPE_BREAK_UPDATE_ALL,
            user=request.user, tournament=t, ip_address=get_ip_address(request))
    messages.success(request, "Teams break updated for all break categories.")
    return redirect_tournament('breaking_teams', t, category=category)
コード例 #2
0
ファイル: views.py プロジェクト: czlee/tabbycat
    def populate_objects(self):
        self.object = self.get_object() # must be populated before self.error_page() called

        round = self.tournament.current_round
        if round.draw_status != Round.STATUS_RELEASED:
            return self.error_page(_("The draw for this round hasn't been released yet."))

        if (self.tournament.pref('enable_motions') or self.tournament.pref('motion_vetoes_enabled')) \
                and not round.motions_released:
            return self.error_page(_("The motions for this round haven't been released yet."))

        try:
            self.debateadj = DebateAdjudicator.objects.get(adjudicator=self.object, debate__round=round)
        except DebateAdjudicator.DoesNotExist:
            return self.error_page(_("It looks like you don't have a debate this round."))
        except DebateAdjudicator.MultipleObjectsReturned:
            return self.error_page(_("It looks like you're assigned to two or more debates this round. "
                    "Please contact a tab room official."))

        self.debate = self.debateadj.debate
        self.ballotsub = BallotSubmission(debate=self.debate, ip_address=get_ip_address(self.request),
            submitter_type=BallotSubmission.SUBMITTER_PUBLIC)

        if not self.debate.adjudicators.has_chair:
            return self.error_page(_("Your debate doesn't have a chair, so you can't enter results for it. "
                    "Please contact a tab room official."))

        if not (self.tournament.pref('draw_side_allocations') == 'manual-ballot' and
                self.tournament.pref('teams_in_debate') == 'two') and not self.debate.sides_confirmed:
            return self.error_page(_("It looks like the sides for this debate haven't yet been confirmed, "
                    "so you can't enter results for it. Please contact a tab room official."))
コード例 #3
0
    def populate_objects(self):
        self.debate = self.object = self.get_object()
        self.ballotsub = BallotSubmission(
            debate=self.debate,
            submitter=self.request.user,
            submitter_type=BallotSubmission.SUBMITTER_TABROOM,
            ip_address=get_ip_address(self.request))

        t = self.get_tournament()

        if t.pref('ballots_per_debate') == 'per-adj' and \
                not self.debate.adjudicators.has_chair:
            messages.error(
                self.request,
                _("Whoops! The debate %(debate)s doesn't have a chair, "
                  "so you can't enter results for it.") %
                {'debate': self.debate.matchup})
            return redirect_round('results-round-list',
                                  self.ballotsub.debate.round)

        if not (t.pref('draw_side_allocations') == 'manual-ballot'
                and t.pref('teams_in_debate')
                == 'two') and not self.debate.sides_confirmed:
            messages.error(
                self.request,
                _("Whoops! The debate %(debate)s doesn't have its "
                  "sides confirmed, so you can't enter results for it.") %
                {'debate': self.debate.matchup})
            return redirect_round('results-round-list',
                                  self.ballotsub.debate.round)
コード例 #4
0
    def populate_objects(self):
        self.object = self.get_object() # must be populated before self.error_page() called

        round = self.tournament.current_round
        if round.draw_status != Round.STATUS_RELEASED:
            return self.error_page(_("The draw for this round hasn't been released yet."))

        if (self.tournament.pref('enable_motions') or self.tournament.pref('motion_vetoes_enabled')) \
                and not round.motions_released:
            return self.error_page(_("The motions for this round haven't been released yet."))

        try:
            self.debateadj = DebateAdjudicator.objects.get(adjudicator=self.object, debate__round=round)
        except DebateAdjudicator.DoesNotExist:
            return self.error_page(_("It looks like you don't have a debate this round."))
        except DebateAdjudicator.MultipleObjectsReturned:
            return self.error_page(_("It looks like you're assigned to two or more debates this round. "
                    "Please contact a tab room official."))

        self.debate = self.debateadj.debate
        self.ballotsub = BallotSubmission(debate=self.debate, ip_address=get_ip_address(self.request),
            submitter_type=BallotSubmission.SUBMITTER_PUBLIC)

        if not self.debate.adjudicators.has_chair:
            return self.error_page(_("Your debate doesn't have a chair, so you can't enter results for it. "
                    "Please contact a tab room official."))

        if not (self.tournament.pref('draw_side_allocations') == 'manual-ballot' and
                self.tournament.pref('teams_in_debate') == 'two') and not self.debate.sides_confirmed:
            return self.error_page(_("It looks like the sides for this debate haven't yet been confirmed, "
                    "so you can't enter results for it. Please contact a tab room official."))
コード例 #5
0
ファイル: views.py プロジェクト: jzbahrai/tabbycat
def new_ballotset(request, t, debate_id):
    debate = get_object_or_404(Debate, id=debate_id)
    ip_address = get_ip_address(request)
    ballotsub = BallotSubmission(debate=debate, submitter=request.user,
            submitter_type=BallotSubmission.SUBMITTER_TABROOM, ip_address=ip_address)

    if not debate.adjudicators.has_chair:
        return HttpResponseBadRequest("Whoops! This debate doesn't have a chair, so you can't enter results for it.")

    if request.method == 'POST':
        form = BallotSetForm(ballotsub, request.POST)
        if form.is_valid():
            form.save()
            ActionLogEntry.objects.log(type=ActionLogEntry.ACTION_TYPE_BALLOT_CREATE, user=request.user,
                    ballot_submission=ballotsub, ip_address=ip_address, tournament=t)
            messages.success(request, "Ballot set for %s added." % debate.matchup)
            return redirect_round('results', debate.round)
    else:
        form = BallotSetForm(ballotsub)

    template = 'enter_results.html' if request.user.is_superuser else 'assistant_enter_results.html'
    all_ballotsubs = debate.ballotsubmission_set_by_version if request.user.is_superuser \
            else debate.ballotsubmission_set_by_version_except_discarded
    context = {
        'form'             : form,
        'ballotsub'        : ballotsub,
        'debate'           : debate,
        'round'            : debate.round,
        'all_ballotsubs'   : all_ballotsubs,
        'not_singleton'    : all_ballotsubs.exists(),
        'new'              : True,
        'show_adj_contact' : True,
    }
    return render(request, template, context)
コード例 #6
0
ファイル: views.py プロジェクト: tienne-B/tabbycat
    def populate_objects(self, prefill=True):
        self.debate = self.object = self.get_object()
        self.ballotsub = BallotSubmission(
            debate=self.debate,
            submitter=self.request.user,
            submitter_type=BallotSubmission.SUBMITTER_TABROOM,
            ip_address=get_ip_address(self.request))

        if self.debate.round.ballots_per_debate == 'per-adj' and \
                not self.debate.adjudicators.has_chair:
            messages.error(
                self.request,
                _("Whoops! The debate %(debate)s doesn't have a chair, "
                  "so you can't enter results for it.") %
                {'debate': self.matchup_description()})
            return HttpResponseRedirect(self.get_error_url())

        if not (self.tournament.pref('draw_side_allocations')
                == 'manual-ballot' and self.tournament.pref('teams_in_debate')
                == 'two') and not self.debate.sides_confirmed:
            messages.error(
                self.request,
                _("Whoops! The debate %(debate)s doesn't have its "
                  "sides confirmed, so you can't enter results for it.") %
                {'debate': self.matchup_description()})
            return HttpResponseRedirect(self.get_error_url())
コード例 #7
0
 def get_submitter_fields(self):
     request = self.get_request()
     return {
         'submitter': request.user,
         'submitter_type': Submission.SUBMITTER_TABROOM,
         'ip_address': get_ip_address(request),
     }
コード例 #8
0
ファイル: views.py プロジェクト: BenMusch/tabbycat
def update_breaking_teams(request, t, category):
    bc = get_object_or_404(BreakCategory, slug=category, tournament=t)
    breaking.update_breaking_teams(bc)
    ActionLogEntry.objects.log(type=ActionLogEntry.ACTION_TYPE_BREAK_UPDATE_ONE,
            user=request.user, tournament=t, ip_address=get_ip_address(request),
            break_category=bc)
    messages.success(request, "Teams break updated for break category %s." % bc.name)
    return redirect_tournament('breaking_teams', t, category=category)
コード例 #9
0
ファイル: mixins.py プロジェクト: czlee/tabbycat
 def log_action(self, **kwargs):
     """Logs the action. Subclasses can call this if the class doesn't
     have `FormMixin`. If keyword arguments are provided, they override the
     keyword arguments provided by `get_action_log_fields()`, except for
     `ip_address`, which cannot be overridden.
     """
     ip_address = get_ip_address(self.request)
     action_log_fields = self.get_action_log_fields()
     action_log_fields.update(kwargs)
     ActionLogEntry.objects.log(ip_address=ip_address, **action_log_fields)
コード例 #10
0
ファイル: mixins.py プロジェクト: tfpk/tabbycat
 def log_action(self, **kwargs):
     """Logs the action. Subclasses can call this if the class doesn't
     have `FormMixin`. If keyword arguments are provided, they override the
     keyword arguments provided by `get_action_log_fields()`, except for
     `ip_address`, which cannot be overridden.
     """
     ip_address = get_ip_address(self.request)
     action_log_fields = self.get_action_log_fields()
     action_log_fields.update(kwargs)
     ActionLogEntry.objects.log(ip_address=ip_address, **action_log_fields)
コード例 #11
0
    def populate_objects(self):
        self.debate = self.object = self.get_object()
        self.ballotsub = BallotSubmission(debate=self.debate, submitter=self.request.user,
            submitter_type=BallotSubmission.SUBMITTER_TABROOM,
            ip_address=get_ip_address(self.request))

        if not self.debate.adjudicators.has_chair:
            messages.error(self.request, "Whoops! The debate %s doesn't have a chair, "
                "so you can't enter results for it." % self.debate.matchup)
            return redirect_round('results-round-list', self.ballotsub.debate.round)
コード例 #12
0
ファイル: views.py プロジェクト: modale/tabbycat
    def populate_objects(self):
        self.debate = self.object = self.get_object()
        self.ballotsub = BallotSubmission(debate=self.debate, submitter=self.request.user,
            submitter_type=BallotSubmission.SUBMITTER_TABROOM,
            ip_address=get_ip_address(self.request))

        if not self.debate.adjudicators.has_chair:
            messages.error(self.request, "Whoops! The debate %s doesn't have a chair, "
                "so you can't enter results for it." % self.debate.matchup)
            return redirect_round('results-round-list', self.ballotsub.debate.round)
コード例 #13
0
ファイル: views.py プロジェクト: jzbahrai/tabbycat
def edit_ballotset(request, t, ballotsub_id):
    ballotsub = get_object_or_404(BallotSubmission, id=ballotsub_id)
    debate = ballotsub.debate

    if not request.user.is_superuser:
        all_ballotsubs = debate.ballotsubmission_set_by_version_except_discarded
    else:
        all_ballotsubs = debate.ballotsubmission_set_by_version

    identical_ballotsubs_dict = debate.identical_ballotsubs_dict
    for b in all_ballotsubs:
        if b in identical_ballotsubs_dict:
            b.identical_ballotsub_versions = identical_ballotsubs_dict[b]

    if request.method == 'POST':
        form = BallotSetForm(ballotsub, request.POST)

        if form.is_valid():
            form.save()

            if ballotsub.discarded:
                action_type = ActionLogEntry.ACTION_TYPE_BALLOT_DISCARD
                messages.success(request, "Ballot set for %s discarded." % debate.matchup)
            elif ballotsub.confirmed:
                ballotsub.confirmer = request.user
                ballotsub.confirm_timestamp = datetime.datetime.now()
                ballotsub.save()
                action_type = ActionLogEntry.ACTION_TYPE_BALLOT_CONFIRM
                messages.success(request, "Ballot set for %s confirmed." % debate.matchup)
            else:
                action_type = ActionLogEntry.ACTION_TYPE_BALLOT_EDIT
                messages.success(request, "Edits to ballot set for %s saved." % debate.matchup)
            ActionLogEntry.objects.log(type=action_type, user=request.user,
                ballot_submission=ballotsub, ip_address=get_ip_address(request), tournament=t)

            return redirect_round('results', debate.round)
    else:
        form = BallotSetForm(ballotsub)

    template = 'enter_results.html' if request.user.is_superuser else 'assistant_enter_results.html'
    context = {
        'form'             : form,
        'ballotsub'        : ballotsub,
        'debate'           : debate,
        'all_ballotsubs'   : all_ballotsubs,
        'disable_confirm'  : request.user == ballotsub.submitter and not t.pref('enable_assistant_confirms') and not request.user.is_superuser,
        'round'            : debate.round,
        'not_singleton'    : all_ballotsubs.exclude(id=ballotsub_id).exists(),
        'new'              : False,
        'show_adj_contact' : True,
    }
    return render(request, template, context)
コード例 #14
0
ファイル: views.py プロジェクト: jzbahrai/tabbycat
def edit_eligibility(request, t):
    context = dict()
    if request.method == "POST":
        form = forms.BreakEligibilityForm(t, request.POST)
        if form.is_valid():
            form.save()
            ActionLogEntry.objects.log(type=ActionLogEntry.ACTION_TYPE_BREAK_ELIGIBILITY_EDIT,
                    user=request.user, tournament=t, ip_address=get_ip_address(request))
            messages.success(request, "Break eligibility saved.")
    else:
        form = forms.BreakEligibilityForm(t)

    context['form'] = form
    return render(request, 'edit_eligibility.html', context)
コード例 #15
0
ファイル: views.py プロジェクト: BenMusch/tabbycat
def breaking_teams(request, t, category):
    bc = get_object_or_404(BreakCategory, slug=category, tournament=t)

    if request.method == "POST":
        form = forms.BreakingTeamsForm(bc, request.POST)
        if form.is_valid():
            form.save()
        ActionLogEntry.objects.log(type=ActionLogEntry.ACTION_TYPE_BREAK_EDIT_REMARKS,
            user=request.user, tournament=t, ip_address=get_ip_address(request))
        messages.success(request, "Changes to breaking team remarks saved.")

    else:
        form = forms.BreakingTeamsForm(bc)

    generated = BreakingTeam.objects.filter(break_category__tournament=t).exists()
    return render(request, 'breaking_teams.html', dict(form=form, category=bc, generated=generated))
コード例 #16
0
ファイル: views.py プロジェクト: czlee/tabbycat
    def populate_objects(self):
        self.debate = self.object = self.get_object()
        self.ballotsub = BallotSubmission(debate=self.debate, submitter=self.request.user,
            submitter_type=BallotSubmission.SUBMITTER_TABROOM,
            ip_address=get_ip_address(self.request))

        if self.debate.round.ballots_per_debate == 'per-adj' and \
                not self.debate.adjudicators.has_chair:
            messages.error(self.request, _("Whoops! The debate %(debate)s doesn't have a chair, "
                "so you can't enter results for it.") % {'debate': self.matchup_description()})
            return HttpResponseRedirect(self.get_error_url())

        if not (self.tournament.pref('draw_side_allocations') == 'manual-ballot' and
                self.tournament.pref('teams_in_debate') == 'two') and not self.debate.sides_confirmed:
            messages.error(self.request, _("Whoops! The debate %(debate)s doesn't have its "
                "sides confirmed, so you can't enter results for it.") % {'debate': self.matchup_description()})
            return HttpResponseRedirect(self.get_error_url())
コード例 #17
0
ファイル: mixins.py プロジェクト: czlee/tabbycat
    def log_action(self, **kwargs):
        """Logs the action. Subclasses can call this if the class doesn't
        have `FormMixin`. If keyword arguments are provided, they override the
        keyword arguments provided by `get_action_log_fields()`, except for
        `ip_address`, which cannot be overridden.
        """
        ip_address = get_ip_address(self.request)
        action_log_fields = self.get_action_log_fields()
        action_log_fields.update(kwargs)
        log = ActionLogEntry.objects.log(ip_address=ip_address, **action_log_fields)

        # Notify the actionlog consumer to broadcast the event
        if self.tournament:
            print('Broadcasting notification of ActionLogEntryConsumer')
            group_name = ActionLogEntryConsumer.group_prefix + "_" + self.tournament.slug
            async_to_sync(get_channel_layer().group_send)(group_name, {
                "type": "send_json",
                "data": log.serialize,
            })
コード例 #18
0
    def log_action(self, **kwargs):
        """Logs the action. Subclasses can call this if the class doesn't
        have `FormMixin`. If keyword arguments are provided, they override the
        keyword arguments provided by `get_action_log_fields()`, except for
        `ip_address`, which cannot be overridden.
        """
        ip_address = get_ip_address(self.request)
        action_log_fields = self.get_action_log_fields()
        action_log_fields.update(kwargs)
        log = ActionLogEntry.objects.log(ip_address=ip_address, **action_log_fields)

        # Notify the actionlog consumer to broadcast the event
        if self.tournament:
            print('Broadcasting notification of ActionLogEntryConsumer')
            group_name = ActionLogEntryConsumer.group_prefix + "_" + self.tournament.slug
            async_to_sync(get_channel_layer().group_send)(group_name, {
                "type": "send_json",
                "data": log.serialize,
            })
コード例 #19
0
    def populate_objects(self):
        self.object = self.get_object() # must be populated before self.error_page() called

        round = self.get_tournament().current_round
        if round.draw_status != Round.STATUS_RELEASED or not round.motions_released:
            return self.error_page("The draw and/or motions for the round haven't been released yet.")

        try:
            self.debateadj = DebateAdjudicator.objects.get(adjudicator=self.object, debate__round=round)
        except DebateAdjudicator.DoesNotExist:
            return self.error_page("It looks like you don't have a debate this round.")

        self.debate = self.debateadj.debate
        self.ballotsub = BallotSubmission(debate=self.debate, ip_address=get_ip_address(self.request),
            submitter_type=BallotSubmission.SUBMITTER_PUBLIC)

        if not self.debate.adjudicators.has_chair:
            return self.error_page("Your debate doesn't have a chair, so you can't enter results for it. "
                    "Please contact a tab room official.")
コード例 #20
0
ファイル: views.py プロジェクト: modale/tabbycat
    def populate_objects(self):
        self.object = self.get_object() # must be populated before self.error_page() called

        round = self.get_tournament().current_round
        if round.draw_status != Round.STATUS_RELEASED or not round.motions_released:
            return self.error_page("The draw and/or motions for the round haven't been released yet.")

        try:
            self.debateadj = DebateAdjudicator.objects.get(adjudicator=self.object, debate__round=round)
        except DebateAdjudicator.DoesNotExist:
            return self.error_page("It looks like you don't have a debate this round.")
        except DebateAdjudicator.MultipleObjectsReturned:
            return self.error_page("It looks like you're assigned to two or more debates this round. "
                    "Please contact a tab room official.")

        self.debate = self.debateadj.debate
        self.ballotsub = BallotSubmission(debate=self.debate, ip_address=get_ip_address(self.request),
            submitter_type=BallotSubmission.SUBMITTER_PUBLIC)

        if not self.debate.adjudicators.has_chair:
            return self.error_page("Your debate doesn't have a chair, so you can't enter results for it. "
                    "Please contact a tab room official.")
コード例 #21
0
ファイル: views.py プロジェクト: jzbahrai/tabbycat
def public_new_ballotset(request, t, adjudicator):
    round = t.current_round

    if round.draw_status != Round.STATUS_RELEASED or not round.motions_released:
        return render(request, 'public_enter_results_error.html', dict(adjudicator=adjudicator,
                message='The draw and/or motions for the round haven\'t been released yet.'))
    try:
        da = DebateAdjudicator.objects.get(adjudicator=adjudicator, debate__round=round)
    except DebateAdjudicator.DoesNotExist:
        return render(request, 'public_enter_results_error.html', dict(adjudicator=adjudicator,
                message='It looks like you don\'t have a debate this round.'))

    ip_address = get_ip_address(request)
    ballotsub = BallotSubmission(debate=da.debate, ip_address=ip_address,
            submitter_type=BallotSubmission.SUBMITTER_PUBLIC)

    if request.method == 'POST':
        form = BallotSetForm(ballotsub, request.POST, password=True)
        if form.is_valid():
            form.save()
            ActionLogEntry.objects.log(type=ActionLogEntry.ACTION_TYPE_BALLOT_SUBMIT,
                    ballot_submission=ballotsub, ip_address=ip_address, tournament=t)
            return render(request, 'public_success.html', dict(success_kind="ballot"))
    else:
        form = BallotSetForm(ballotsub, password=True)

    context = {
        'form'                : form,
        'debate'              : da.debate,
        'round'               : round,
        'ballotsub'           : ballotsub,
        'adjudicator'         : adjudicator,
        'existing_ballotsubs' : da.debate.ballotsubmission_set.exclude(discarded=True).count(),
        'show_adj_contact'    : False,
    }
    return render(request, 'public_enter_results.html', context)
コード例 #22
0
 def get_submitter_fields(self):
     return {
         'submitter_type': Submission.SUBMITTER_PUBLIC,
         'ip_address': get_ip_address(self.request)
     }
コード例 #23
0
ファイル: mixins.py プロジェクト: BenMusch/tabbycat
 def log_action(self):
     ip_address = get_ip_address(self.request)
     ActionLogEntry.objects.log(type=self.get_action_log_type(),
             ip_address=ip_address, **self.get_action_log_fields())
コード例 #24
0
ファイル: mixins.py プロジェクト: jzbahrai/tabbycat
 def form_valid(self, form):
     ip_address = get_ip_address(self.request)
     ActionLogEntry.objects.log(type=self.get_action_log_type(),
             ip_address=ip_address, **self.get_action_log_fields())
     return super().form_valid(form)
コード例 #25
0
 def get_submitter_fields(self):
     return {
         'submitter': self.request.user,
         'submitter_type': Submission.SUBMITTER_TABROOM,
         'ip_address': get_ip_address(self.request)
     }
コード例 #26
0
ファイル: views.py プロジェクト: tienne-B/tabbycat
    def populate_objects(self, prefill=True):
        self.object = self.get_object(
        )  # must be populated before self.error_page() called

        if self.round.draw_status != Round.STATUS_RELEASED:
            return self.error_page(
                _("The draw for this round hasn't been released yet."))

        if (self.tournament.pref('enable_motions') or self.tournament.pref('motion_vetoes_enabled')) \
                and not self.round.motions_released:
            return self.error_page(
                _("The motions for this round haven't been released yet."))

        try:
            self.debateadj = DebateAdjudicator.objects.get(
                adjudicator=self.object, debate__round=self.round)
        except DebateAdjudicator.DoesNotExist:
            return self.error_page(
                _("It looks like you don't have a debate this round."))
        except DebateAdjudicator.MultipleObjectsReturned:
            return self.error_page(
                _("It looks like you're assigned to two or more debates this round. "
                  "Please contact a tab room official."))

        self.debate = self.debateadj.debate
        self.ballotsub = BallotSubmission(
            debate=self.debate,
            ip_address=get_ip_address(self.request),
            submitter_type=BallotSubmission.SUBMITTER_PUBLIC,
            single_adj=self.tournament.pref('individual_ballots'),
            private_url=self.private_url,
            participant_submitter=self.object)

        self.round_motions = {}
        for rm in RoundMotion.objects.filter(round_id=self.debate.round_id):
            self.round_motions[rm.motion_id] = rm

        self.result = DebateResult(self.ballotsub,
                                   round=self.round,
                                   tournament=self.tournament)
        self.vetos = None
        self.prefilled = False
        if self.ballotsub.single_adj and prefill:
            former_ballot = self.debate.ballotsubmission_set.filter(
                discarded=False).exclude(
                    participant_submitter=self.object, ).prefetch_related(
                        'speakerscore_set',
                        'speakerscore_set__debate_team',
                        'debateteammotionpreference_set',
                        'debateteammotionpreference_set__debate_team',
                    ).order_by('-confirmed', '-version').first()
            if former_ballot is not None:
                self.set_speakers(former_ballot)
                self.set_motions(former_ballot)

        if not self.debate.adjudicators.has_chair:
            return self.error_page(
                _("Your debate doesn't have a chair, so you can't enter results for it. "
                  "Please contact a tab room official."))

        if not (self.tournament.pref('draw_side_allocations')
                == 'manual-ballot' and self.tournament.pref('teams_in_debate')
                == 'two') and not self.debate.sides_confirmed:
            return self.error_page(
                _("It looks like the sides for this debate haven't yet been confirmed, "
                  "so you can't enter results for it. Please contact a tab room official."
                  ))
コード例 #27
0
 def get_submitter_fields(self):
     return {
         'submitter_type': Submission.SUBMITTER_PUBLIC,
         'ip_address': get_ip_address(self.request)
     }