Ejemplo n.º 1
0
def feed_agenda_item_state_change(obj, event):
    """ Will add a feed entry when the state change on agenda items.
    """
    request = get_current_request()
    userid = authenticated_userid(request)
    msg = None
    if event.old_state == "private" and event.new_state == "upcoming":
        msg = _(u"${agenda_item} has been added to the agenda.", mapping={"agenda_item": obj.title})
    elif event.new_state == "ongoing":
        msg = _(u"${agenda_item} has been set to ongoing.", mapping={"agenda_item": obj.title})
    elif event.new_state == "closed":
        msg = _(u"${agenda_item} has been closed.", mapping={"agenda_item": obj.title})
    if msg:
        meeting = find_interface(obj, IMeeting)
        feed_handler = request.registry.getAdapter(meeting, IFeedHandler)

        feed_handler.add(obj.uid, msg, tags=("agenda_item", event.new_state))
Ejemplo n.º 2
0
def feed_poll_state_change(obj, event):
    """ Will add a feed entry when a poll is opened and closes
    """
    if event.new_state in ("ongoing", "closed"):
        request = get_current_request()
        userid = authenticated_userid(request)
        agenda_item = find_interface(obj, IAgendaItem)
        if event.new_state == "ongoing":
            msg = _(
                u"A poll has started in ${agenda_item}, vote now!",
                mapping={"userid": userid, "agenda_item": agenda_item.title},
            )
        elif event.new_state == "closed":
            msg = _(u"The result of a poll in ${agenda_item} is set.", mapping={"agenda_item": agenda_item.title})
        meeting = find_interface(obj, IMeeting)
        feed_handler = request.registry.getAdapter(meeting, IFeedHandler)
        feed_handler.add(obj.uid, msg, tags=("poll", event.new_state))
Ejemplo n.º 3
0
def create_feed_object(request):
    settings = IFeedSettings(request.meeting, {})
    te = request.localizer.translate
    fg = FeedGenerator()
    fg.id(rss_feed_url(request, token=settings.get('token', None))) #Mandatory for atom feeds
    fg.title(request.meeting.title)
    fg.description(settings.get('description_text', te(_("No description"))))
    #fg.author({'name': 'XXXX', 'email': '*****@*****.**'})
    fg.link(href=request.resource_url(request.meeting), rel='alternate')
    #fg.icon('http://ex.com/icon.jpg')
    #fg.logo('http://ex.com/logo.jpg')
    #fg.rights('cc-by')
    #fg.subtitle('This is a cool feed!')
    fg.link(href=rss_feed_url(request, token=settings.get('link_token')), rel='self')
    fg.language(request.localizer.locale_name)
    # Fetch objects we want to interact with
    limit = settings.get('limit', 50)
    type_names = list(settings.get('type_names', ()))
    items = get_feed_items(request, type_names, limit=limit)
    # Create feed entries
    for obj in items:
        # Newest first is already the case in items
        fe = fg.add_entry(order='append')
        author_txt = _cleanup_txt(request.creators_info(obj.creator, portrait=False, no_tag=True))
        # Needed?
        fe.id(request.resource_url(obj))
        fe.published(obj.created)
        if obj.type_name == 'Poll':
            fe.title(te(_("${state} poll: ${title}",
                          mapping={'state': te(voteit_mf(obj.current_state_title(request))),
                                   'title': obj.title})))
            fe.content()
            #fe.summary()
        if obj.type_name == 'DiscussionPost':
            fe.title(te(_("${name} added a discussion post", mapping={'name': author_txt})))
            fe.content(nl2br(obj.text))
            #fe.summary()
        if obj.type_name == 'Proposal':
            fe.title(te(_("${name} added a proposal", mapping={'name': author_txt})))
            fe.content(request.render_proposal_text(obj, tag_func=lambda x: x))
            #fe.summary()
        fe.link(href=request.resource_url(obj), rel='alternate')
        fe.author(name=author_txt)
    return fg
Ejemplo n.º 4
0
def includeme(config):
    config.scan(__name__)
    config.add_view_action(
        control_panel_category,
        'control_panel', 'feed',
        panel_group='control_panel_feed',
        title=_("RSS Feeds"),
        check_active=feeds_enabled,
    )
    config.add_view_action(
        control_panel_link,
        'control_panel_feed', 'settings',
        title=_("Settings"),
        view_name='feed_settings_form',
    )
    config.add_view_action(
        rss_feed_link,
        'control_panel_feed', 'link_to_feed',
        title=_("Link to RSS feed"),
    )
Ejemplo n.º 5
0
def feed_discussion_post_added(obj, event):
    """ Will add a feed entry when a discussion post is added if agenda item is not private.
    """
    request = get_current_request()
    userid = authenticated_userid(request)
    agenda_item = find_interface(obj, IAgendaItem)
    if agenda_item.get_workflow_state() == "private":
        return
    msg = _(
        u"${userid} has written a post in ${agenda_item}.", mapping={"userid": userid, "agenda_item": agenda_item.title}
    )
    meeting = find_interface(obj, IMeeting)
    feed_handler = request.registry.getAdapter(meeting, IFeedHandler)
    feed_handler.add(obj.uid, msg, tags=("discussion_post", "added"))
Ejemplo n.º 6
0
    def _get_feed(self):
        ''' Makes a respone dict for renderers '''
        def _get_url(entry):
            """ If something stored in the database is deleted,
                the query won't return any object since that UID won't exist.
            """
            brains = self.api.get_metadata_for_query(uid=entry.context_uid)
            if brains:
                resource = find_resource(self.api.root, brains[0]['path'])
                return self.request.resource_url(resource)
            return self.request.resource_url(self.api.meeting)
        
        # Borrowed from PyRSS2Gen, thanks for this workaround
        def _format_date(dt):
            """convert a datetime into an RFC 822 formatted date
        
            Input date must be in GMT.
            """
            # Looks like:
            #   Sat, 07 Sep 2002 00:00:01 GMT
            # Can't use strftime because that's locale dependent
            #
            # Isn't there a standard way to do this for Python?  The
            # rfc822 and email.Utils modules assume a timestamp.  The
            # following is based on the rfc822 module.
            tz = pytz.timezone('GMT')
            dt = tz.normalize(dt.astimezone(tz))
            return "%s, %02d %s %04d %02d:%02d:%02d GMT" % (
                    ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"][dt.weekday()],
                    dt.day,
                    ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
                     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][dt.month-1],
                    dt.year, dt.hour, dt.minute, dt.second)

        feed_handler = self.request.registry.getAdapter(self.context, IFeedHandler)
        self.response['entries'] = feed_handler.feed_storage.values()
        self.response['format_date'] = _format_date
        self.response['active'] = self.context.get_field_value('rss_feed', False)
        self.response['feed_not_active_notice'] = self.api.translate(_(u"This RSS-feed isn't enabled."))
        # only show entries when meeting is ongoing
        self.response['closed'] = self.context.get_workflow_state() == 'closed'
        self.response['get_url'] = _get_url
        return self.response
Ejemplo n.º 7
0
    def _next_free_key(self):
        try:
            return self.feed_storage.maxKey()+1
        except ValueError: #Emptry tree
            return 0
    
    def add(self, context_uid, message, tags=(), context=None):
        obj = createContent('FeedEntry', context_uid, message, tags=tags)
        
        for i in range(10):
            k = self._next_free_key()
            if self.feed_storage.insert(k, obj):
                return
        
        raise KeyError("Couln't find a free key for feed handler after 10 retries.") # pragma : no cover


@content_factory('FeedEntry', title=_(u"Feed entry"))
class FeedEntry(Persistent):
    """ FeedEntry lightweight content type.
        See :mod:`voteit.core.models.interfaces.IFeedEntry`.
        All methods are documented in the interface of this class.
    """
    implements(IFeedEntry)

    def __init__(self, context_uid, message, tags=()):
        self.created = utcnow()
        self.context_uid = context_uid
        self.message = message
        self.tags = tuple(tags)
Ejemplo n.º 8
0
import colander
from betahaus.pyracont.decorators import schema_factory

from voteit.feed import FeedMF as _


@schema_factory('RssSettingsMeetingSchema', title = _(u"RSS settings"))
class RssSettingsMeetingSchema(colander.MappingSchema):
    rss_feed = colander.SchemaNode(colander.Boolean(),
        title = _(u"Activate RSS feed"),
        description = _(u"rss_feed_checkbox_description",
                        default=u"When the checkbox below is checked your meeting will be able to show a public RSS feed that can be followed with a RSS reader. This feed will contain info about when changes are made in the meeting and who did the changes. You can access the feed on: 'The meeting URL' + '/feed'. This should be something like 'www.yourdomain.com/yourmeetingname/feed'. If you want the feed to show up in an iframe you can use '/framefeed' instead. This is an advanced feature and read more about it in the manual on wiki.voteit.se. Please note a word of warning: the feed is public for all who can figure it out."),
        default = False,
    )
Ejemplo n.º 9
0
 def validator(self, form, value):
     if value["enable_rss"] and not len(value['type_names']):
         exc = colander.Invalid(form, _("Types missing"))
         exc["type_names"] = _("If RSS is enabled, you need to pick content types to add to the feed.")
         raise exc
Ejemplo n.º 10
0
def default_feed_description(node, kw):
    request = kw['request']
    return request.localizer.translate(_("An RSS feed this meeting"))
Ejemplo n.º 11
0
# -*- coding: utf-8 -*-
from uuid import uuid4

import colander
import deform

from voteit.feed import _


RSS_TYPES = (
    ("Proposal", _("Proposal")),
    ("DiscussionPost", _("Discussion post")),
    ("Poll", _("Poll")),
)


@colander.deferred
def default_feed_description(node, kw):
    request = kw['request']
    return request.localizer.translate(_("An RSS feed this meeting"))


class FeedSettingsSchema(colander.Schema):
    enable_rss = colander.SchemaNode(
        colander.Bool(),
        title = _("Enalbe RSS feeds"),
    )
    link_token = colander.SchemaNode(
        colander.String(),
        title = _("Add token to link"),
        description=_("Adds the following token to the link to make it impossible to guess."),
Ejemplo n.º 12
0
            except ValidationFailure, e:
                self.response['form'] = e.render()
                return self.response
            self.context.set_field_appstruct(appstruct)
            url = self.request.resource_url(self.context)
            return HTTPFound(location=url)
        if 'cancel' in post:
            self.api.flash_messages.add(_(u"Canceled"))
            url = self.request.resource_url(self.context)
            return HTTPFound(location=url)
        #No action - Render form
        appstruct = self.context.get_field_appstruct(schema)
        self.response['form'] = form.render(appstruct)
        return self.response

@view_action('settings_menu', 'rss_settings', title = _(u"RSS settings"), link = "rss_settings", permission = security.MODERATE_MEETING)
def generic_menu_link(context, request, va, **kw):
    """ This is for simple menu items for the meeting root """
    api = kw['api']
    url = "%s%s" % (api.meeting_url, va.kwargs['link'])
    return """<li><a href="%s">%s</a></li>""" % (url, api.translate(va.title))
    
@view_action('meeting', 'feed', title = _(u"RSS feed"), link = "feed", )
def feed_menu_link(context, request, va, **kw):
    """ This is for simple menu items for the meeting root """
    api = kw['api']
    url = request.resource_url(api.meeting, va.kwargs['link'])
    if api.meeting.get_field_value('rss_feed', False):
        return """<li><a href="%s">%s</a></li>""" % (url, api.translate(va.title))
    return '' # pragma : no coverage