class IBasicData(Interface): short_name = schema.TextLine(title=_(u'Short Name'), ) title = schema.TextLine(title=_(u'Title'), ) description = schema.TextLine( title=_(u'Description'), required=False, )
def validate_response_id(self): """Validate the response id from the request. Return -1 if for example the response id does not exist. Return the response id otherwise. Side effect: an informative status message is set. """ status = IStatusMessage(self.request) response_id = self.request.form.get('response_id', None) if response_id is None: msg = _(u"No response selected.") msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') return -1 else: try: response_id = int(response_id) except ValueError: msg = _(u"Response id ${response_id} is no integer.", mapping=dict(response_id=response_id)) msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') return -1 if response_id >= len(self.folder): msg = _(u"Response id ${response_id} does not exist.", mapping=dict(response_id=response_id)) msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') return -1 else: return response_id # fallback return -1
def getManagersVocab(self): """ Get the managers available as a DisplayList. The first item is 'None', with a key of '(UNASSIGNED)'. """ tracker = self.getTracker() items = tracker.getManagers() vocab = DisplayList() vocab.add('(UNASSIGNED)', _(u'None'), 'poi_vocab_none') vocab.add('(AREAMANAGER)', _(u'Area Manager'), 'poi_vocab_area_manager') for item in items: vocab.add(item, item) return vocab
def getManagersVocab(self): """ Get the managers available as a DisplayList. The first item is 'None', with a key of '(UNASSIGNED)'. """ tracker = self.getTracker() items = tracker.getManagers() vocab = DisplayList() vocab.add("(UNASSIGNED)", _(u"None"), "poi_vocab_none") vocab.add("(AREAMANAGER)", _(u"Area Manager"), "poi_vocab_area_manager") for item in items: vocab.add(item, item) return vocab
def default(self): self.errors = {} form = self.request.form self.authorized = True if not self.getTracker(): self.authorized = False obj = self.tool.getNoFeaturePage() self.page_nofeature = obj campos = ['title','details','area','issueType', 'severity','contactEmail'] #'responsibleManager', if 'form.submited' in form.keys(): for item in campos: if not form.get(item): self.errors[item] = 'Este Campo não pode ficar em branco.' if not self.errors: obj = self.createIssue(form) url = obj.portal_url()+'/vindula_poi_issue?key='+form.get('key','') # self.request.set('ajax_load',True) # self.request.set('ajax_include_head',True) IStatusMessage(self.request).addStatusMessage(_(u"Obrigado, o seu ticket foi criado com sucesso."), "info") self.request.response.redirect(url, lock=True) return ''
def getManagersVocab(self, strict=False): """ Get the managers available as a DisplayList. The first item is 'None', with a key of '(UNASSIGNED)'. Note, we now also allow Technicians here, unless we are called with 'strict' is True. """ vocab = DisplayList() vocab.add( '(UNASSIGNED)', _( u"not_assigned", default=u'(Not assigned)')) mtool = getToolByName(self, 'portal_membership') for item in self.getManagers(): user = mtool.getMemberById(item) if user: fullname = user.getProperty('fullname', item) or item else: fullname = item vocab.add(item, fullname) if not strict: for item in self.getTechnicians(): user = mtool.getMemberById(item) if user: fullname = user.getProperty('fullname', item) or item else: fullname = item vocab.add(item, fullname) return vocab
def getManagersVocab(self, strict=False): """ Get the managers available as a DisplayList. The first item is 'None', with a key of '(UNASSIGNED)'. Note, we now also allow Technicians here, unless we are called with 'strict' is True. """ tracker = self.getTracker() vocab = DisplayList() vocab.add('(UNASSIGNED)', _(u'None')) mtool = getToolByName(self, 'portal_membership') for item in tracker.getManagers(): user = mtool.getMemberById(item) if user: fullname = user.getProperty('fullname', item) or item else: fullname = item vocab.add(item, fullname) if not strict: for item in tracker.getTechnicians(): user = mtool.getMemberById(item) if user: fullname = user.getProperty('fullname', item) or item else: fullname = item vocab.add(item, fullname) return vocab
def __call__(self): context = aq_inner(self.context) request = self.request response_id = self.validate_response_id() file = None if response_id != -1: response = self.folder[response_id] file = response.attachment if file is None: status = IStatusMessage(request) msg = _(u"Response id ${response_id} has no attachment.", mapping=dict(response_id=response_id)) msg = translate(msg, 'Poi', context=context) status.addStatusMessage(msg, type='error') if file is None: request.response.redirect(context.absolute_url()) # From now on file exists. # Code mostly taken from Archetypes/Field.py:FileField.download filename = getattr(file, 'filename', file.getId()) if filename is not None: if FILE_NORMALIZER: filename = IUserPreferredFileNameNormalizer(request).normalize( safe_unicode(filename, context.getCharset())) else: filename = safe_unicode(filename, context.getCharset()) header_value = contentDispositionHeader( disposition='attachment', filename=filename) request.response.setHeader("Content-disposition", header_value) return file.index_html(request, request.response)
def __call__(self): form = self.request.form context = aq_inner(self.context) status = IStatusMessage(self.request) authenticator = getMultiAdapter((context, context.REQUEST), name=u"authenticator") if not self.can_edit_response: msg = _(u"You are not allowed to edit responses.") msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') else: response_id = form.get('response_id', None) if response_id is None: msg = _(u"No response selected for saving.") msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') elif self.folder[response_id] is None: msg = _(u"Response does not exist anymore; perhaps it was " "removed by another user.") msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') else: response = self.folder[response_id] response_text = form.get('response', u'') response.text = response_text # Remove cached rendered response. response.rendered_text = None msg = _(u"Changes saved to response id ${response_id}.", mapping=dict(response_id=response_id)) msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='info') # Fire event. We put the context in the descriptions # so event handlers can use this fully acquisition # wrapped object to do their thing. Feels like # cheating, but it gets the job done. Arguably we # could turn the two arguments around and signal that # the issue has changed, with the response in the # event descriptions. modified(response, context) redirect_url = "{0}?_authenticator={1}".format(context.absolute_url(), authenticator.token()) self.request.response.redirect(redirect_url)
def subject(self): context = aq_inner(self.context) tracker = context.getTracker() subject = _('poi_email_new_response_subject_template', u"[${tracker_title}] #${issue_id} - Re: ${issue_title}", mapping=dict(tracker_title=su(tracker.Title()), issue_id=su(context.getId()), issue_title=su(context.Title()))) # Ensure that the subject is unicode and translate it too. subject = su(subject) subject = translate(subject, 'Poi', context=self.request) return subject
def getReleasesVocab(self): """ Get the vocabulary of available releases, including the item (UNASSIGNED) to denote that a release is not yet assigned. """ vocab = DisplayList() vocab.add('(UNASSIGNED)', _(u'None')) tracker = self.getTracker() trackerVocab = tracker.getReleasesVocab() for k in trackerVocab.keys(): vocab.add(k, trackerVocab.getValue(k), trackerVocab.getValue(k)) return vocab
def getReleasesVocab(self): """ Get the vocabulary of available releases, including the item (UNASSIGNED) to denote that a release is not yet assigned. """ vocab = DisplayList() vocab.add("(UNASSIGNED)", _(u"None")) tracker = self.getTracker() trackerVocab = tracker.getReleasesVocab() for k in trackerVocab.keys(): vocab.add(k, trackerVocab.getValue(k), trackerVocab.getValue(k)) return vocab
def __call__(self): context = aq_inner(self.context) status = IStatusMessage(self.request) if not self.can_delete_response: msg = _(u"You are not allowed to delete responses.") msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') else: response_id = self.request.form.get('response_id', None) if response_id is None: msg = _(u"No response selected for removal.") msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') else: try: response_id = int(response_id) except ValueError: msg = _( u"Response id ${response_id} is no integer so it " "cannot be removed.", mapping=dict(response_id=response_id)) msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') self.request.response.redirect(context.absolute_url()) return if response_id >= len(self.folder): msg = _( u"Response id ${response_id} does not exist so it " "cannot be removed.", mapping=dict(response_id=response_id)) msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') else: self.folder.delete(response_id) msg = _(u"Removed response id ${response_id}.", mapping=dict(response_id=response_id)) msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='info') self.request.response.redirect(context.absolute_url())
def __call__(self): context = aq_inner(self.context) status = IStatusMessage(self.request) ts = getGlobalTranslationService() if not self.can_delete_response: msg = _(u"You are not allowed to delete responses.") msg = ts.translate('Poi', msg, context=context) status.addStatusMessage(msg, type='error') else: response_id = self.request.form.get('response_id', None) if response_id is None: msg = _(u"No response selected for removal.") msg = ts.translate('Poi', msg, context=context) status.addStatusMessage(msg, type='error') else: try: response_id = int(response_id) except ValueError: msg = _(u"Response id ${response_id} is no integer so it " "cannot be removed.", mapping=dict(response_id=response_id)) msg = ts.translate('Poi', msg, context=context) status.addStatusMessage(msg, type='error') self.request.response.redirect(context.absolute_url()) return if response_id >= len(self.folder): msg = _(u"Response id ${response_id} does not exist so it " "cannot be removed.", mapping=dict(response_id=response_id)) msg = ts.translate('Poi', msg, context=context) status.addStatusMessage(msg, type='error') else: self.folder.delete(response_id) msg = _(u"Removed response id ${response_id}.", mapping=dict(response_id=response_id)) msg = ts.translate('Poi', msg, context=context) status.addStatusMessage(msg, type='info') self.request.response.redirect(context.absolute_url())
def subject(self): context = aq_inner(self.context) tracker = context.getTracker() subject = _( 'poi_email_issue_resolved_subject_template', u"[${tracker_title}] Resolved #${issue_id} - ${issue_title}", mapping=dict(tracker_title=su(tracker.Title()), issue_id=su(context.getId()), issue_title=su(context.Title()))) # Make the subject unicode and translate it too. subject = su(subject) subject = translate(subject, 'Poi', context=self.request) return subject
def subject(self): context = aq_inner(self.context) tracker = context.getTracker() subject = _( 'poi_email_issue_resolved_subject_template', u"[${tracker_title}] Resolved #${issue_id} - ${issue_title}", mapping=dict( tracker_title=su(tracker.getExternalTitle()), issue_id=su(context.getId()), issue_title=su(context.Title()))) # Make the subject unicode and translate it too. subject = su(subject) subject = translate(subject, 'Poi', context=self.request) return subject
def subject(self): context = aq_inner(self.context) tracker = context.getTracker() subject = _( 'poi_email_new_response_subject_template', u"[${tracker_title}] #${issue_id} - Re: ${issue_title}", mapping=dict( tracker_title=su(tracker.Title()), issue_id=su(context.getId()), issue_title=su(context.Title()))) # Ensure that the subject is unicode and translate it too. subject = su(subject) subject = translate(subject, 'Poi', context=self.request) return subject
def getManagersVocab(self, strict=False): """ Get the managers available as a DisplayList. The first item is 'None', with a key of '(UNASSIGNED)'. Note, we now also allow Technicians here, unless we are called with 'strict' is True. """ tracker = self.getTracker() vocab = DisplayList() vocab.add("(UNASSIGNED)", _(u"None")) for item in tracker.getManagers(): vocab.add(item, item) if not strict: for item in tracker.getTechnicians(): vocab.add(item, item) return vocab
def sendResolvedMail(self, state_change, **kw): """Send an email to the original submitter that the issue was marked as resolved, inviting him/her to confirm it. """ issue = state_change.object tracker = issue.aq_parent if not tracker.getSendNotificationEmailsTo(): return issueEmail = issue.getContactEmail() if not issueEmail: return portal_url = getToolByName(self, 'portal_url') portal = portal_url.getPortalObject() plone_utils = getToolByName(portal, 'plone_utils') charset = plone_utils.getSiteEncoding() def su(value): # We are going to use the same encoding everywhere, so we will # make that easy. return safe_unicode(value, encoding=charset) portal_membership = getToolByName(portal, 'portal_membership') member = portal_membership.getAuthenticatedMember() memberInfo = portal_membership.getMemberInfo(member.getUserName()) stateChanger = member.getUserName() if memberInfo: stateChanger = memberInfo['fullname'] or stateChanger fromName = portal.getProperty('email_from_name', None) mailText = _( 'poi_email_issue_resolved_template', u"""The issue **${issue_title}** in the **${tracker_title}** tracker has been marked as resolved by **${response_author}**. Please visit the issue and either confirm that it has been satisfactorily resolved or re-open it. Response Information -------------------- Issue ${issue_title} (${issue_url}) * This is an automated email, please do not reply - ${from_name}""", mapping=dict( issue_title = su(issue.title_or_id()), tracker_title = su(tracker.title_or_id()), response_author = su(stateChanger), issue_url = su(issue.absolute_url()), from_name = su(fromName))) subject = _( 'poi_email_issue_resolved_subject_template', u"[${tracker_title}] Resolved #${issue_id} - ${issue_title}", mapping=dict( tracker_title = su(tracker.getExternalTitle()), issue_id = su(issue.getId()), issue_title = su(issue.Title()))) tracker.sendNotificationEmail([issueEmail], subject, mailText)
from Products.Poi import PoiMessageFactory as _ from Products.Poi import permissions from Products.Poi.config import PROJECTNAME from Products.Poi.config import ISSUE_RECOGNITION_PATTERNS from Products.Poi.config import REVISION_RECOGNITION_PATTERNS from Products.Poi.interfaces import ITracker from Products.Poi.utils import linkBugs from Products.Poi.utils import linkSvn schema = atapi.Schema(( atapi.StringField( name='title', widget=atapi.StringWidget( label=_(u'Poi_label_tracker_title', default=u"Tracker name"), description=_( u'Poi_help_tracker_title', default=u"Enter a descriptive name for this tracker"), ), required=True, accessor="Title", searchable=True ), atapi.TextField( name='description', widget=atapi.TextAreaWidget( label=_(u'Poi_label_tracker_description', default=u"Tracker description"), description=_(
def sendResolvedMail(self, state_change, **kw): """Send an email to the original submitter that the issue was marked as resolved, inviting him/her to confirm it. """ issue = state_change.object tracker = issue.aq_parent if not tracker.getSendNotificationEmailsTo(): return issueEmail = issue.getContactEmail() if not issueEmail: return portal_url = getToolByName(self, 'portal_url') portal = portal_url.getPortalObject() plone_utils = getToolByName(portal, 'plone_utils') charset = plone_utils.getSiteEncoding() def su(value): # We are going to use the same encoding everywhere, so we will # make that easy. return safe_unicode(value, encoding=charset) portal_membership = getToolByName(portal, 'portal_membership') member = portal_membership.getAuthenticatedMember() memberInfo = portal_membership.getMemberInfo(member.getUserName()) stateChanger = member.getUserName() if memberInfo: stateChanger = memberInfo['fullname'] or stateChanger fromName = portal.getProperty('email_from_name', None) mailText = _('poi_email_issue_resolved_template', u"""The issue **${issue_title}** in the **${tracker_title}** tracker has been marked as resolved by **${response_author}**. Please visit the issue and either confirm that it has been satisfactorily resolved or re-open it. Response Information -------------------- Issue ${issue_title} (${issue_url}) * This is an automated email, please do not reply - ${from_name}""", mapping=dict(issue_title=su(issue.title_or_id()), tracker_title=su(tracker.title_or_id()), response_author=su(stateChanger), issue_url=su(issue.absolute_url()), from_name=su(fromName))) subject = _('poi_email_issue_resolved_subject_template', u"[${tracker_title}] Resolved #${issue_id} - ${issue_title}", mapping=dict(tracker_title=su(tracker.getExternalTitle()), issue_id=su(issue.getId()), issue_title=su(issue.Title()))) tracker.sendNotificationEmail([issueEmail], subject, mailText)
def __call__(self): form = self.request.form context = aq_inner(self.context) if not self.memship.checkPermission('Poi: Add Response', context): raise Unauthorized response_text = form.get('response', u'') new_response = Response(response_text) new_response.mimetype = self.mimetype new_response.type = self.determine_response_type(new_response) issue_has_changed = False transition = form.get('transition', u'') if transition and transition in self.available_transitions: wftool = getToolByName(context, 'portal_workflow') before = wftool.getInfoFor(context, 'review_state') before = wftool.getTitleForStateOnType(before, 'PoiIssue') wftool.doActionFor(context, transition) after = wftool.getInfoFor(context, 'review_state') after = wftool.getTitleForStateOnType(after, 'PoiIssue') new_response.add_change('review_state', _(u'Issue state'), before, after) issue_has_changed = True options = [ ('severity', _(u'Severity'), 'available_severities'), ('responsibleManager', _(u'Responsible manager'), 'available_managers'), ] # Changes that need to be applied to the issue (apart from # workflow changes that need to be handled separately). changes = {} for option, title, vocab in options: new = form.get(option, u'') if new and new in self.__getattribute__(vocab): current = self.__getattribute__(option) if current != new: changes[option] = new new_response.add_change(option, title, current, new) issue_has_changed = True #('targetRelease', 'Target release', 'available_releases'), new = form.get('targetRelease', u'') if new and new in self.available_releases: current = self.targetRelease if current != new: # from value (uid) to key (id) new_label = self.available_releases.getValue(new) current_label = self.available_releases.getValue(current) changes['targetRelease'] = new new_response.add_change('targetRelease', _(u'Target release'), current_label, new_label) issue_has_changed = True attachment = form.get('attachment') if attachment: # File(id, title, file) data = File(attachment.filename, attachment.filename, attachment) new_response.attachment = data issue_has_changed = True if len(response_text) == 0 and not issue_has_changed: status = IStatusMessage(self.request) msg = _(u"No response text added and no issue changes made.") msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') else: # Apply changes to issue context.update(**changes) # Add response self.folder.add(new_response) self.request.response.redirect(context.absolute_url())
class IIssue(model.Schema): """Marker interface for Poi issue""" dexteritytextindexer.searchable('title') title = schema.TextLine( title=_(u'Poi_label_issue_title', default=u"Title"), description=_(u'Poi_help_issue_title', default=u"Enter a short, descriptive title for " u"the issue. A good title will make it easier " u"for project managers to identify and respond " u"to the issue.")) release = schema.Choice( title=_(u'Poi_label_issue_release', default=u'Release'), description=_(u'Poi_help_issue_release', default=u"Select the version the issue was found in."), required=False, source=possibleTargetReleases) dexteritytextindexer.searchable('details') details = RichText(title=_(u'Poi_label_issue_details', default=u'Details'), description=_( u'Poi_help_issue_details', default=u"Please provide further details.")) dexteritytextindexer.searchable('steps') steps = RichText( title=_(u'Poi_label_issue_steps', default=u'Steps To Reproduce'), description=_(u'Poi_help_issue_steps', default=u"If applicable, please provide the steps to " u"reproduce the error or identify the issue, one per " u"line."), required=False, ) area = schema.Choice( title=_(u'Poi_label_issue_area', default=u'Area'), description=_(u'Poi_help_issue_area', default=u"Select the area this issue is relevant to."), source=possibleAreas) issue_type = schema.Choice(title=_(u'Poi_label_issue_type', default=u'Issue Type'), description=_( u'Poi_help_issue_type', default=u"Select the type of issue."), source=possibleIssueTypes) read_permission(severity='Poi.ModifyIssueSeverity') write_permission(severity='Poi.ModifyIssueSeverity') severity = schema.Choice( title=_(u'Poi_label_issue_severity', default=u'Severity'), description=_(u'Poi_help_issue_severity', default=u"Select the severity of this issue."), defaultFactory=default_severity, source=possibleSeverities) read_permission(target_release='Poi.ModifyIssueTargetRelease') write_permission(target_release='Poi.ModifyIssueTargetRelease') target_release = schema.Choice( title=_(u'Poi_label_issue_target_release', default=u'Target Release'), description=_(u'Poi_help_issue_target_release', default=u"Release this issue is targetted to be fixed " u"in."), source=possibleTargetReleases, required=False, ) read_permission(assignee='Poi.ModifyIssueAssignment') write_permission(assignee='Poi.ModifyIssueAssignment') assignee = schema.Choice( title=_(u'Poi_label_issue_assignee', default=u'Assignee'), description=_(u'Poi_help_issue_assignee', default=u"Select which person, if any, is assigned to " u"this issue."), source=possibleAssignees, required=False, ) contact_email = email.Email( title=_(u'Poi_label_issue_contact_email', default=u'Contact Email'), description=_(u'Poi_help_issue_contact_email', default=u"Please provide an email address where you can " u"be contacted for further information or when a " u"resolution is available. Note that your email " u"address will not be displayed to others."), required=False, ) read_permission(watchers='Poi.ModifyIssueWatchers') write_permission(watchers='Poi.ModifyIssueWatchers') widget('watchers', AjaxSelectFieldWidget, vocabulary='plone.app.vocabularies.Users') watchers = schema.List( title=_(u'Poi_label_issue_watchers', default=u'Watchers'), description=_(u'Poi_help_issue_watchers', default=u"Enter the user ids of members who are watching" u" this issue, one per line. E-mail addresses are " u"allowed too. These persons will " u"receive an email when a response is added to the " u"issue. Members can also add themselves as " u"watchers."), value_type=schema.TextLine(), required=False, defaultFactory=default_watchers, ) write_permission(subject='Poi.ModifyIssueTags') read_permission(subject='Poi.ModifyIssueTags') widget('subject', AjaxSelectFieldWidget, vocabulary='plone.app.vocabularies.Keywords', pattern_options={'allowNewItems': 'true'}) subject = schema.Tuple( title=_(u'Poi_label_issue_subject', default=u'Subject'), description=_(u'Poi_help_issue_subject', default=u"Tags can be used to add arbitrary " u"categorisation to issues. The list below shows " u"existing tags which you can select, or you can add " u"new ones."), value_type=schema.TextLine(), required=False, missing_value=[], ) read_permission(related_issue='Poi.ModifyRelatedIssues') write_permission(related_issue='Poi.ModifyRelatedIssues') widget( 'related_issue', RelatedItemsFieldWidget, pattern_options={ 'resultTemplate': '' + '<div class="pattern-relateditems-result<% if (oneLevelUp) { %> one-level-up<% } %>">' + ' <a class="pattern-relateditems-result-select<% if (selectable) { %> selectable<% } else if (browsing && is_folderish) { %> pattern-relateditems-result-browse<% } %><% if (oneLevelUp) { %> one-level-up<% } %>" data-path="<%- path %>">' + ' <% if (getURL && (getIcon || portal_type === "Image")) { %><img src="<%- getURL %>/@@images/image/icon "><br><% } %>' + ' <span class="pattern-relateditems-result-title" title="<%- portal_type %>"><%- Title %></span>' + ' <span class="pattern-relateditems-result-path"><%- path %></span>' + ' </a>' + '</div>' }) related_issue = RelationList(title=_(u'Poi_label_issue_related', default=u'Related Issue(s)'), description=_( u'Poi_help_issue_related', default=u'Link related issues.'), value_type=RelationChoice( title=u"Related", source=tracker_issues, ), required=False) empty = schema.Bool(title=_(u'Poi_label_issue_empty', default=u'Leave this field empty'), required=False, constraint=checkEmpty)
def __call__(self): form = self.request.form context = aq_inner(self.context) request = context.REQUEST authenticator = getMultiAdapter((context, request), name=u"authenticator") # CSRF should be disabled during tests if (not IDisableCSRFProtection.providedBy(request) and not authenticator.verify()): raise Unauthorized if not self.memship.checkPermission('Poi: Add Response', context): raise Unauthorized response_text = form.get('response', u'') new_response = Response(response_text) new_response.mimetype = self.mimetype new_response.type = self.determine_response_type(new_response) issue_has_changed = False transition = form.get('transition', u'') if transition and transition in self.available_transitions: wftool = getToolByName(context, 'portal_workflow') before = wftool.getInfoFor(context, 'review_state') before = wftool.getTitleForStateOnType(before, 'PoiIssue') wftool.doActionFor(context, transition) after = wftool.getInfoFor(context, 'review_state') after = wftool.getTitleForStateOnType(after, 'PoiIssue') new_response.add_change('review_state', _(u'Issue state'), before, after) issue_has_changed = True options = [ ('severity', _(u'Severity'), 'available_severities'), ('current_assignee', _(u'Assignee'), 'available_assignees'), ('targetRelease', _(u'Target release'), 'available_releases'), ] for option, title, vocab in options: new = form.get(option, u'') if new and new in self.__getattribute__(vocab): current = self.__getattribute__(option) if current == new: continue new_response.add_change(option, title, current, new) issue_has_changed = True if option == 'severity': context.severity = new elif option == 'targetRelease': context.target_release = new elif option == 'current_assignee': context.assignee = new if len(response_text) == 0 and not issue_has_changed: status = IStatusMessage(self.request) msg = _(u"No response text added and no issue changes made.") msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') else: # Add response self.folder.add(new_response) redirect_url = "{0}?_authenticator={1}".format(context.absolute_url(), authenticator.token()) self.request.response.redirect(redirect_url)
wrapper = textwrap.TextWrapper(initial_indent=' ', subsequent_indent=' ') logger = logging.getLogger('Poi') PLAIN_MIMETYPES = ( 'text/x-web-intelligent', 'text/plain', ) schema = Schema(( StringField( name='id', widget=StringWidget( visible={'view': 'invisible', 'edit': 'visible'}, modes=('view', ), label=_(u'Poi_label_issue_id', default=u'Id'), ), mode="r" ), StringField( name='title', widget=StringWidget( label=_(u"Poi_label_issue_title", default=u"Title"), description=_( u'Poi_help_issue_title', default=( u"Enter a short, descriptive title for the issue. " u"A good title will make it easier for project " u"managers to identify and respond to the issue.")),
def sendNotificationMail(self): """ When this issue is created, send a notification email to all tracker managers, unless emailing is turned off. """ portal_url = getToolByName(self, 'portal_url') portal = portal_url.getPortalObject() portal_membership = getToolByName(portal, 'portal_membership') plone_utils = getToolByName(portal, 'plone_utils') charset = plone_utils.getSiteEncoding() # We are going to use the same encoding everywhere, so we will # make that easy. def su(value): return safe_unicode(value, encoding=charset) fromName = portal.getProperty('email_from_name', None) if isinstance(fromName, unicode): fromName = fromName.encode(charset, 'replace') tracker = self.getTracker() issueCreator = self.Creator() issueCreatorInfo = portal_membership.getMemberInfo(issueCreator) issueAuthor = issueCreator if issueCreatorInfo: issueAuthor = issueCreatorInfo['fullname'] or issueCreator issueText = self.getDetails(mimetype="text/x-web-intelligent") paras = issueText.splitlines() issueDetails = '\n\n'.join([wrapper.fill(p) for p in paras]) addresses = tracker.getNotificationEmailAddresses() mailText = _( 'poi_email_new_issue_template', u"""A new issue has been submitted to the **${tracker_title}** tracker by **${issue_author}** and awaits confirmation. Issue Information ----------------- Issue ${issue_title} (${issue_url}) **Issue Details**:: ${issue_details} * This is an automated email, please do not reply - ${from_name}""", mapping=dict( issue_title = su(self.title_or_id()), tracker_title = su(tracker.title_or_id()), issue_author = su(issueAuthor), issue_details = su(issueDetails), issue_url = su(self.absolute_url()), from_name = su(fromName))) subject = _( 'poi_email_new_issue_subject_template', u"[${tracker_title}] #${issue_id} - New issue: ${issue_title}", mapping=dict( tracker_title = su(tracker.getExternalTitle()), issue_id = su(self.getId()), issue_title = su(self.Title()))) tracker.sendNotificationEmail(addresses, subject, mailText)
from Products.Poi.config import PROJECTNAME from Products.Poi.interfaces import IIssue from Products.Poi.interfaces import ITracker wrapper = textwrap.TextWrapper(initial_indent=' ', subsequent_indent=' ') logger = logging.getLogger('Poi') schema = Schema(( StringField(name='id', widget=StringWidget( visible={ 'view': 'invisible', 'edit': 'visible' }, modes=('view', ), label=_(u'Poi_label_issue_id', default=u'Id'), ), mode="r"), StringField( name='title', widget=StringWidget( label=_(u"Poi_label_issue_title", default=u"Title"), description=_( u'Poi_help_issue_title', default=(u"Enter a short, descriptive title for the issue. " u"A good title will make it easier for project " u"managers to identify and respond to the issue.")), ), required=True, accessor="Title", searchable=True),
def sendResponseNotificationMail(issue, response): """When a response is created, send a notification email to all tracker managers, unless emailing is turned off. """ tracker = aq_parent(issue) addresses = tracker.getNotificationEmailAddresses(issue) if not addresses: # This also catches the case where there may be addresses but # the tracker is not configured to send emails. return portal_url = getToolByName(issue, 'portal_url') portal = portal_url.getPortalObject() portal_membership = getToolByName(portal, 'portal_membership') plone_utils = getToolByName(portal, 'plone_utils') ts = getGlobalTranslationService() charset = plone_utils.getSiteEncoding() # We are going to use the same encoding everywhere, so we will # make that easy. def su(value): return safe_unicode(value, encoding=charset) fromName = su(portal.getProperty('email_from_name', '')) creator = response.creator creatorInfo = portal_membership.getMemberInfo(creator) if creatorInfo and creatorInfo['fullname']: responseAuthor = creatorInfo['fullname'] else: responseAuthor = creator responseAuthor = su(responseAuthor) responseText = su(response.text) paras = responseText.splitlines() # Indent the response details so they are correctly interpreted as # a literal block after the double colon behind the 'Response # Details' header. wrapper = textwrap.TextWrapper(initial_indent=u' ', subsequent_indent=u' ') responseDetails = u'\n\n'.join([wrapper.fill(p) for p in paras]) if responseDetails: header = _( 'poi_heading_response_details', u"Response Details") header = ts.translate('Poi', header, context=issue) responseDetails = u"**%s**::\n\n\n%s" % (header, responseDetails) changes = u'' for change in response.changes: before = su(change.get('before')) after = su(change.get('after')) # Some changes are workflow changes, which can be translated. # Note that workflow changes are in the plone domain. before = ts.translate('plone', before, context=issue) after = ts.translate('plone', after, context=issue) changes += u"%s -> %s\n" % (before, after) if response.attachment: extra = _( 'poi_attachment_added', u"An attachment has been added with id ${attachment_id}", mapping=dict( attachment_id=response.attachment.getId())) extra = ts.translate(extra, 'Poi', context=issue) changes += extra + "\n" mailText = _( 'poi_email_new_response_template', u"""A new response has been given to the issue **${issue_title}** in the tracker **${tracker_title}** by **${response_author}**. Response Information -------------------- Issue ${issue_title} (${issue_url}) ${changes} ${response_details} * This is an automated email, please do not reply - ${from_name}""", mapping=dict( issue_title = su(issue.title_or_id()), tracker_title = su(tracker.title_or_id()), response_author = responseAuthor, response_details = responseDetails, issue_url = su(issue.absolute_url()), changes = changes, from_name = fromName)) subject = _( 'poi_email_new_response_subject_template', u"[${tracker_title}] #${issue_id} - Re: ${issue_title}", mapping=dict( tracker_title = su(tracker.getExternalTitle()), issue_id = su(issue.getId()), issue_title = su(issue.Title()))) tracker.sendNotificationEmail(addresses, subject, mailText)
def sendNotificationMail(self): """ When this issue is created, send a notification email to all tracker managers, unless emailing is turned off. """ portal_url = getToolByName(self, "portal_url") portal = portal_url.getPortalObject() portal_membership = getToolByName(portal, "portal_membership") plone_utils = getToolByName(portal, "plone_utils") charset = plone_utils.getSiteEncoding() # We are going to use the same encoding everywhere, so we will # make that easy. def su(value): return safe_unicode(value, encoding=charset) fromName = portal.getProperty("email_from_name", None) if isinstance(fromName, unicode): fromName = fromName.encode(charset, "replace") tracker = self.getTracker() issueCreator = self.Creator() issueCreatorInfo = portal_membership.getMemberInfo(issueCreator) issueAuthor = issueCreator if issueCreatorInfo: issueAuthor = issueCreatorInfo["fullname"] or issueCreator issueText = self.getDetails(mimetype="text/x-web-intelligent") paras = issueText.splitlines() issueDetails = "\n\n".join([wrapper.fill(p) for p in paras]) addresses = tracker.getNotificationEmailAddresses() mailText = _( "poi_email_new_issue_template", u"""A new issue has been submitted to the **${tracker_title}** tracker by **${issue_author}** and awaits confirmation. Issue Information ----------------- Issue ${issue_title} (${issue_url}) **Issue Details**:: ${issue_details} * This is an automated email, please do not reply - ${from_name}""", mapping=dict( issue_title=su(self.title_or_id()), tracker_title=su(tracker.title_or_id()), issue_author=su(issueAuthor), issue_details=su(issueDetails), issue_url=su(self.absolute_url()), from_name=su(fromName), ), ) subject = _( "poi_email_new_issue_subject_template", u"[${tracker_title}] #${issue_id} - New issue: ${issue_title}", mapping=dict( tracker_title=su(tracker.getExternalTitle()), issue_id=su(self.getId()), issue_title=su(self.Title()) ), ) tracker.sendNotificationEmail(addresses, subject, mailText)
def __call__(self): form = self.request.form context = aq_inner(self.context) request = context.REQUEST authenticator = getMultiAdapter((context, request), name=u"authenticator") # CSRF should be disabled during tests if (not IDisableCSRFProtection.providedBy(request) and not authenticator.verify()): raise Unauthorized if not self.memship.checkPermission('Poi: Add Response', context): raise Unauthorized response_text = form.get('response', u'') new_response = Response(response_text) new_response.mimetype = self.mimetype new_response.type = self.determine_response_type(new_response) issue_has_changed = False transition = form.get('transition', u'') if transition and transition in self.available_transitions: wftool = getToolByName(context, 'portal_workflow') before = wftool.getInfoFor(context, 'review_state') before = wftool.getTitleForStateOnType(before, 'PoiIssue') wftool.doActionFor(context, transition) after = wftool.getInfoFor(context, 'review_state') after = wftool.getTitleForStateOnType(after, 'PoiIssue') new_response.add_change('review_state', _(u'Issue state'), before, after) issue_has_changed = True options = [ ('severity', _(u'Severity'), 'available_severities'), ('current_assignee', _(u'Assignee'), 'available_assignees'), ('targetRelease', _(u'Target release'), 'available_releases'), ] for option, title, vocab in options: new = form.get(option, u'') if new and new in self.__getattribute__(vocab): current = self.__getattribute__(option) if current == new: continue new_response.add_change(option, title, current, new) issue_has_changed = True if option == 'severity': context.severity = new elif option == 'targetRelease': context.target_release = new elif option == 'current_assignee': context.assignee = new if len(response_text) == 0 and not issue_has_changed: status = IStatusMessage(self.request) msg = _(u"No response text added and no issue changes made.") msg = translate(msg, 'Poi', context=self.request) status.addStatusMessage(msg, type='error') else: # Add response self.folder.add(new_response) context.reindexObject() redirect_url = "{0}?_authenticator={1}".format(context.absolute_url(), authenticator.token()) self.request.response.redirect(redirect_url)
from Products.Poi.utils import link_bugs from Products.Poi.utils import link_repo from plone.app.textfield import RichText from plone.app.z3cform.widget import AjaxSelectFieldWidget from plone.autoform.directives import widget from plone.autoform.directives import write_permission, read_permission from plone.dexterity.content import Container from plone.protect.utils import addTokenToUrl from plone.supermodel import model from plone.z3cform.textlines import TextLinesFieldWidget from collective.z3cform.datagridfield import DataGridFieldFactory, DictRow from z3c.form import validator DEFAULT_SEVERITIES = [ _(u'Critical'), _(u'Important'), _(u'Medium'), _(u'Low') ] def possibleAreas(context): """ Get the available areas as a Vocabulary. """ if ITracker.providedBy(context): tracker = context elif hasattr(context, 'getTracker'): tracker = context.getTracker() else:
class ITracker(model.Schema): title = schema.TextLine( title=_(u'title', default=u'Title'), description=_(u'Poi_help_tracker_title', default=u"Enter a descriptive name for this tracker"), ) description = schema.Text( title=_(u'description', default=u'Description'), description=_(u'Poi_help_tracker_description', default=u"Describe the purpose of this tracker"), required=False, ) help_text = RichText( title=_(u'help_text', default=u'Help Text'), description=_( u'Poi_help_helpText', default=(u"Enter any introductory help text you'd like to " u"display on the tracker front page.")), required=False, ) widget(available_areas=DataGridFieldFactory) available_areas = schema.List( title=_(u'Poi_label_availableAreas', default=u"Areas"), description=_( u'Poi_help_availableAreas', default="Enter the issue topics/areas for this tracker."), default=[ { 'short_name': 'ui', 'title': 'User interface', 'description': 'User interface issues' }, { 'short_name': 'functionality', 'title': 'Functionality', 'description': 'Issues with the basic functionality' }, { 'short_name': 'process', 'title': 'Process', 'description': 'Issues relating to the development process itself' }, ], value_type=DictRow(title=_(u'Area'), schema=IBasicData), ) widget(available_issue_types=DataGridFieldFactory) available_issue_types = schema.List( title=_(u'Poi_label_availableIssueTypes', default=u"Issue types"), description=_(u'Poi_help_availableIssueTypes', default=u"Enter the issue types for this tracker."), default=[ { 'short_name': 'bug', 'title': 'Bug', 'description': 'Functionality bugs in the software' }, { 'short_name': 'feature', 'title': 'Feature', 'description': 'Suggested features' }, { 'short_name': 'patch', 'title': 'Patch', 'description': 'Patches to the software' }, ], value_type=DictRow(title=_(u'Issue Type'), schema=IBasicData), ) widget(available_severities=TextLinesFieldWidget) available_severities = schema.List( title=_(u'Poi_label_availableSeverities', default=u"Available severities"), default=DEFAULT_SEVERITIES, description=_(u'Poi_help_availableSeverities', default=(u"Enter the different type of issue severities " u"that should be available, one per line.")), value_type=schema.TextLine(), ) default_severity = schema.Choice( title=_( u'Poi_label_defaultSeverity', default=u"Default severity", ), default=_(u'Medium'), description=_(u'Poi_help_defaultSeverity', default=u"Select the default severity for new issues."), source=possibleSeverities, ) widget(available_releases=TextLinesFieldWidget) available_releases = schema.List( title=_(u'Poi_label_availableReleases', default=u'Available releases'), description=_( u'Poi_help_availableReleases', default=(u"Enter the releases which issues can be assigned to, " u"one per line. If no releases are entered, issues " u"will not be organized by release.")), value_type=schema.TextLine(), required=False, ) widget('assignees', AjaxSelectFieldWidget) assignees = schema.List( title=_(u'Poi_label_assignees', default=u'Assignees'), description=_(u"Enter users who will be responsible for solving " u"the issues. Users also need to be added as " u"Watchers to receive notifications."), value_type=schema.Choice(source='plone.app.vocabularies.Users'), ) read_permission(watchers='Poi.ModifyIssueWatchers') write_permission(watchers='Poi.ModifyIssueWatchers') widget('watchers', AjaxSelectFieldWidget, vocabulary='plone.app.vocabularies.Users') watchers = schema.List( title=_(u'Poi_label_tracker_watchers', default=u'Watchers'), description=_( u'Poi_help_tracker_watchers', default=(u"Enter the user ids of members who are watching " u"this tracker, one per line. E-mail addresses are " u"allowed too. These persons will receive " u"an email when an issue or response is added to the " u"tracker. Members can also add themselves as " u"watchers.")), value_type=schema.TextLine(), required=False, ) notification_emails = schema.Bool( title=_(u'Poi_label_sendNotificationEmails', default=u"Send notification emails"), description=_( u'Poi_help_sendNotificationEmails', default=(u"If selected, all tracker assignees above will " u"receive an email for new issues and all issue " u"responses. Issue watchers will receive an email " u"for all issue responses. Issue submitters will " u"receive an email when the issue has been resolved.")), ) mailing_list = schema.TextLine( title=_(u'Poi_label_mailingList', default=u"Mailing list"), description=_( u'Poi_help_mailingList', default=(u"If given, and if 'Send notification emails' is " u"selected, an email will be sent to this address " u"each time a new issue or response is posted.")), required=False, constraint=is_email, ) repo_url = schema.TextLine( title=_(u'Poi_label_svnurl', default=u"URL to Repository"), description=_( u'Poi_help_svnurl', default=( u"Please enter the URL to the related repository, " u"e.g.: " u"https://github.com/collective/Products.Poi/commit/%(rev)s " u"for Products.Poi.")), required=False, )
# No multilingual support from Products.Archetypes import atapi from Products.Poi import PoiMessageFactory as _ from Products.Poi import permissions from Products.Poi.config import PROJECTNAME from Products.Poi.interfaces import ITracker from Products.Poi.utils import linkBugs from Products.Poi.utils import linkSvn schema = atapi.Schema(( atapi.StringField( name='title', widget=atapi.StringWidget( label=_(u'Poi_label_tracker_title', default=u"Tracker name"), description=_( u'Poi_help_tracker_title', default=u"Enter a descriptive name for this tracker"), ), required=True, accessor="Title", searchable=True ), atapi.TextField( name='description', widget=atapi.TextAreaWidget( label=_(u'Poi_label_tracker_description', default=u"Tracker description"), description=_(
from Products.Poi.utils import is_email from Products.Poi.utils import link_bugs from Products.Poi.utils import link_repo from plone.app.textfield import RichText from plone.app.z3cform.widget import AjaxSelectFieldWidget from plone.autoform.directives import widget from plone.autoform.directives import write_permission, read_permission from plone.dexterity.content import Container from plone.memoize import ram from plone.protect.utils import addTokenToUrl from plone.supermodel import model from plone.z3cform.textlines import TextLinesFieldWidget from collective.z3cform.datagridfield import DataGridFieldFactory, DictRow from z3c.form import validator DEFAULT_SEVERITIES = [_(u'Critical'), _(u'Important'), _(u'Medium'), _(u'Low')] def possibleAreas(context): """ Get the available areas as a Vocabulary. """ if ITracker.providedBy(context): tracker = context elif hasattr(context, 'getTracker'): tracker = context.getTracker() else: return SimpleVocabulary.fromValues([]) terms = [ SimpleTerm(value=tt.get('short_name'), title=tt.get('title')) for tt in tracker.available_areas if tt.get('short_name') is not None
except ImportError: # No multilingual support from Products.Archetypes import atapi from Products.Poi import PoiMessageFactory as _ from Products.Poi import permissions from Products.Poi.config import PROJECTNAME from Products.Poi.interfaces import ITracker from Products.Poi.utils import linkBugs from Products.Poi.utils import linkSvn schema = atapi.Schema(( atapi.StringField( name='title', widget=atapi.StringWidget( label=_(u'Poi_label_tracker_title', default=u"Tracker name"), description=_( u'Poi_help_tracker_title', default=u"Enter a descriptive name for this tracker"), ), required=True, accessor="Title", searchable=True), atapi.TextField( name='description', widget=atapi.TextAreaWidget( label=_(u'Poi_label_tracker_description', default=u"Tracker description"), description=_(u'Poi_help_tracker_description', default=u"Describe the purpose of this tracker"), ),