def pronoun_in_site_settings(schema, event): schema.add(colander.SchemaNode( colander.Boolean(), name="pronoun_active", title=_("Let users select pronoun"), description=_("Pronoun might be shown in different contexts like the speaker list."), missing=False))
def __call__(self, form, values): exc = colander.Invalid(form) # Raised if trouble pns = self.request.registry.getAdapter(self.request.meeting, IParticipantNumbers) numbers = tuple(pns.tickets.keys()) start_at = values['start_at'] if start_at not in numbers and not values['create_new']: exc['start_at'] = _("Not an existing participant number") raise exc existing_emails = tuple([x.email for x in pns.tickets.values()]) found = [] i = start_at emails = values['emails'].splitlines() for email in emails: if email in existing_emails: found.append(email) if not values['create_new']: # Check if numbers exist if i not in numbers: exc['emails'] = _("attach_emails_pn_dont_exist_error", default="There are more email addresses than " "existing participant numbers. " "Number ${num} not found. Total emails: ${emails_count}", mapping={'num': i, 'emails_count': len(emails)}) raise exc i += 1 if found: exc['emails'] = _("The following emails are already assigned to numbers: ${emails}", mapping={'emails': ", ".join(found)}) raise exc
def claim_participant_number_menu(context, request, va, **kw): if request.meeting: translate = request.localizer.translate participant_numbers = request.registry.getAdapter(request.meeting, IParticipantNumbers) if request.authenticated_userid not in participant_numbers.userid_to_number: self_assignment = request.registry.getAdapter(request.meeting, ISelfAssignmentSettings) if self_assignment.enabled: if self_assignment.user_has_required_role(request): url = request.resource_url(request.meeting, 'self_claim_participant_number') else: # The current user don't have the required role role = request.registry.roles.get(self_assignment.required_role, None) if role: role_title = translate(role.title) else: role_title = self_assignment.required_role return """<li class="disabled"><a>%s<br/>%s</a></li>""" % ( translate( _("You lack the role '${role}'", mapping={'role': role_title}) ), translate( _("which is required to request a participant number.") ), ) else: url = request.resource_url(request.meeting, 'claim_participant_number') return """<li><a href="%s">%s</a></li>""" % (url, translate(_("Claim participant number"))) else: return """<li class="disabled"><a>%s: %s</a></li>""" % ( translate(_("Your participant number")), participant_numbers.userid_to_number[request.authenticated_userid] )
def adjust_voters(self, method_name): method = self.request.registry.getAdapter(self.context, IElegibleVotersMethod, name = method_name) new_voters = method.get_voters(request = self.request) if not isinstance(new_voters, frozenset): new_voters = frozenset(new_voters) electoral_register = self.request.registry.getAdapter(self.context, IElectoralRegister) current_voters = electoral_register.currently_set_voters() if current_voters == new_voters: msg = _(u"no_update_of_perms_needed_notice", default = u"Method '${method_title}' applied but it reports no change needed.", mapping = {'method_title': self.request.localizer.translate(method.title)}) self.flash_messages.add(msg) return removed_voters = current_voters - new_voters added_voters = new_voters - current_voters for userid in removed_voters: self.context.del_groups(userid, (ROLE_VOTER,)) for userid in added_voters: self.context.add_groups(userid, (ROLE_VOTER,)) msg = _("updated_voter_permissions_notice", default = "Method '${method_title}' added ${added_count} and removed ${removed_count}.", mapping = {'method_title': self.request.localizer.translate(method.title), 'added_count': len(added_voters), 'removed_count': len(removed_voters)}) self.flash_messages.add(msg)
def save_success(self, appstruct): # Since this is a bit backwards, we need to fetch the token. pn = appstruct['pn'] userid = appstruct['userid'] found = False for (token, num) in self.participant_numbers.token_to_number.items(): if num == pn: found = True break if not found: raise HTTPForbidden(_(u"Participant number not found")) # Clear old number? if userid in self.participant_numbers.userid_to_number: number = self.participant_numbers.userid_to_number[userid] msg = _("participant_number_moved_warning", default = u"This user was already assigned number ${number} so that number was cleared.", mapping = {'number': number}) self.flash_messages.add(msg, type = 'warning') self.participant_numbers.clear_number(number) # Assign number = self.participant_numbers.claim_ticket(userid, token) msg = _("number_now_assigned_notice", default = "You're now assigned number ${number}.", mapping = {'number': number}) self.flash_messages.add(msg) return HTTPFound(location = self.request.resource_url(self.context, "manage_participant_numbers"))
def claim_participant_number(self): """ This view is for participants who're already members of this meeting, but haven't registered their number yet. """ if self.api.userid in self.participant_numbers.userid_to_number: number = self.participant_numbers.userid_to_number[self.api.userid] msg = _(u"already_assigned_number_error", default = u"You've already been assigned the number ${number} so you don't need to do anything else.", mapping = {'number': number}) self.api.flash_messages.add(msg, type = 'error') return HTTPFound(location = self.api.meeting_url) schema = createSchema('ClaimParticipantNumber') schema = schema.bind(context = self.context, request = self.request, api = self.api) form = deform.Form(schema, buttons = [deform.Button('submit', title = _(u"Submit"))]) if 'submit' in self.request.POST: controls = self.request.POST.items() try: appstruct = form.validate(controls) except deform.ValidationFailure, e: self.response['form'] = e.render() return self.response number = self.participant_numbers.claim_ticket(self.api.userid, appstruct['token']) msg = _(u"number_now_assigned_notice", default = u"You're now assigned number ${number}.", mapping = {'number': number}) self.api.flash_messages.add(msg) return HTTPFound(location = self.api.meeting_url)
def __call__(self, node, value): if value not in security.find_authorized_userids(self.context, [security.VIEW]): raise colander.Invalid(node, _("${userid} doesn't exist in this meeting.", mapping = {'userid': value})) if security.ROLE_VOTER in self.context.get_groups(value): raise colander.Invalid(node, _("${userid} is already a voter.", mapping = {'userid': value}))
def manage_participant_numbers(self): if 'back' in self.request.POST: return HTTPFound(location = self.request.resource_url(self.context)) response = {} add = 'add' in self.request.POST remove = 'remove' in self.request.POST here_url = self.request.resource_url(self.context, 'manage_participant_numbers') if add or remove: #Basic validation try: start = self.request.POST.get('start', None) start = int(start) end = self.request.POST.get('end', None) if not end: end = None else: end = int(end) if start > end: raise HTTPForbidden(_(u"End must be higher than start")) except TypeError: raise HTTPForbidden(_(u"Must be an integer value")) if add: res = self.participant_numbers.new_tickets(self.request.authenticated_userid, start, end) msg = _(u"Added ${count} new numbers", mapping = {'count': len(res)}) self.flash_messages.add(msg) if remove: res = self.participant_numbers.clear_numbers(start, end) msg = _(u"Removed ${count} numbers", mapping = {'count': len(res)}) self.flash_messages.add(msg, type = "warning") return HTTPFound(location = here_url) response['participant_numbers'] = self.participant_numbers return response
def __call__(self, node, value): if not principal_has_permisson(self.request, value, security.VIEW, context=self.context): raise colander.Invalid(node, _("${userid} doesn't exist in this meeting.", mapping={'userid': value})) if security.ROLE_VOTER in self.context.get_groups(value): raise colander.Invalid(node, _("${userid} is already a voter.", mapping={'userid': value}))
def __call__(self, node, value): participant_numbers = self.request.registry.getAdapter(self.context, IParticipantNumbers) if value not in participant_numbers.token_to_number: raise colander.Invalid(node, _(u"No match - remember that it's case sensitive!")) number = participant_numbers.token_to_number[value] if participant_numbers.tickets[number].claimed: raise colander.Invalid(node, _(u"This number has already been claimed."))
def includeme(config): config.add_portlet(MeetingPresencePortlet) config.scan(__name__) config.add_view_action( control_panel_category, 'control_panel', 'meeting_presence', panel_group = 'control_panel_meeting_presence', title=_("Meeting presence"), description=_("meeting_presence_cp_description", default="Check who's present. " "Can be used as base to distribute voting rights."), permission = MODERATE_MEETING, check_active=meeting_presence_enabled, ) config.add_view_action( control_panel_link, 'control_panel_meeting_presence', 'check', title=_("Check presence"), view_name='check_meeting_presence', priority=10, ) config.add_view_action( control_panel_link, 'control_panel_meeting_presence', 'settings', title=_("Settings"), view_name='meeting_presence_settings', priority=20, )
def get_schema(self): schema = colander.Schema(title = _(u"Select discussion posts to print"), description = _(u"print_discussion_description", default = u"Each post will be on its own page")) for post in self.context.get_content(content_type = 'DiscussionPost'): schema.add(colander.SchemaNode(colander.Bool(), name = post.__name__, title = strip_and_truncate(post.text, symbol = '[...]'),)) return schema
def __call__(self): if security.ROLE_VOTER not in self.api.cached_effective_principals: raise HTTPForbidden(_("You're not a voter")) query = {'content_type': 'Poll', 'path': resource_path(self.context), 'workflow_state': 'ongoing'} res = self.api.search_catalog(**query)[0] if res.total > 0: raise HTTPForbidden(_("Votes can't be transfered while a poll is open.")) return super(TransferVoteForm, self).__call__()
def __call__(self, node, value): parts = value.split('-') err = _("Must be written as 'NN-XX' where N is low nr and X high.") if len(parts) != 2: raise colander.Invalid(node, err) try: parts = [int(x) for x in parts] except: raise colander.Invalid(node, err) if parts[0] >= parts[1]: raise colander.Invalid(node, _("First value must be higher than second"))
def add_gender_in_profile(schema, event): request = get_current_request() if request.context.content_type == 'Meeting' and \ request.context.get_field_value('access_policy') != ParticipantNumberAPWithGender.name: return #Skip in meeting context without this AP schema.add(colander.SchemaNode(colander.String(), name = "gender", title = _(u"Gender"), description = _(u"Used for statistics and perhaps gender based quotas. See meeting for details."), widget = deform.widget.RadioChoiceWidget(values = GENDER_VALUES)), )
def get_schema(self): schema = colander.Schema(title = _(u"Select proposals to print"), description = _(u"print_proposals_description", default = u"Each proposal will be on its own page")) for prop in self.context.get_content(content_type = 'Proposal'): schema.add(colander.SchemaNode(colander.Bool(), name = prop.__name__, title = prop.get_field_value('aid'), description = prop.title)) return schema
def assign_success(self, appstruct): start_number = self.self_assignment_settings.get('start_number', None) if not isinstance(start_number, int): self.flash_messages.add(_("Meeting has bad configurartion for participant numbers, contact the moderator.", type='danger')) return HTTPFound(location=self.request.resource_url(self.context)) new_pn = assign_next_free_pn(self.participant_numbers, self.request.authenticated_userid, start_number) if not new_pn: raise HTTPBadRequest("No number can be assigned.") msg = _("You've been assigned number ${num}", mapping={'num': new_pn}) self.flash_messages.add(msg, type='success') return HTTPFound(location = self.request.resource_url(self.context))
def __call__(self): if not _enabled(self.request.meeting): raise HTTPForbidden(_('Vote transfer is not currently enabled.')) if security.ROLE_VOTER not in self.context.local_roles.get( self.request.authenticated_userid, ()): raise HTTPForbidden(_("You're not a voter")) query = Eq('type_name', 'Poll') & Eq('path', resource_path(self.context)) & Eq( 'workflow_state', 'ongoing') res = self.request.root.catalog.query(query)[0] if res.total > 0: raise HTTPForbidden(_("Votes can't be transfered while a poll is open.")) return super(TransferVoteForm, self).__call__()
def manage_participant_callbacks(self): if 'back' in self.request.POST: return HTTPFound(location = self.request.resource_url(self.context)) add = 'add' in self.request.POST remove = 'remove' in self.request.POST if add or remove: #Basic validation try: start = self.request.POST.get('start', None) start = int(start) end = self.request.POST.get('end', None) if not end: end = None else: end = int(end) if start > end: raise HTTPForbidden(_("End must be higher than start")) except TypeError: raise HTTPForbidden(_("Must be an integer value")) callback = self.request.POST['callback'] if add: added, existed = self.participant_callbacks.add(callback, start, end) msg = _(u"Added ${added} new callbacks and skipped ${existed} that already existed.", mapping = {'added': len(added), 'existed': len(existed)}) self.flash_messages.add(msg) if self.request.POST.get('execute_for_existing', True): executed = 0 if end == None: end = start for i in range(start, end + 1): #Range stops before end otherwise if i in self.participant_numbers.number_to_userid: #The method execute_callbacks_for is fault tolerant for missing callbacks, but not for #failures within the actual callback. self.participant_callbacks.execute_callbacks_for(i, self.participant_numbers.number_to_userid[i], limit = callback, request = self.request) executed += 1 msg = _(u"Executed callback for ${num} users that had already claimed a participant number.", mapping = {'num': executed}) self.flash_messages.add(msg) if remove: removed, nonexistent = self.participant_callbacks.remove(callback, start, end) msg = _(u"Removed ${removed} callbacks and skipped ${nonexistent} that wasn't registered.", mapping = {'removed': len(removed), 'nonexistent': len(nonexistent)}) self.flash_messages.add(msg) here_url = self.request.resource_url(self.context, 'manage_participant_callbacks') return HTTPFound(location = here_url) response = {} response['participant_numbers'] = self.participant_numbers response['participant_callbacks'] = self.participant_callbacks response['callback_adapters'] = [adapter for (name, adapter) in self.request.registry.getAdapters([self.request.meeting], IParticipantCallback)] return response
def includeme(config): config.scan(__name__) config.add_view_action( control_panel_category, 'control_panel', 'print_', panel_group='control_panel_print_btn_settings', title=_("Print button"), ) config.add_view_action( control_panel_link, 'control_panel_print_btn_settings', 'settings', title=_("Settings"), view_name='print_btn_settings', )
def inject_in_settings(schema, event): schema.add( colander.SchemaNode( colander.String(), title = _("Voter participant number range"), description=_("voter_pn_range_desc", default="Write number as 'NN-NN', i.e. 10-20 means that " "10 to and including 20 will be voters if they're " "marked as present."), name = 'elegible_voter_pn', missing = "", validator = ElegibleVoterPNRangeValidator(), ) )
def presence_check_ctrl(self): action = self.request.GET.get('action', '') if action == 'start': self.flash_messages.add(_("Started"), type = 'success') self.mp_util.start_check() elif action == 'end': if self.mp_util.open: self.flash_messages.add(_("Closed"), type = 'warning') self.mp_util.end_check() else: raise HTTPForbidden("No check ongoing") else: raise HTTPForbidden("No such action %r" % action) came_from = self.request.GET.get('came_from', self.request.resource_url(self.request.meeting)) return HTTPFound(location = came_from)
def save_success(self, appstruct): number = self.participant_numbers.claim_ticket(self.request.authenticated_userid, appstruct['token']) msg = _("number_now_assigned_notice", default = "You're now assigned number ${number}.", mapping = {'number': number}) self.flash_messages.add(msg) return HTTPFound(location = self.request.resource_url(self.context))
def execute_callbacks_for(self, number, userid, limit = None, request = None, **kw): assert isinstance(number, int) assert isinstance(userid, basestring) if request is None: request = get_current_request() if isinstance(limit, basestring): limit = (limit,) errors = [] executed = [] for callback_name in self.get_callbacks(number): if limit is None: callback = request.registry.queryAdapter(self.context, IParticipantCallback, name = callback_name) else: if not callback_name in limit: continue callback = request.registry.queryAdapter(self.context, IParticipantCallback, name = callback_name) #Check that adapter was found if callback is None: errors.append(callback_name) else: callback(number, userid, request = request, **kw) executed.append(callback_name) if errors: fm = request.registry.getAdapter(request, IFlashMessages) msg = _(u"could_not_execute_callback_error", default = u"Some callbacks for the UserId '${userid}' failed. Contact the moderator about this. " u"The ones that failed were: ${callback_errors}", mapping = {'callback_errors': ", ".join(errors), 'userid': userid}) fm.add(msg, type = 'error') return executed
def change_ownership(self, objects, schema): schema = schema.bind(context = self.context, request = self.request, api = self.api) back_url = self.request.resource_url(self.context) if not objects: self.api.flash_messages.add(_(u"No proposals here")) return HTTPFound(location = back_url) form = deform.Form(schema, buttons = (button_update, button_cancel,)) self.api.register_form_resources(form) if 'cancel' in self.request.POST: self.api.flash_messages.add(vmf(u"Canceled")) return HTTPFound(location = back_url) if 'update' in self.request.POST: controls = self.request.POST.items() try: #appstruct is deforms convention. It will be the submitted data in a dict. appstruct = form.validate(controls) except deform.exception.ValidationFailure, e: self.response['form'] = e.render() return self.response updated = set() for (name, owner) in appstruct.items(): obj = self.context[name] if change_ownership(obj, owner): updated.add(name) if updated: self.api.flash_messages.add(vmf(u"Successfully updated")) else: self.api.flash_messages.add(vmf(u"Nothing updated")) return HTTPFound(location = back_url)
def set_as_present(self): if self.request.authenticated_userid not in self.mp_util.present_userids: #Add here will raise forbidden if it isn't open self.mp_util.add(self.request.authenticated_userid) if self.request.is_xhr: return {} self.flash_messages.add(_("You're now set as present"), type = 'success') return HTTPFound(localtion = self.request.resource_url(self.request.meeting))
def elegible_voters_method_choices_widget(node, kw): """ Create a widget where you can choose all selectable methods to adjust elegible voters. """ context = kw['context'] request = kw['request'] method_choices = [('', _('<Select>'))] for (name, method) in request.registry.getAdapters([context], IElegibleVotersMethod): method_choices.append((name, method.title)) return deform.widget.SelectWidget(values=method_choices)
def save_success(self, appstruct): userid = appstruct['to_userid'] if userid is None: raise HTTPBadRequest("No userid found") self.context.del_groups(self.request.authenticated_userid, [security.ROLE_VOTER]) self.context.add_groups(userid, [security.ROLE_VOTER]) self.flash_messages.add(_("Vote transfered to ${userid}", mapping={'userid': userid})) return HTTPFound(location=self.request.resource_url(self.context))
def diff_electoral_register_view(self): post = self.request.POST if 'back' in post: url = self.request.resource_url(self.context, 'electoral_register') return HTTPFound(location = url) schema = createSchema('ElectoralRegisterDiff').bind(context = self.context, request = self.request, api = self.api) form = deform.Form(schema, buttons=(deform.Button('diff', _(u"Diff")), deform.Button('back', _(u"Back")),)) if 'diff' in post: controls = post.items() try: appstruct = form.validate(controls) self.response['form'] = form.render(appstruct = appstruct) self.append_diff_info(appstruct['first'], appstruct['second']) except deform.ValidationFailure, e: self.response['form'] = e.render()
def schema(self): schema = createSchema("ClaimParticipantNumber") if self.context.get_field_value('pn_ap_public_roles', False): schema['token'].missing = u"" schema['token'].description = _(u"token_validator_description_when_ok_without", default = u"Enter your code to claim your participant number and all permissions associated with it. " u"If you're not supposed to have a participant number, you're allowed to proceed by clicking " u"'Request access'.") return schema