--- a/src/pyams_content/shared/common/review.py Fri Nov 10 12:04:50 2017 +0100
+++ b/src/pyams_content/shared/common/review.py Fri Nov 10 12:05:25 2017 +0100
@@ -14,220 +14,10 @@
# import standard library
-import os
-from datetime import datetime
-from uuid import uuid4
# import interfaces
-from pyams_content.interfaces import READER_ROLE
-from pyams_content.interfaces.review import IReviewManager, IReviewComment, IReviewComments, \
- REVIEW_COMMENTS_ANNOTATION_KEY, CommentAddedEvent, ICommentAddedEvent
-from pyams_content.shared.common.interfaces import IWfSharedContent, IWfSharedContentRoles
-from pyams_i18n.interfaces import II18n
-from pyams_mail.interfaces import IPrincipalMailInfo
-from pyams_security.interfaces import ISecurityManager, IProtectedObject
-from pyams_security.interfaces.notification import INotificationSettings
-from pyramid_chameleon.interfaces import IChameleonTranslate
-from pyramid_mailer.interfaces import IMailer
-from zope.annotation.interfaces import IAnnotations
-from zope.location.interfaces import ISublocations
-from zope.traversing.interfaces import ITraversable
# import packages
-from persistent import Persistent
-from pyams_mail.message import HTMLMessage
-from pyams_security.principal import MissingPrincipal
-from pyams_utils.adapter import adapter_config, ContextAdapter
-from pyams_utils.container import BTreeOrderedContainer
-from pyams_utils.registry import query_utility
-from pyams_utils.request import check_request, query_request
-from pyams_utils.url import absolute_url
-from pyramid.events import subscriber
-from pyramid.threadlocal import get_current_registry
-from pyramid_chameleon.zpt import PageTemplateFile
-from zope.container.contained import Contained
-from zope.interface import implementer
-from zope.location import locate
-from zope.schema.fieldproperty import FieldProperty
-from pyams_content import _
-
-
-@implementer(IReviewComment)
-class ReviewComment(Persistent, Contained):
- """Review comment persistent class"""
-
- owner = FieldProperty(IReviewComment['owner'])
- comment = FieldProperty(IReviewComment['comment'])
- comment_type = FieldProperty(IReviewComment['comment_type'])
- creation_date = FieldProperty(IReviewComment['creation_date'])
-
- def __init__(self, owner, comment, comment_type='comment'):
- self.owner = owner
- self.comment = comment
- self.comment_type = comment_type
- self.creation_date = datetime.utcnow()
-
-
-@implementer(IReviewComments)
-class ReviewCommentsContainer(BTreeOrderedContainer):
- """Review comments container"""
-
- reviewers = FieldProperty(IReviewComments['reviewers'])
-
- def clear(self):
- for k in self.keys()[:]:
- del self[k]
-
- def add_comment(self, comment):
- uuid = str(uuid4())
- self[uuid] = comment
- reviewers = self.reviewers or set()
- reviewers.add(comment.owner)
- self.reviewers = reviewers
- get_current_registry().notify(CommentAddedEvent(self.__parent__, comment))
-
-
-@adapter_config(context=IWfSharedContent, provides=IReviewComments)
-def SharedContentReviewCommentsFactory(context):
- """Shared content review comments factory"""
- annotations = IAnnotations(context)
- comments = annotations.get(REVIEW_COMMENTS_ANNOTATION_KEY)
- if comments is None:
- comments = annotations[REVIEW_COMMENTS_ANNOTATION_KEY] = ReviewCommentsContainer()
- locate(comments, context, '++review-comments++')
- return comments
-
-
-@adapter_config(name='review-comments', context=IWfSharedContent, provides=ITraversable)
-class SharedContentReviewCommentsNamespace(ContextAdapter):
- """++review-comments++ namespace traverser"""
-
- def traverse(self, name, furtherpath=None):
- return IReviewComments(self.context)
-
-
-@adapter_config(name='review-comments', context=IWfSharedContent, provides=ISublocations)
-class SharedContentReviewCommentsSublocations(ContextAdapter):
- """Shared content review comments sub-location adapter"""
-
- def sublocations(self):
- return IReviewComments(self.context).values()
-
-
-@adapter_config(context=IWfSharedContent, provides=IReviewManager)
-class SharedContentReviewAdapter(ContextAdapter):
- """Shared content review adapter"""
-
- review_template = PageTemplateFile(os.path.join(os.path.dirname(__file__),
- 'zmi/templates/review-notification.pt'))
-
- def ask_review(self, reviewers, comment, notify_all=True):
- """Ask for content review"""
- roles = IWfSharedContentRoles(self.context, None)
- if roles is None:
- return
- # check request
- request = check_request()
- translate = request.localizer.translate
- # initialize mailer
- security = query_utility(ISecurityManager)
- settings = INotificationSettings(security)
- sender_name = request.principal.title if request.principal is not None else settings.sender_name
- sender_address = settings.sender_email
- sender = security.get_principal(request.principal.id, info=False)
- sender_mail_info = IPrincipalMailInfo(sender, None)
- if sender_mail_info is not None:
- for sender_name, sender_address in sender_mail_info.get_addresses():
- break
- if settings.enable_notifications:
- mailer = query_utility(IMailer, name=settings.mailer)
- else:
- mailer = None
- # create message
- message_body = self.review_template(request=request,
- context=self.context,
- translate=query_utility(IChameleonTranslate),
- options={'settings': settings,
- 'comment': comment,
- 'sender': sender_name})
- # notify reviewers
- notifications = 0
- readers = roles.readers
- for reviewer in reviewers:
- if settings.enable_notifications and \
- (mailer is not None) and \
- (notify_all or (reviewer not in readers)):
- principal = security.get_principal(reviewer, info=False)
- if not isinstance(principal, MissingPrincipal):
- mail_info = IPrincipalMailInfo(principal, None)
- if mail_info is not None:
- for name, address in mail_info.get_addresses():
- message = HTMLMessage(
- subject=translate(_("[{service_name}] A content review is requested")).format(
- service_name=settings.subject_prefix),
- fromaddr='{name} <{address}>'.format(name=sender_name,
- address=sender_address),
- toaddr='{name} <{address}>'.format(name=name, address=address),
- html=message_body)
- mailer.send(message)
- notifications += 1
- readers.add(reviewer)
- roles.readers = readers
- # add comment
- review_comment = ReviewComment(owner=request.principal.id,
- comment=comment,
- comment_type='request')
- IReviewComments(self.context).add_comment(review_comment)
- # return notifications count
- return notifications
-
-
-#
-# Review comment notification
-#
-
-try:
- from pyams_notify.interfaces import INotification, INotificationHandler
- from pyams_notify.event import Notification
-except ImportError:
- pass
-else:
-
- @subscriber(ICommentAddedEvent)
- def handle_new_comment(event):
- """Handle new review comment"""
- request = query_request()
- if request is None:
- return
- content = event.object
- translate = request.localizer.translate
- notification = Notification(request=request,
- context=content,
- source=event.comment.owner,
- action='notify',
- category='content.review',
- message=translate(_("A new comment was added on content « {0} »")).format(
- II18n(content).query_attribute('title', request=request)),
- url=absolute_url(content, request, 'admin#review-comments.html'),
- comments=IReviewComments(content))
- notification.send()
-
-
- @adapter_config(name='content.review', context=INotification, provides=INotificationHandler)
- class ContentReviewNotificationHandler(ContextAdapter):
- """Content review notification handler"""
-
- def get_target(self):
- context = self.context.context
- principals = set()
- protection = IProtectedObject(context, None)
- if protection is not None:
- principals |= protection.get_principals(READER_ROLE)
- comments = self.context.user_data.get('comments')
- if comments is not None:
- principals |= comments.reviewers
- source_id = self.context.source['id']
- if source_id in principals:
- principals.remove(source_id)
- return {'principals': tuple(principals)}
+# imports for backward compatibility: module moved to pyams_content.features.review !!
+from pyams_content.features.review import ReviewComment, ReviewCommentsContainer