Example #1
0
class CommentsFolder(Base, Folder, ContextACLMixin, LocalRolesMixin):
    """ Container for comments.
    """
    nav_visible = False
    listing_visible = True
    search_visible = True
    title = _("Comments")
    type_name = "CommentsFolder"
    type_title = _("Comments folder")
    type_description = _("Container for comments.")
    add_permission = ENABLE_COMMENTS
    enabled = False

    def is_subscibing(self, userid):
        return userid in self.subscribers

    def get_subscribers(self):
        return self.subscribers.keys()

    def add_subscribing_userid(self, userid):
        if userid not in self.subscribers:
            self.subscribers[userid] = unicode(uuid4())
        return self.subscribers[userid]

    def remove_subscribing_userid(self, userid):
        self.subscribers.pop(userid, None)

    def subscribe_url(self, request):
        userid = request.authenticated_userid
        if userid not in self.subscribers:
            return request.resource_url(self, 'subscribe')

    def unsubscribe_url(self, request, userid=None):
        userid = userid and userid or request.authenticated_userid
        if userid in self.subscribers:
            return request.resource_url(self, 'unsubscribe', userid, self.subscribers[userid])

    def validate(self, request):
        """ Fetch userid if token is valid. """
        if len(request.subpath) != 2:
            return
        userid = request.subpath[0]
        token = request.subpath[1]
        if self.subscribers.get(userid, object()) == token:
            return userid

    @property
    def subscribers(self):
        if not hasattr(self, '_subscribers'):
            self._subscribers = OOBTree()
        return self._subscribers

    @property
    def __acl__(self):
        """ Return the parents ACL and inject deny in case comments are closed. """
        acl = _find_closest_parent_attr(self, '__acl__', [])
        if not self.enabled:
            acl.insert(0, (Deny, Everyone, ADD_COMMENT))
        return acl
Example #2
0
class CommentSchema(colander.Schema):
    body = colander.SchemaNode(
        colander.String(),
        title=_("Comment"),
        description=_("Note that HTML tags will be stripped"),
        widget=deform.widget.TextAreaWidget(cols=10),
        validator=colander.Length(max=5000),
        preparer=convert_text,
    )
Example #3
0
class CommentsPortletSchema(colander.Schema):
    allowed_types = colander.SchemaNode(
        colander.Set(),
        title=_("Allow comments on these types?"),
        description=
        _("It will still require the user to have the correct permission to enable comments."
          ),
        widget=limit_types_widget,
        missing=(),
    )
Example #4
0
 def unsubscribe_notifications(self):
     if not len(self.request.subpath) == 2:
         raise HTTPNotFound()
     userid = self.context.validate(self.request)
     if userid:
         self.context.remove_subscribing_userid(userid)
         self.flash_messages.add(_("Notifications are now turned off."))
     else:
         self.flash_messages.add(_("No subscription found."))
     return HTTPFound(
         location=self.request.resource_url(self.context.__parent__))
Example #5
0
 def subscribe_notifications(self):
     userid = self.request.authenticated_userid
     if not userid:
         raise HTTPUnauthorized(_("You must be logged in"))
     if not self.context.is_subscibing(self.request.authenticated_userid):
         self.context.add_subscribing_userid(userid)
         self.flash_messages.add(
             _("You will receive email notifications when someone posts something here."
               ))
     else:
         self.flash_messages.add(_("You were already subscribing."))
     return HTTPFound(
         location=self.request.resource_url(self.context.__parent__))
Example #6
0
class CommentsPortlet(PortletType):
    name = "comments"
    title = _("Comments")
    tpl = "arche_comments:templates/portlet.pt"
    schema_factory = CommentsPortletSchema

    def visible(self, context, request, view, **kwargs):
        return context.get('_comments',
                           None) is not None or request.has_permission(
                               ENABLE_COMMENTS, context)

    def render(self, context, request, view, **kwargs):
        comments = context.get('_comments', None)
        allowed_types = self.portlet.settings.get('allowed_types', ())
        if not allowed_types:
            return
        if getattr(context, 'type_name', '') not in allowed_types:
            return
        can_toggle = request.has_permission(ENABLE_COMMENTS, context)
        if comments:
            need_lib('deform')
            can_add = request.has_permission(ADD_COMMENT, comments)
            can_view = request.has_permission(PERM_VIEW, comments)
        else:
            can_add = False
            can_view = None
        return render(self.tpl, {
            'portlet': self.portlet,
            'comments': comments,
            'view': view,
            'can_toggle': can_toggle,
            'can_add': can_add,
            'can_view': can_view
        },
                      request=request)
Example #7
0
 def add_success(self, appstruct):
     factory = self.request.content_factories[self.type_name]
     obj = factory(**appstruct)
     name = generate_slug(self.context, obj.uid)
     self.context[name] = obj
     self.flash_messages.add(_("Added"), type="success")
     return _redirect_or_remove(self)
Example #8
0
class AddCommentForm(DefaultAddForm):
    title = _("Add")
    type_name = 'Comment'
    use_ajax = True
    formid = "add-comment-form"
    ajax_options = """
        {success:
          function (rText, sText, xhr, form) {
            arche.load_flash_messages();
           }
        }
    """

    @property
    def buttons(self):
        return (self.button_add, self.button_cancel)

    def add_success(self, appstruct):
        factory = self.request.content_factories[self.type_name]
        obj = factory(**appstruct)
        name = generate_slug(self.context, obj.uid)
        self.context[name] = obj
        self.flash_messages.add(_("Added"), type="success")
        return _redirect_or_remove(self)

    def cancel(self, *args):
        return _redirect_or_remove(self)

    cancel_failure = cancel_success = cancel
def notify_subscribing_users(context, event):
    """ Send an email to any user subscribing to this folder. """
    request = get_current_request()
    comments = find_interface(context, ICommentsFolder)
    subject = _("Notification")
    comments_context = comments.__parent__
    for userid in comments.get_subscribers():
        if userid == request.authenticated_userid:
            continue
        try:
            user = request.root['users'][userid]
        except KeyError:
            continue
        if not user.email:
            continue
        try:
            comment_user = request.root['users'][context.creator[0]]
        except (KeyError, IndexError):
            comment_user = None
        values = dict(
            user=user,
            body=context.body,
            comment_context=comments_context,
            comment_user=comment_user,
            unsubscribe_url=comments.unsubscribe_url(request, userid),
        )
        body = render('arche_comments:templates/notification_email.pt', values, request=request)
        request.send_email(subject, [user.email], body)
Example #10
0
class AddCommentsFolderForm(DefaultAddForm):
    title = _("Create comments section?")
    description = _("You can disable this later on if you wish.")
    type_name = 'CommentsFolder'

    def save_success(self, appstruct):
        self.flash_messages.add(self.default_success, type="success")
        notify_user = appstruct.pop('notify', False)
        factory = self.request.content_factories[self.type_name]
        obj = factory(**appstruct)
        name = '_comments'
        if name in self.context:
            raise HTTPForbidden(_("Comments already exist here"))
        if notify_user:
            obj.add_subscribing_userid(self.request.authenticated_userid)
        self.context[name] = obj
        return HTTPFound(location=self.request.resource_url(self.context,
                                                            anchor='comments'))
Example #11
0
 def __init__(self, context, request):
     buttons = []
     if request.has_permission(EDIT_COMMENT, context):
         buttons.append(self.button_save)
     if request.has_permission(DELETE_COMMENT, context):
         buttons.append(self.button_delete)
     if not buttons:
         raise HTTPForbidden(
             _("You're not allowed to edit or delete this comment"))
     buttons.append(self.button_cancel)
     self.buttons = buttons
     super(EditCommentForm, self).__init__(context, request)
Example #12
0
 def save_success(self, appstruct):
     self.flash_messages.add(self.default_success, type="success")
     notify_user = appstruct.pop('notify', False)
     factory = self.request.content_factories[self.type_name]
     obj = factory(**appstruct)
     name = '_comments'
     if name in self.context:
         raise HTTPForbidden(_("Comments already exist here"))
     if notify_user:
         obj.add_subscribing_userid(self.request.authenticated_userid)
     self.context[name] = obj
     return HTTPFound(location=self.request.resource_url(self.context,
                                                         anchor='comments'))
Example #13
0
class Comment(Base, LocalRolesMixin):
    nav_visible = False
    listing_visible = True
    search_visible = True
    type_name = "Comment"
    type_title = _("Comment")
    body = ""
    _creator = ()
    add_permission = ADD_COMMENT

    @property
    def creator(self):
        return self._creator

    @creator.setter
    def creator(self, value):
        self._creator = tuple(value)
Example #14
0
class EditCommentForm(DefaultEditForm):
    title = _("Edit")
    type_name = 'Comment'

    def __init__(self, context, request):
        buttons = []
        if request.has_permission(EDIT_COMMENT, context):
            buttons.append(self.button_save)
        if request.has_permission(DELETE_COMMENT, context):
            buttons.append(self.button_delete)
        if not buttons:
            raise HTTPForbidden(
                _("You're not allowed to edit or delete this comment"))
        buttons.append(self.button_cancel)
        self.buttons = buttons
        super(EditCommentForm, self).__init__(context, request)

    @property
    def formid(self):
        return "edit-comment-%s" % self.context.uid

    def appstruct(self):
        appstruct = super(EditCommentForm, self).appstruct()
        # It would be nice if this was handled by colander instead :/
        appstruct['body'] = strip_tags(appstruct['body'])
        return appstruct

    def save_success(self, appstruct):
        self.flash_messages.add(_("Updated"), type='success')
        self.context.update(**appstruct)
        return redirect_parent(self.context, self.request)

    def delete_success(self, appstruct):
        self.flash_messages.add(_("Removed"), type='warning')
        redir = redirect_parent(self.context, self.request)
        parent = self.context.__parent__
        del parent[self.context.__name__]
        return redir

    def cancel(self, *args):
        return redirect_parent(self.context, self.request)

    cancel_failure = cancel_success = cancel
Example #15
0
class CommentsFolderSchema(colander.Schema):
    notify = colander.SchemaNode(
        colander.Bool(),
        title=_("Send an email notification when a comment is added?"),
    )
Example #16
0
 def delete_success(self, appstruct):
     self.flash_messages.add(_("Removed"), type='warning')
     redir = redirect_parent(self.context, self.request)
     parent = self.context.__parent__
     del parent[self.context.__name__]
     return redir
Example #17
0
 def save_success(self, appstruct):
     self.flash_messages.add(_("Updated"), type='success')
     self.context.update(**appstruct)
     return redirect_parent(self.context, self.request)