예제 #1
0
 def user_checkout(self):
     if self.presence_qr.checkout(self.request.authenticated_userid,
                                  self.request):
         self.flash_messages.add(_("Checked out"), type="success")
     else:
         self.flash_messages.add(_("Already checked out"), type="warning")
     return HTTPFound(self.request.resource_path(self.context))
예제 #2
0
 def __call__(self):
     mp = IMeetingPresence(self.context)
     if not mp.enabled:
         raise HTTPForbidden(
             _("Presence check not enabled for this meeting."))
     if not len(mp.present_userids):
         self.flash_messages.add(_("No users to check in", type="danger"))
         return HTTPFound(location=self.request.resource_url(self.context))
     already_handled = 0
     checked_in = 0
     for userid in tuple(mp.present_userids):
         if userid in self.presence_qr:
             already_handled += 1
             continue
         self.presence_qr.checkin(userid, request=self.request)
         checked_in += 1
     self.flash_messages.add(
         _(
             "checkin_from_presence_msg",
             default=
             "Checked in ${checked_in} user(s). Skipped ${already_handled} already handled.",
             mapping={
                 "already_handled": already_handled,
                 "checked_in": checked_in
             },
         ),
         type=checked_in and "success" or "warning",
     )
     return HTTPFound(location=self.request.resource_url(self.context))
예제 #3
0
 def checkout_success(self, appstruct):
     userid = appstruct["userid"]
     if self.presence_qr.checkout(userid, self.request):
         self.flash_messages.add(_("Checked out"), type="success")
     else:
         self.flash_messages.add(_("Already checked out"), type="warning")
     return HTTPFound(
         location=self.request.resource_url(self.context, "manual_checkin"))
예제 #4
0
파일: schemas.py 프로젝트: VoteIT/voteit.qr
 def __call__(self, node, value):
     if not value:
         raise colander.Invalid(node, _("No UserID"))
     if not principal_has_permisson(
             self.request, value, VIEW, context=self.context):
         raise colander.Invalid(
             node,
             _("That user doesn't have permission to view this meeting."))
예제 #5
0
 def status_success(self, appstruct):
     userid = appstruct["userid"]
     if userid in self.presence_qr:
         self.flash_messages.add(_("User is checked in"), type="success")
         self.set_checkin_message(userid)
     else:
         self.flash_messages.add(_("User is checked out"), type="danger")
     url = self.request.resource_url(self.context,
                                     "manual_checkin",
                                     query={"userid": userid})
     return HTTPFound(location=url)
예제 #6
0
파일: schemas.py 프로젝트: VoteIT/voteit.qr
class QRManualCheckin(colander.Schema):
    userid = colander.SchemaNode(
        colander.String(),
        title=_("User"),
        widget=MeetingUserReferenceWidget(multiple=False),
        validator=UserCanViewMeeting,
        default=submitted_userid,
    )
    pn = colander.SchemaNode(
        colander.Int(),
        title=_('Set participant number'),
        missing=None,
    )
예제 #7
0
파일: schemas.py 프로젝트: VoteIT/voteit.qr
class QRSettingsSchema(colander.Schema):
    active = colander.SchemaNode(
        colander.Bool(),
        title=_("Enable QR code checkin?"),
    )
    log_time = colander.SchemaNode(
        colander.Bool(),
        title=_("Log time present for all users?"),
        default=True,
    )
    assign_pn = colander.SchemaNode(
        colander.Bool(),
        title=
        _("Create and assign a participant number at checkin if the user lacks one?"
          ),
    )
예제 #8
0
class QRSettingsForm(DefaultEditForm, QRViewMixin):
    schema_name = "settings"
    type_name = "QR"
    title = _("QR settings")

    def appstruct(self):
        appstruct = dict(self.presence_qr.settings)
        appstruct["active"] = self.presence_qr.active
        return appstruct

    def save_success(self, appstruct):
        self.presence_qr.active = appstruct.pop("active", False)
        enable_logging = appstruct.get("log_time", None)
        checked_in = len(self.presence_qr)
        if (enable_logging
                and not self.presence_qr.settings.get("log_time", None)
                and checked_in):
            self.flash_messages.add(
                _(
                    "logging_enalbed_with_checked_in_warning",
                    default=
                    "${users} have already checked in so their checkouts won't be "
                    "registered in the log.",
                    mapping={"users": checked_in},
                ),
                type="danger",
            )
        self.presence_qr.settings = appstruct
        self.flash_messages.add(self.default_success, type="success")
        return HTTPFound(location=self.request.resource_url(self.context))
예제 #9
0
def meeting_nav_link(context, request, va, **kw):
    """ Link to check-in or check-out from meeting. """
    try:
        pqr = IPresenceQR(request.meeting)
    except ComponentLookupError:
        return
    if not pqr.active:
        return
    if request.authenticated_userid in pqr:
        title = _("Check-out")
    else:
        title = _("Check-in")
    url = request.resource_path(request.meeting, "user_check_page")
    return """<li><a data-open-modal href="%s">%s</a></li>""" % (
        url,
        request.localizer.translate(title),
    )
예제 #10
0
 def save_success(self, appstruct):
     checked_in = tuple(self.presence_qr)
     for userid in checked_in:
         self.presence_qr.checkout(userid, request=self.request)
     msg = _("Checked out ${num} users", mapping={"num": len(checked_in)})
     self.flash_messages.add(msg, type="success")
     return HTTPFound(location=self.request.resource_url(
         self.context, "checked_in_users"))
예제 #11
0
def includeme(config):
    config.scan(__name__)
    config.add_view_action(
        control_panel_category,
        "control_panel",
        "qr",
        panel_group="control_panel_qr",
        title=_("QR codes"),
        description=_(
            "Checkin with QR codes, manually or with presence check if enabled."
        ),
        permission=security.MODERATE_MEETING,
        check_active=_qr_codes_active,
    )
    config.add_view_action(
        control_panel_link,
        "control_panel_qr",
        "settings",
        title=_("Settings"),
        view_name="qr_settings",
    )
    config.add_view_action(
        check_in_present_users_nav,
        "control_panel_qr",
        "check_in_present_users",
        view_name="_check_in_present_users",
    )
    config.add_view_action(
        control_panel_link,
        "control_panel_qr",
        "register_endpoint",
        title=_("Register endpoint"),
        view_name="register_endpoint_page",
    )
    config.add_view_action(
        control_panel_link,
        "control_panel_qr",
        "manual_checkin",
        title=_("Manual check-in"),
        view_name="manual_checkin",
    )
    config.add_view_action(
        control_panel_link,
        "control_panel_qr",
        "checked_in_users",
        title=_("Show checked in users"),
        view_name="checked_in_users",
    )
    config.add_view_action(
        control_panel_link,
        "control_panel_qr",
        "presence_log",
        title=_("Presence log"),
        view_name="_presence_log",
    )
    config.add_view_action(meeting_nav_link,
                           "nav_meeting",
                           "qr_check_user",
                           permission=security.VIEW)
예제 #12
0
def check_in_present_users_nav(context, request, va, **kw):
    mp = IMeetingPresence(request.meeting)
    if not mp.enabled:
        title = _("(Presence check not enabled)")
        return """<li class="text-muted">%s</li>""" % request.localizer.translate(
            title)
    if mp.open:
        title = _("Check in from open presence check")
    else:
        if not len(mp.present_userids):
            title = _("(No old presence check to use)")
            return """<li class="text-muted">%s</li>""" % request.localizer.translate(
                title)
        else:
            title = _("Check in from last archived presence check")
    return """<li><a href="%s">%s</a></li>""" % (
        request.resource_url(request.meeting, va.kwargs["view_name"]),
        request.localizer.translate(title),
    )
예제 #13
0
 def checkin_success(self, appstruct):
     userid = appstruct["userid"]
     pn = appstruct["pn"]
     ticket = pn and self.participant_numbers.tickets.get(pn)
     if pn and not ticket:
         self.flash_messages.add(_("Participant number is not available"),
                                 type="warning")
     checkin_status = self.presence_qr.checkin(userid, self.request)
     if ticket:
         if self.participant_numbers.userid_to_number.get(userid):
             self.flash_messages.add(
                 _("User already has a participant number"), type="warning")
         else:
             try:
                 self.participant_numbers.claim_ticket(userid, ticket.token)
             except TicketAlreadyClaimedError:
                 self.flash_messages.add(
                     _("Participant number already claimed"),
                     type="warning")
     elif not checkin_status:
         self.flash_messages.add(_("Already checked in"), type="warning")
     self.set_checkin_message(userid)
     return HTTPFound(
         location=self.request.resource_url(self.context, "manual_checkin"))
예제 #14
0
class CheckoutEveryoneForm(DefaultEditForm, QRViewMixin):
    title = _("Checkout everyone - are you sure?")

    def get_schema(self):
        return Schema()

    def save_success(self, appstruct):
        checked_in = tuple(self.presence_qr)
        for userid in checked_in:
            self.presence_qr.checkout(userid, request=self.request)
        msg = _("Checked out ${num} users", mapping={"num": len(checked_in)})
        self.flash_messages.add(msg, type="success")
        return HTTPFound(location=self.request.resource_url(
            self.context, "checked_in_users"))

    def cancel_success(self, *args):
        return HTTPFound(location=self.request.resource_url(
            self.context, "checked_in_users"))
예제 #15
0
 def presence_log(self):
     if not self.presence_qr.settings.get("log_time", None):
         self.flash_messages.add(_("Log not enabled in settings"),
                                 type="danger")
         return HTTPFound(location=self.request.resource_url(self.context))
     log = IPresenceEventLog(self.context)
     users = []
     for userid in log:
         try:
             user = self.request.root["users"][userid]
         except KeyError:
             user = None
         row = {
             "userid": userid,
             "fullname": user and user.title or "",
             "timedelta": log.total(userid),
         }
         users.append(row)
     users = sorted(users, key=lambda x: x["fullname"].lower())
     return {"users": users, "log": log}
예제 #16
0
 def receiver(self):
     payload = self.get_payload()
     translate = self.request.localizer.translate
     if payload.get("action") == "get_config":
         body = self.presence_qr.encode({
             "message":
             translate(
                 _(
                     "Handling checkins for VoteIT-meeting ${name}",
                     mapping={"name": self.context.title},
                 )),
             "config": {
                 "default_text":
                 translate(_("Please scan QR code to check in or out")),
                 "text_color":
                 "#0a243d",  # VoteIT dark blue TODO: import from somewhere?
                 "text_color_default":
                 "#aaaaaa",  # Light grey
                 "text_font": ("Arial", 20, "bold"),  # Family, size, style
                 "button_colors": {
                     "yes": "#5cb85c",
                     "no": "#d9534f",
                 },  # Bootstrap colors. TODO: Import?
             },
         })
         return Response(body, content_type=b"application/jwt")
     try:
         userid = payload["userid"]
     except KeyError:
         raise HTTPBadRequest("Invalid data")
     response = {}
     if not principal_has_permisson(
             self.request, userid, security.VIEW, context=self.context):
         raise HTTPForbidden("Not part of this meeting")
     # Check actions against what's being sent?
     # FIXME: Allow checkin event to decide what messages should be sent
     if userid not in self.presence_qr:
         response["message"] = translate(
             _("You've checked in as ${userid}", mapping={"userid":
                                                          userid}))
         self.presence_qr.checkin(userid, self.request)
     elif userid in self.presence_qr:
         # Essentially an action was performed
         value = payload.get("value", None)
         if value:
             if value == "yes":
                 self.presence_qr.checkout(userid, self.request)
                 response["message"] = translate(_("Checked out"))
             elif value == "no":
                 response["message"] = translate(
                     _("OK, you're still checked in"))
             else:
                 response["message"] = translate(
                     _("${act} is not a valid action",
                       mapping={"act": value}))
         else:
             response["question"] = {
                 "text":
                 translate(
                     _(
                         "Hello ${userid}. You're checked in. Do you want to exit and check out?",
                         mapping={"userid": userid},
                     )),
                 "buttons": (
                     ("no", translate(_("No"))),
                     ("yes", translate(_("Yes"))),
                 ),
                 "data":
                 payload,
             }
     body = self.presence_qr.encode(response)
     return Response(body, content_type=b"application/jwt")
예제 #17
0
class QRManualCheckin(DefaultEditForm, QRViewMixin):
    schema_name = "manual_checkin"
    type_name = "QR"
    title = _("Manual checkin")
    buttons = (
        Button("checkin", title=_("Check-in")),
        Button("checkout", title=_("Check-out")),
        Button("status", title=_("Status")),
    )
    session_key = "qr.manual.checked_in"

    @reify
    def participant_numbers(self):
        return IParticipantNumbers(self.context)

    @reify
    def role_dict(self):
        # type: () -> dict
        try:
            from voteit.vote_groups.interfaces import VOTE_GROUP_ROLES
        except ImportError:
            return {}
        return dict(VOTE_GROUP_ROLES)

    def get_user_groups(self, userid):
        """ Try to get groups from plugin voteit.vote_groups, if available """
        try:
            from voteit.vote_groups.interfaces import IVoteGroups
        except ImportError:
            pass
        else:
            groups = self.request.registry.getMultiAdapter(
                [self.context, self.request], IVoteGroups)
            user_groups = groups.vote_groups_for_user(userid)
            return [{
                "title":
                g.title,
                "role":
                self.request.localizer.translate(
                    self.role_dict.get(g[userid]) or g[userid]).lower(),
                "substitutes":
                g.get_primary_for(userid),
                "substitute":
                g.get_substitute_for(userid),
                "is_voter":
                userid in g.get_voters(),
            } for g in user_groups]

    def set_checkin_message(self, userid):
        checked_in = self.request.session.setdefault(self.session_key, {})
        # Below, temp solution because bad data in db
        if not isinstance(checked_in, dict):
            self.request.session[self.session_key] = {}
        user_groups = self.get_user_groups(userid)
        checked_in[self.context.uid] = {
            "userid": userid,
            "pn": self.participant_numbers.userid_to_number.get(userid),
            "groups": user_groups,
            "is_voter": any(g["is_voter"] for g in user_groups),
        }
        self.request.session.changed()

    def pop_checkin_message(self):
        msg = self.request.session.get(self.session_key,
                                       {}).pop(self.context.uid, {})
        self.request.session.changed()
        return msg

    def checkin_success(self, appstruct):
        userid = appstruct["userid"]
        pn = appstruct["pn"]
        ticket = pn and self.participant_numbers.tickets.get(pn)
        if pn and not ticket:
            self.flash_messages.add(_("Participant number is not available"),
                                    type="warning")
        checkin_status = self.presence_qr.checkin(userid, self.request)
        if ticket:
            if self.participant_numbers.userid_to_number.get(userid):
                self.flash_messages.add(
                    _("User already has a participant number"), type="warning")
            else:
                try:
                    self.participant_numbers.claim_ticket(userid, ticket.token)
                except TicketAlreadyClaimedError:
                    self.flash_messages.add(
                        _("Participant number already claimed"),
                        type="warning")
        elif not checkin_status:
            self.flash_messages.add(_("Already checked in"), type="warning")
        self.set_checkin_message(userid)
        return HTTPFound(
            location=self.request.resource_url(self.context, "manual_checkin"))

    def checkout_success(self, appstruct):
        userid = appstruct["userid"]
        if self.presence_qr.checkout(userid, self.request):
            self.flash_messages.add(_("Checked out"), type="success")
        else:
            self.flash_messages.add(_("Already checked out"), type="warning")
        return HTTPFound(
            location=self.request.resource_url(self.context, "manual_checkin"))

    def status_success(self, appstruct):
        userid = appstruct["userid"]
        if userid in self.presence_qr:
            self.flash_messages.add(_("User is checked in"), type="success")
            self.set_checkin_message(userid)
        else:
            self.flash_messages.add(_("User is checked out"), type="danger")
        url = self.request.resource_url(self.context,
                                        "manual_checkin",
                                        query={"userid": userid})
        return HTTPFound(location=url)