Exemple #1
0
def deferred_default_hashtag_text(node, kw):
    """ If this is a reply to something else, the default value will
        contain the userid of the original poster + any hashtags used.
    """
    context = kw["context"]
    request = kw["request"]
    output = u""
    request_tag = request.GET.get("tag", None)
    if request_tag:
        if not HASHTAG_PATTERN.match(request_tag):
            request_tag = None  # Blank it, since it's invalid!
    if IAgendaItem.providedBy(context):
        # This is a first post - don't add any hashtags or similar,
        # unless they're part of query string
        if request_tag:
            output += u"#%s" % request_tag
        return output
    # get creator of answered object
    creators = context.get_field_value("creators")
    if creators:
        output += u"@%s: " % creators[0]
    # get tags and make a string of them
    tags = list(context.get_tags([]))
    if request_tag and request_tag not in tags:
        tags.append(request_tag)
    for tag in tags:
        output += u" #%s" % tag
    return output
Exemple #2
0
 def get_ai_results(self):
     for obj in self.context.values():
         if IAgendaItem.providedBy(obj):
             preprocess_tags = IPreprocessUserTags(obj)
             results = preprocess_tags.get_results()
             if results:
                 yield obj, results
Exemple #3
0
def _update_if_ai_parent(catalog, obj):
    """ Since AIs keep track of count of Poll, Proposal and Discussion objects.
        Only needed for add and remove.
    """
    parent = getattr(obj, '__parent__', None)
    if IAgendaItem.providedBy(parent):
        reindex_object(catalog, parent)
Exemple #4
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("config_uri", help="Paster ini file to load settings from")
    parser.add_argument("path", help="from which path to clear likes (meeting or agenda item)")
    args = parser.parse_args()
    env = bootstrap(args.config_uri)
    root = env['root']
    request = env['request']
    context = traverse(root, args.path).get('context')

    if IMeeting.providedBy(context) or IAgendaItem.providedBy(context):
        print('Clearing likes on {}'.format(context.title))
        path_query = query.Eq('path', args.path)
        cleared = False

        for type_name in ('Proposal', 'DiscussionPost'):
            count, docids = root.catalog.query(path_query & query.Eq('type_name', type_name))
            response = input('Found {} {} on {}. Do you want to clear likes on these? (y/N) '.format(
                count, type_name, context.title).encode('utf8'))
            if response.lower() in ('y', 'yes', 'j', 'ja'):
                cleared = True
                for obj in request.resolve_docids(docids, perm=None):
                    like = request.registry.getAdapter(obj, IUserTags, name='like')
                    like.storage.clear()
                    like._notify()

        if cleared:
            transaction.commit()
            env['closer']()

    else:
        print('Path does not match a meeting or agenda item')
Exemple #5
0
def _update_if_ai_parent(catalog, obj):
    """ Since AIs keep track of count of Poll, Proposal and Discussion objects.
        Only needed for add and remove.
    """
    parent = getattr(obj, '__parent__', None)
    if IAgendaItem.providedBy(parent):
        reindex_object(catalog, parent)
Exemple #6
0
def all_agenda_items_keys(node, kw):
    context = kw['context']
    values = []
    for (name, obj) in context.items():
        if IAgendaItem.providedBy(obj):
            values.append(name)
    return values
Exemple #7
0
def deferred_default_hashtag_text(node, kw):
    """ If this is a reply to something else, the default value will
        contain the userid of the original poster + any hashtags used.
    """
    context = kw['context']
    request = kw['request']
    output = u""
    request_tag = request.GET.get('tag', None)
    if request_tag:
        if not HASHTAG_PATTERN.match(request_tag):
            request_tag = None  #Blank it, since it's invalid!
    if IAgendaItem.providedBy(context):
        #This is a first post - don't add any hashtags or similar,
        #unless they're part of query string
        if request_tag:
            output += u"#%s" % request_tag
        return output
    # get creator of answered object
    creators = context.get_field_value('creators')
    if creators:
        output += u"@%s: " % creators[0]
    # get tags and make a string of them
    tags = list(context.get_tags([]))
    if request_tag and request_tag not in tags:
        tags.append(request_tag)
    for tag in tags:
        output += u" #%s" % tag
    return output
Exemple #8
0
def selectable_agenda_items_widget(node, kw):
    context = kw['context']
    values = []
    for (name, obj) in context.items():
        if not IAgendaItem.providedBy(obj):
            continue
        values.append((name, obj.title))
    return deform.widget.CheckboxChoiceWidget(values=values)
Exemple #9
0
def speaker_list_controls_moderator(api, slists, context):
    assert IAgendaItem.providedBy(context)
    response = {}
    response['api'] = api
    response['context'] = context
    response['active_list'] = slists.get(slists.active_list_name)
    response['context_lists'] = slists.get_contextual_lists(context)
    return render("templates/speaker_list_controls_moderator.pt", response, request = api.request)
Exemple #10
0
 def render(self, context, request, view, **kwargs):
     if IAgendaItem.providedBy(context):
         query = "type_name == 'Poll' and path == '%s'" % resource_path(context)
         query += " and workflow_state in any(['ongoing', 'upcoming', 'closed'])"
         if request.is_moderator or view.catalog_query(query):
             url = request.resource_url(context, self.view_name)
             response = {'portlet': self.portlet, 'view': view, 'load_url': url}
             return render(self.template, response, request=request)
Exemple #11
0
def get_docids_to_show(request, context, type_name, tags=(), limit=5, start_after=None,
                       end_before=None):
    """ Helper method to fetch docids that would be a resonable batch to show.
        This is mostly to allow agenda views to load fast.

        - Fetch batch from the first unread docid so there will be no items
            skipped in case they were read from a tag view.
        - If batch contains less items than limit, insert items from previous.
        - start_after - remove everything before this docid and the value specified.
        - end_before - remove this value and everything after it.
        
        Result example:
        {'batch': [4, 5, 6], 'previous': [1, 2, 3], 'over_limit': [7, 8, 9], 'unread': [4, 5, 6, 7, 8, 9]}
    """
    assert IAgendaItem.providedBy(context)
    query = Eq('path', resource_path(context))
    query &= Eq('type_name', type_name)
    if tags:
        query &= Any('tags', list(tags))
    read_names = request.get_read_names(context)
    unread_query = query & NotAny('__name__', set(read_names.get(request.authenticated_userid, [])))
    unread_docids = list(request.root.catalog.query(unread_query, sort_index='created')[1])
    docids_pool = list(request.root.catalog.query(query, sort_index='created')[1])

    if start_after and start_after in docids_pool:
        i = docids_pool.index(start_after)
        for docid in docids_pool[:i + 1]:
            if docid in unread_docids:
                unread_docids.remove(docid)
        docids_pool[0:i + 1] = []
    if end_before and end_before in docids_pool:
        i = docids_pool.index(end_before)
        for docid in docids_pool[i:]:
            if docid in unread_docids:
                unread_docids.remove(docid)
        docids_pool[i:] = []
    if limit:
        if unread_docids:
            first_pos = docids_pool.index(unread_docids[0])
            batch = docids_pool[first_pos:first_pos + limit]
            over_limit = docids_pool[first_pos + limit:]
            previous = docids_pool[:first_pos]
            # Fill batch from last item of previous if batch is too small
            while previous and len(batch) < limit:
                batch.insert(0, previous.pop(-1))
        else:
            batch = docids_pool[-limit:]
            previous = docids_pool[:-limit]
            over_limit = []
        return {'batch': batch,
                'previous': previous,
                'over_limit': over_limit,
                'unread': unread_docids}
    # no limit
    return {'batch': docids_pool,
            'previous': [],
            'over_limit': [],
            'unread': unread_docids}
 def render(self, context, request, view, **kwargs):
     if IAgendaItem.providedBy(context):
         query = {}
         tags = request.GET.getall('tag')
         if tags:
             query['tag'] = [x.lower() for x in tags]
         url = request.resource_url(context, self.view_name, query=query)
         response = {'portlet': self.portlet, 'view': view, 'load_url': url}
         return render(self.template, response, request=request)
Exemple #13
0
def evolve(root):
    """ Remove old redis attrs
    """
    for meeting in [x for x in root.values() if IMeeting.providedBy(x)]:
        if hasattr(meeting, '_read_names_counter'):
            delattr(meeting, '_read_names_counter')
        for ai in [x for x in meeting.values() if IAgendaItem.providedBy(x)]:
            if hasattr(ai, '_read_names'):
                delattr(ai, '_read_names')
Exemple #14
0
 def render(self, context, request, view, **kwargs):
     if IAgendaItem.providedBy(context):
         query = {}
         tags = request.GET.getall('tag')
         if tags:
             query['tag'] = [x.lower() for x in tags]
         url = request.resource_url(context, self.view_name, query=query)
         response = {'portlet': self.portlet, 'view': view, 'load_url': url}
         return render(self.template, response, request=request)
Exemple #15
0
 def visible(self, context, request, view, **kwargs):
     if IAgendaItem.providedBy(context):
         if request.is_moderator:
             return True
         diff_text = IDiffText(context)
         paragraphs = diff_text.get_paragraphs()
         if paragraphs:
             return True
     return False
Exemple #16
0
 def add(self, key, value, parent = None):
     if not ISpeakerList.providedBy(value):
         raise TypeError("Only objects implementing ISpeakerList allowed")
     if parent is None:
         request = get_current_request()
         parent = request.context
     assert IAgendaItem.providedBy(parent)
     value.__parent__ = parent #To hack in traversal
     self.speaker_lists[key] = value
     return key
Exemple #17
0
def projector_menu_link(context, request, va, **kw):
    """ Visible in the moderator menu, but doesn't work for the meeting root """
    if IAgendaItem.providedBy(context):
        url = request.resource_url(request.meeting, '__projector__', anchor=context.__name__)
    else:
        url = request.resource_url(request.meeting, '__projector__')
    return """<li><a href="{url}" title="{title}">{title}</a></li>""".format(
        title=request.localizer.translate(va.title),
        url=url,
    )
Exemple #18
0
def find_ais(root, found):
    for m in root.values():
        if not IMeeting.providedBy(m):
            continue
        print "Processing: /%s" % m.__name__
        for ai in m.values():
            if not IAgendaItem.providedBy(ai) or ai.uid not in found:
                continue
            mark_read(ai, found.pop(ai.uid))
            if not found:
                return
Exemple #19
0
def find_ais(root, found):
    for m in root.values():
        if not IMeeting.providedBy(m):
            continue
        print "Processing: /%s" % m.__name__
        for ai in m.values():
            if not IAgendaItem.providedBy(ai) or ai.uid not in found:
                continue
            mark_read(ai, found.pop(ai.uid))
            if not found:
                return
Exemple #20
0
 def render(self, context, request, view, **kwargs):
     if request.meeting:
         ai_name = IAgendaItem.providedBy(
             context) and context.__name__ or ''
         response = {
             'title': self.title,
             'portlet': self.portlet,
             'view': view,
             'load_url': self.load_url(request, ai_name)
         }
         return render(self.tpl, response, request=request)
Exemple #21
0
 def minutes(self):
     """ Show an overview of the meeting activities. Should work as a template for minutes. """
     if self.request.meeting.get_workflow_state() != 'closed':
         msg = _(u"meeting_not_closed_minutes_incomplete_notice",
                 default = u"This meeting hasn't closed yet so these minutes won't be complete")
         self.flash_messages.add(msg)
     #Add agenda item objects to response
     results = []
     for obj in self.context.values():
         if IAgendaItem.providedBy(obj) and self.request.has_permission(security.VIEW, obj):
             results.append(obj)
     return {'agenda_items': results}
def set_initial_order(obj, event):
    """ Sets the initial order of the agenda item """
    meeting = find_interface(obj, IMeeting)
    assert meeting
    
    order = 0
    for ai in meeting.values():
        if IAgendaItem.providedBy(ai):
            if ai.get_field_value('order') >= order:
                order = ai.get_field_value('order')+1

    obj.set_field_appstruct({'order': order})
Exemple #23
0
 def render(self, context, request, view, **kwargs):
     if IAgendaItem.providedBy(context):
         pns = IParticipantNumbers(request.meeting, None)
         pn = None
         if pns:
             pn = pns.userid_to_number.get(request.authenticated_userid, None)
         update_interv = request.speaker_lists.settings.get('user_update_interval', 5)
         return render(self.tpl,
                       {'portlet': self.portlet,
                        'view': view,
                        'user_update_interval': update_interv,
                        'pn': pn},
                       request=request)
Exemple #24
0
 def save_success(self, appstruct):
     from_meeting = self.request.root[appstruct['meeting_name']]
     reset_wf =  appstruct['all_props_published']
     only_copy_prop_states = appstruct['only_copy_prop_states']
     copy_types = appstruct['copy_types']
     assert IMeeting.providedBy(from_meeting)
     counter = 0
     for ai in from_meeting.values():
         if not IAgendaItem.providedBy(ai):
             continue
         counter += copy_ai(self.context, ai, reset_wf=reset_wf, only_copy_prop_states=only_copy_prop_states, copy_types=copy_types)
     self.flash_messages.add(_("Copied ${num} objects", mapping={'num': counter}))
     return HTTPFound(location=self.request.resource_url(self.context))
Exemple #25
0
 def render(self, context, request, view, **kwargs):
     if IAgendaItem.providedBy(context):
         query = "type_name == 'Poll' and path == '%s'" % resource_path(
             context)
         query += " and workflow_state in any(['ongoing', 'upcoming', 'closed'])"
         if request.is_moderator or view.catalog_query(query):
             url = request.resource_url(context, self.view_name)
             response = {
                 'portlet': self.portlet,
                 'view': view,
                 'load_url': url
             }
             return render(self.template, response, request=request)
Exemple #26
0
def evolve(root):
    """ Migrate all old unread markers that were stored in the catalog.
    """
    if '__name__' not in root.catalog:
        raise KeyError("__name__ index must be in catalog before this migration."
                       "Run catalog update first.")
    #We only need to care about meetings
    for m in root.values():
        if not IMeeting.providedBy(m):
            continue
        users = set(root.local_roles) | set(m.local_roles)
        for ai in m.values():
            if not IAgendaItem.providedBy(ai):
                continue
            convert_ai(ai, users)
        print "Processed '%s' for %s users" % (m.__name__, len(users))
def system_users_in_add_schema(schema, event):
    """ Inject a choice so add a proposal as another user if:
        - The current user is a moderator
        - System users are set on the meeting
    """
    #The context check here is essentially a guess if this is an add-view.
    if IAgendaItem.providedBy(
            event.context) and event.request.has_permission(MODERATE_MEETING):
        system_userids = _get_other_system_userids(event.request)
        if system_userids:
            schema.add(
                colander.SchemaNode(colander.Set(),
                                    name='creator',
                                    title=_("Add as"),
                                    widget=add_as_system_user_widget,
                                    validator=current_user_or_system_users,
                                    preparer=to_tuple,
                                    default=current_userid_as_tuple,
                                    missing=current_userid_as_tuple))
Exemple #28
0
 def _get_sibbling_ai(self, pos):
     meeting = self.request.meeting
     m_order = tuple(meeting.order)
     ai_count = len(m_order)
     try:
         this_pos = meeting.order.index(self.context.__name__)
     except ValueError:
         return
     #only try a few times - we don't want to iterate through the whole meeting
     # if there's lots of hidden Agenda items.
     for obj_pos in range(this_pos+pos, this_pos+(pos*5), pos):
         if obj_pos < 0 or obj_pos > ai_count:
             return
         try:
             obj = meeting[m_order[obj_pos]]
         except (KeyError, IndexError):
             return
         if not IAgendaItem.providedBy(obj):
             continue
         if self.request.has_permission(VIEW, obj):
             return obj
Exemple #29
0
def _reorder_ais(meeting):
    order_priority = {}
    #Order will be blank so we must fetch the keys from data
    curr_keys = set(meeting.data.keys())
    if curr_keys != set(meeting.keys()):
        meeting.order = meeting.data.keys()
    for k in curr_keys:
        order_priority[k] = len(curr_keys)
    for ai in meeting.values():
        if not IAgendaItem.providedBy(ai):
            continue
        if 'order' in ai.field_storage:
            order_priority[ai.__name__] = ai.field_storage.pop('order')
    def _sorter(key):
        return order_priority[key]
    order = sorted(curr_keys, key=_sorter)
    meeting.order = order
    for obj in find_all_db_objects(meeting):
        cataloger = ICataloger(obj, None)
        if cataloger:
            cataloger.index_object()
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("config_uri",
                        help="Paster ini file to load settings from")
    parser.add_argument(
        "path", help="from which path to clear likes (meeting or agenda item)")
    args = parser.parse_args()
    env = bootstrap(args.config_uri)
    root = env['root']
    request = env['request']
    context = traverse(root, args.path).get('context')

    if IMeeting.providedBy(context) or IAgendaItem.providedBy(context):
        print('Clearing likes on {}'.format(context.title))
        path_query = query.Eq('path', args.path)
        cleared = False

        for type_name in ('Proposal', 'DiscussionPost'):
            count, docids = root.catalog.query(
                path_query & query.Eq('type_name', type_name))
            response = input(
                'Found {} {} on {}. Do you want to clear likes on these? (y/N) '
                .format(count, type_name, context.title).encode('utf8'))
            if response.lower() in ('y', 'yes', 'j', 'ja'):
                cleared = True
                for obj in request.resolve_docids(docids, perm=None):
                    like = request.registry.getAdapter(obj,
                                                       IUserTags,
                                                       name='like')
                    like.storage.clear()
                    like._notify()

        if cleared:
            transaction.commit()
            env['closer']()

    else:
        print('Path does not match a meeting or agenda item')
Exemple #31
0
def _reorder_ais(meeting):
    order_priority = {}
    #Order will be blank so we must fetch the keys from data
    curr_keys = set(meeting.data.keys())
    if curr_keys != set(meeting.keys()):
        meeting.order = meeting.data.keys()
    for k in curr_keys:
        order_priority[k] = len(curr_keys)
    for ai in meeting.values():
        if not IAgendaItem.providedBy(ai):
            continue
        if 'order' in ai.field_storage:
            order_priority[ai.__name__] = ai.field_storage.pop('order')

    def _sorter(key):
        return order_priority[key]

    order = sorted(curr_keys, key=_sorter)
    meeting.order = order
    for obj in find_all_db_objects(meeting):
        cataloger = ICataloger(obj, None)
        if cataloger:
            cataloger.index_object()
Exemple #32
0
def evolve(root):
    """ Migrate unread to redis
    """
    try:
        from fakeredis import FakeStrictRedis
        maybe_fr = True
    except ImportError:
        maybe_fr = False
    request = get_current_request()
    if maybe_fr:
        if isinstance(request.redis_conn, FakeStrictRedis):
            raise Exception(
                "Your redis connection is a FakeRedis instance. "
                "All migrated data would be thrown away! "
                "Please set voteit.redis_url in your paster.ini file.")
    for meeting in [x for x in root.values() if IMeeting.providedBy(x)]:
        if hasattr(meeting, '_read_names_counter'):
            delattr(meeting, '_read_names_counter')
        for ai in [x for x in meeting.values() if IAgendaItem.providedBy(x)]:
            if not hasattr(ai, '_read_names'):
                continue
            read_names = request.get_read_names(ai)
            for (userid, names) in ai._read_names.items():
                read_names.mark_read(names, userid)
Exemple #33
0
 def visible(self, context, request, view, **kwargs):
     # These will all be visible regardless
     return IAgendaItem.providedBy(context)
Exemple #34
0
class ManageAgendaItemsView(BaseView):
    def __call__(self):
        post = self.request.POST
        if 'cancel' in self.request.POST:
            url = self.request.resource_url(self.context)
            return HTTPFound(location=url)
        if 'change' in post:
            state_id = self.request.POST['state_id']
            block_proposals = self.request.POST.get('block_proposals', None)
            block_proposals = _BLOCK_VALS.get(block_proposals, None)
            block_discussion = self.request.POST.get('block_discussion', None)
            block_discussion = _BLOCK_VALS.get(block_discussion, None)

            controls = self.request.POST.items()
            agenda_items = []
            for (k, v) in controls:
                if k == 'ais':
                    agenda_items.append(self.context[v])
            output_msg = ""
            translate = self.request.localizer.translate
            #WF state change
            if state_id:
                states_changed = 0
                for ai in agenda_items:
                    try:
                        ai.set_workflow_state(self.request, state_id)
                        states_changed += 1
                    except WorkflowError, e:
                        self.flash_messages.add(_(
                            'Unable to change state on ${title}: ${error}',
                            mapping={
                                'title': ai.title,
                                'error': e
                            }),
                                                type='danger')
                if states_changed:
                    output_msg += translate(
                        _("${num} changed state",
                          mapping={'num': states_changed}))
                    output_msg += "<br/>"
            #Block states
            if block_proposals != None or block_discussion != None:
                blocked = 0
                for ai in agenda_items:
                    blocked += 1
                    if block_proposals != None:
                        ai.set_field_value('proposal_block', block_proposals)
                    if block_discussion != None:
                        ai.set_field_value('discussion_block',
                                           block_discussion)
                if blocked:
                    output_msg += translate(
                        _("Changing block state for ${num} agenda items.",
                          mapping={'num': blocked}))

            if output_msg:
                self.flash_messages.add(output_msg, type='success')
            else:
                self.flash_messages.add(_('Nothing updated'), type='warning')
            return HTTPFound(location=self.request.resource_url(
                self.context, 'manage_agenda'))

        state_info = _dummy_agenda_item.workflow.state_info(None, self.request)
        tstring = _

        def _translated_state_title(state):
            for info in state_info:
                if info['name'] == state:
                    return tstring(info['title'])
            return state

        response = {}
        response['translated_state_title'] = _translated_state_title
        response['find_resource'] = find_resource
        response['states'] = states = ('ongoing', 'upcoming', 'closed',
                                       'private')
        response['ais'] = ais = {}
        for state in states:
            ais[state] = []
        for obj in self.context.values():
            if IAgendaItem.providedBy(obj):
                ais[obj.get_workflow_state()].append(obj)
        return response
Exemple #35
0
 def get_ai(self):
     if self.ai_name in self.context:
         ai = self.context[self.ai_name]
         if IAgendaItem.providedBy(ai):
             return ai
Exemple #36
0
def get_docids_to_show(request,
                       context,
                       type_name,
                       tags=(),
                       limit=5,
                       start_after=None,
                       end_before=None):
    """ Helper method to fetch docids that would be a resonable batch to show.
        This is mostly to allow agenda views to load fast.

        - Fetch batch from the first unread docid so there will be no items
            skipped in case they were read from a tag view.
        - If batch contains less items than limit, insert items from previous.
        - start_after - remove everything before this docid and the value specified.
        - end_before - remove this value and everything after it.
        
        Result example:
        {'batch': [4, 5, 6], 'previous': [1, 2, 3], 'over_limit': [7, 8, 9], 'unread': [4, 5, 6, 7, 8, 9]}
    """
    assert IAgendaItem.providedBy(context)
    query = Eq('path', resource_path(context))
    query &= Eq('type_name', type_name)
    if tags:
        query &= Any('tags', list(tags))
    read_names = request.get_read_names(context)
    unread_query = query & NotAny(
        '__name__', set(read_names.get(request.authenticated_userid, [])))
    unread_docids = list(
        request.root.catalog.query(unread_query, sort_index='created')[1])
    docids_pool = list(
        request.root.catalog.query(query, sort_index='created')[1])

    if start_after and start_after in docids_pool:
        i = docids_pool.index(start_after)
        for docid in docids_pool[:i + 1]:
            if docid in unread_docids:
                unread_docids.remove(docid)
        docids_pool[0:i + 1] = []
    if end_before and end_before in docids_pool:
        i = docids_pool.index(end_before)
        for docid in docids_pool[i:]:
            if docid in unread_docids:
                unread_docids.remove(docid)
        docids_pool[i:] = []
    if limit:
        if unread_docids:
            first_pos = docids_pool.index(unread_docids[0])
            batch = docids_pool[first_pos:first_pos + limit]
            over_limit = docids_pool[first_pos + limit:]
            previous = docids_pool[:first_pos]
            # Fill batch from last item of previous if batch is too small
            while previous and len(batch) < limit:
                batch.insert(0, previous.pop(-1))
        else:
            batch = docids_pool[-limit:]
            previous = docids_pool[:-limit]
            over_limit = []
        return {
            'batch': batch,
            'previous': previous,
            'over_limit': over_limit,
            'unread': unread_docids
        }
    # no limit
    return {
        'batch': docids_pool,
        'previous': [],
        'over_limit': [],
        'unread': unread_docids
    }
Exemple #37
0
def get_read_names(request, context):
    assert IAgendaItem.providedBy(context)
    return request.registry.queryMultiAdapter([context, request], IReadNames)
def moderator_context_delete(context, request, va, **kw):
    """ This is already a part of the Arches context menu, so it shouldn't be shown in meetings or agenda items.
    """
    if IAgendaItem.providedBy(context) or IMeeting.providedBy(context):
        return
    return moderator_context_action(context, request, va, **kw)
def get_read_names(request, context):
    assert IAgendaItem.providedBy(context)
    return request.registry.queryMultiAdapter([context, request], IReadNames)