def get_tabs(self): return ( {"id": _("global-my_tickets"), "class": ""}, {"id": _("global-my_issued_tickets"), "class": ""}, {"id": _("global-all_tickets"), "class": ""}, {"id": _("global-ticketboxes"), "class": ""}, )
def yes_no(self): """return displaylist with two static rows contents: yes and no """ return DisplayList(( ("1", _(u"yes")), ("0", _(u"no")), ))
def move_document_to_reference(obj, event): """Create own File and add it to References""" file_ = obj.getAttachment() if file_.data != '': new_id = queryUtility(IIDNormalizer).normalize( file_.filename.decode('utf-8')) if obj.get(new_id, None): IStatusMessage(obj.REQUEST).addStatusMessage( _(u"text_file_exists_error"), type='error') obj.setAttachment('DELETE_FILE') return new_file_id = obj.invokeFactory( type_name="TicketAttachment", id=new_id, title=file_.filename, file=file_) new_file = obj.get(new_file_id, None) if new_file is None: return uid = new_file.UID() references = obj.getRawAttachments() if not isinstance(references, list): references = [references] references.append(uid) obj.setAttachments(references) obj.setAttachment('DELETE_FILE') obj.reindexObject()
def _get_filter_configuration(self): filters = {} filters['getResponsibleManager'] = { 'label': _(u'label_heading_by_responsible', default=u'By responsible'), 'options': sorted( self.context.assignable_users(), key=lambda item: item[1].lower().decode('utf-8'))} filters['getState'] = { 'label': _(u'label_heading_by_states'), 'options': self.context.getAvailableStates()} available_releases = self.context.getAvailableReleases() filters['getReleases'] = { 'label': _(u'label_heading_by_release'), 'options': available_releases} filters['getWatchedRelease'] = { 'label': _(u'label_heading_by_watched_release'), 'options': available_releases} filters['getPriority'] = { 'label': _(u'label_heading_by_severities'), 'options': self.context.getAvailablePriorities()} filters['getArea'] = { 'label': _(u'label_heading_by_area'), 'options': self.context.getAvailableAreas()} filters['getVariety'] = { 'label': _(u'label_heading_by_varieties'), 'options': self.context.getAvailableVarieties()} return filters
def __call__(self): form = self.request.form context = aq_inner(self.context) status = IStatusMessage(self.request) response_id = form.get('response_id', None) if response_id is None: msg = _(u"msg_no_response_selected", default=u"No response selected for saving.") msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') elif self.folder[response_id] is None: msg = _(u"msg_doesnt_exists", default=u"Response does not exist anymore; \ perhaps it was removed by another user.") msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') response = self.folder[response_id] member = context.portal_membership.getAuthenticatedMember() if not (self.can_edit_response or response.creator == member.getId()): msg = _(u"msg_not_restricted", default=u"You are not allowed to edit responses.") msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') else: response_text = form.get('response', u'') response.text = response_text # Remove cached rendered response. response.rendered_text = None msg = _(u"msg_changes_saved", default="Changes Saved", mapping=dict(response_id=response_id)) msg = self.context.translate(msg) 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) self.request.response.redirect(context.absolute_url())
def __call__(self): context = aq_inner(self.context) status = IStatusMessage(self.request) if not self.can_delete_response: msg = _(u"msg_restricted_delete", default=u"You are not allowed to delete Responses") msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') else: response_id = self.request.form.get('response_id', None) if response_id is None: msg = _(u"msg_no_response_delete", default=u"No response selected for removal.") msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') else: try: response_id = int(response_id) except ValueError: msg = _( u"msg_nointeger", default=u"Response id ${response_id} is no integer.", mapping=dict(response_id=response_id)) msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') self.request.response.redirect(context.absolute_url()) return if response_id >= len(self.folder): msg = _(u"msg_invalid", default=u"The Response ID ${response_id} " "doesn't exist.", mapping=dict(response_id=response_id)) msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') else: self.folder.delete(response_id) msg = _(u"msg_removed", default="Removed response.", mapping=dict(response_id=response_id)) msg = self.context.translate(msg) status.addStatusMessage(msg, type='info') self.request.response.redirect(context.absolute_url())
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"msg_no_response", default=u"No Response was selected") msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') return -1 else: try: response_id = int(response_id) except ValueError: msg = _(u"msg_nointeger", default=u"Response id ${response_id} is no integer.", mapping=dict(response_id=response_id)) msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') return -1 if response_id >= len(self.folder): msg = _( u"msg_invalid", default=u"The Response ID ${response_id} doesn't exist.", mapping=dict(response_id=response_id)) msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') return -1 else: return response_id # fallback return -1
def readable_author(context): """ get the full name of a user-id """ author = context.getResponsibleManager() if not author: return '-' name = author user = context.acl_users.getUserById(author) if user is None: return _(u"unassigned") else: name = user.getProperty('fullname', author) if not len(name): name = author return name
def assignable_users(self): """ Get the managers available as a DisplayList. The first item is 'None', with a key of '(UNASSIGNED)'. """ factory = queryUtility(IVocabularyFactory, name='assignable_users') if factory is None: factory = getUtility(IVocabularyFactory, name='plone.principalsource.Users', context=self) vocabulary = factory(self) # TODO: Use vocabulary instead of list of tuples. users = [('(UNASSIGNED)', _(u'None'))] mtool = getToolByName(self, 'portal_membership') assignable_userids = self.getAssignableUserIds() for term in vocabulary: member = mtool.getMemberById(term.token) if member is None: continue if member.getId() not in assignable_userids: continue user = member.getUser() #We do this the same way plone.api does. # But can't use plone.api due to a bug. old_security_manager = getSecurityManager() newSecurityManager(self.REQUEST, user) has_permission = user.checkPermission( 'izug.ticketbox: Add Ticket', self ) setSecurityManager(old_security_manager) if member and has_permission: title = term.title if not title: title = term.value users.append((term.token, title)) return users
def get_header(context): return [ context.translate( _(u'export_heading_nr', default=u'No.')), context.translate( _(u'export_heading_title', default=u'Title')), context.translate( _(u'export_heading_description', default=u'Description')), context.translate( _(u'export_heading_creator', default=u'Creator')), context.translate( _(u'export_heading_created', default=u'Created')), context.translate( _(u'export_heading_responsible', default=u'Responsible')), context.translate( _(u'export_heading_state', default=u'State')), context.translate( _(u'export_heading_priorities', default=u'Priorities')), context.translate( _(u'export_heading_area', default=u'Area')), context.translate( _(u'export_heading_variety', default=u'Variety')), context.translate( _(u'export_heading_releases', default=u'Releases')), context.translate( _(u'export_heading_watched_release', default=u'Watched release')), context.translate( _(u'export_heading_watched_due_date', default=u'Due date')), ]
def infos(self): """Returns Infos for email-template""" responses = self.get_responses() author = readable_author(self.context) if isinstance(author, Message): author = self.context.translate(author) ticket_infos = {'tracker_title': self.context.aq_parent.title, 'tracker_url': self.context.aq_parent.absolute_url(), 'title': self.context.Title(), 'ticket_id': self.context.getId(), 'individualIdendifier': self.context.aq_parent.getIndividualIdentifier, 'url': self.context.absolute_url(), 'text': self.context.getTicket_description(), 'state': map_attribute(self.context, "state"), 'responsibleManager': author, 'priority': map_attribute(self.context, "priority"), 'area': map_attribute(self.context, "area"), 'variety': map_attribute(self.context, "variety"), 'releases': map_attribute(self.context, "releases"), 'watchedRelease': map_attribute(self.context, "watchedRelease"), 'answerDate': self.context.toLocalizedTime( self.context.getAnswerDate(), long_format=True), 'response': False} if responses == []: return ticket_infos else: response_date = responses[len(responses) - 1]['response'].date if self.context.modification_date > response_date: return ticket_infos else: response = responses[len(responses) - 1] changes = { 'tracker_title': self.context.aq_parent.title, 'tracker_url': self.context.aq_parent.absolute_url(), 'title': self.context.Title(), 'ticket_id': self.context.getId(), 'individualIdendifier': self.context.aq_parent.getIndividualIdentifier, 'url': self.context.absolute_url(), 'text': '', 'state': '', 'responsibleManager': '', 'priority': '', 'area': '', 'variety': '', 'releases': '', 'watchedRelease': '', 'answerDate': '', 'response': True} for item in response['response'].changes: # XXX: Hack to solve the label_unassigned translations # problem. # If we retrieve a responsibleManager named # label_unassigned, try to translate it if item['id'] == 'responsibleManager': if item['before'] == 'label_unassigned': item['before'] = self.context.translate( _(item['before'])) if item['after'] == 'label_unassigned': item['after'] = self.context.translate( _(item['after'])) changes[item['id']] = ( item['before'] + ' → ' + item['after']) changes['text'] = response['response'].text return changes
def __call__(self): form = self.request.form context = aq_inner(self.context) modifiedDate = context.modified() 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 #Unassigned is no member in portal_membership. #So we have to set it manually unassigned = _(u'label_unassigned', default=u'unassigned') responsible_after = form.get('responsibleManager', u'') if responsible_after != context.getResponsibleManager(): #get ResponsibleManager and member-infos before changes responsible_before = context.getResponsibleManager() member_before = self.context.portal_membership.getMemberById( responsible_before) context.setResponsibleManager(responsible_after) #get member-infos after changes member_after = self.context.portal_membership.getMemberById( responsible_after) #get fullname from member before changes if member_before: before = member_before.getProperty( 'fullname', responsible_before) else: before = unassigned #get fullname from member after changes if member_after: after = member_after.getProperty( 'fullname', responsible_after) else: after = unassigned new_response.add_change('responsibleManager', _(u'label_responsibleManager', default=u"Responsible"), before, after) issue_has_changed = True # Answerdate answerdate_before = context.getAnswerDate() if answerdate_before: answerdate_before = answerdate_before.strftime('%d.%m.%Y %H:%M') else: answerdate_before = '' answerdate_after = answerdate_before year = int(form.get('answerdate_year', 0)) month = int(form.get('answerdate_month', 0)) day = int(form.get('answerdate_day', 0)) if year and month and day: hour = int(form.get('answerdate_hour', 0)) minute = int(form.get('answerdate_minute', 0)) answerdate_after = DateTime( year, month, day, hour, minute).strftime('%d.%m.%Y %H:%M') if answerdate_before != answerdate_after: context.setAnswerDate(answerdate_after) new_response.add_change('answerDate', _(u'label_answerdate', default=u'Answerdate'), answerdate_before, answerdate_after) issue_has_changed = True options = [ ('priority', _(u'label_priority_', default=u"Priority"), 'available_priorities'), ('releases', _(u'label_releases', default=u"Target Release"), 'available_releases'), ('state', _(u'label_state', default=u"State"), 'available_states'), ('area', _(u'label_areas', default=u"Area"), 'available_areas'), ('variety', _(u'label_varieties', default=u"Variety"), 'available_varieties'), ('watchedRelease', _(u'label_watched_release', default=u"Watched Release"), 'available_watched_releases'), ] # 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 = context.__getattribute__(option) if current != new: changes[option] = new new_response.add_change( option, title, map_attribute(self.context, option, current), map_attribute(self.context, option, new)) issue_has_changed = True attachment = form.get('attachment') if attachment: # Create filename like AT - some Browser delivers the # local full path filename = attachment.filename filename = filename[max( filename.rfind('/'), filename.rfind('\\'), filename.rfind(':')) + 1:] # File(id, title, file) data = File(filename, filename, attachment) if not hasattr(data, 'filename'): setattr(data, 'filename', filename) # Create TicketAttachment and save the uid in attachment attr of # new_response new_id = queryUtility(IIDNormalizer).normalize( filename.decode('utf-8')) if context.get(new_id, None): IStatusMessage(context.REQUEST).addStatusMessage( _(u"text_file_exists_error"), type='error') context.setAttachment('DELETE_FILE') return self.request.response.redirect(context.absolute_url()) new_file_id = context.invokeFactory( type_name="TicketAttachment", id=new_id, title=filename, file=data) new_file = context.get(new_file_id, None) new_response.attachment = new_file.UID() issue_has_changed = True references = form.get('ticketReferences') if references: new_response.references = references # Store refs also on Ticket self.context.setTicketReferences( references + self.context.getRawTicketReferences()) if len(response_text) == 0 and not issue_has_changed: status = IStatusMessage(self.request) msg = _( u"msg_no_changes", default="No response text added and no issue changes made.") # # msg = self.context.translate(msg) status.addStatusMessage(msg, type='error') else: # Apply changes to issue # XXX: CHANGE WORKFLOW - OR CHANGE SECURITYMANAGER # We cannot use AT's update method, because of a security check # we don't want. Let's set the new values manually. # OLD: # context.update(**changes) # NEW: if 'releases' in changes: context.setReleases(changes['releases']) if 'priority' in changes: context.setPriority(changes['priority']) if 'area' in changes: context.setArea(changes['area']) if 'variety' in changes: context.setVariety(changes['variety']) if 'state' in changes: context.setState(changes['state']) if 'watchedRelease' in changes: context.setWatchedRelease(changes['watchedRelease']) # Add response catalog_tool = self.context.portal_catalog # re-set the modification date - # this must be the last modifying access context.reindexObject() self.folder.add(new_response) context.setModificationDate(modifiedDate) catalog_tool.catalog_object(context, '/'.join(context.getPhysicalPath())) if form.get('sendNotification', None): self.request.response.redirect( context.absolute_url() + '/notification_form') else: self.request.response.redirect(context.absolute_url())
from izug.ticketbox.interfaces import ITicketBox from zope.component import queryUtility, getUtility from zope.interface import implements from zope.schema.interfaces import IVocabularyFactory TicketBoxSchema = folder.ATBTreeFolderSchema.copy() + Schema(( #Individual Identifier StringField( name='individualIdentifier', searchable=True, widget=StringWidget( maxlength=7, label=_(u"label_individualIdentifier", default=u"Individual identifier"), description=_( u"help_individualIdentifier", default=u"Enter a individual identifier " + u"(max 7 positions)"))), #Available States DataGridField( name='availableStates', searchable=True, allow_empty_rows=False, default=( {'id': '', 'title': "offen", 'show_in_all_tickets': '1',
def columns(self): columns = list(super(GlobalTicketTabBase, self).columns) columns.append({"column": "ticketbox_title", "column_title": _(u"Ticket Box"), "transform": link_to_parent}) return tuple(columns)
TicketSchema = schemata.ATContentTypeSchema.copy() + Schema(( TextField( name='ticket_description', default='', searchable=True, default_content_type='text/html', allowable_content_types=('text/html',), validators=('isTidyHtmlWithCleanup', ), default_output_type='text/x-html-safe', default_input_type='text/html', widget = atapi.RichWidget( label=_(u"label_description", default=u"Description"), rows=30)), #Due-Date (default: x + 14 days) DateTimeField( name='dueDate', default_method='default_due_date', required=True, validators=('isValidDate'), widget=CalendarWidget( label=_(u"label_duedate", default=u"Due Date"), description=_(u"help_duedate", default=u"Due-date of the ticket"))), #State StringField(
def columns(self): columns = list(super(GlobalTicketTabBase, self).columns) columns.append({'column': 'ticketbox_title', 'column_title': _(u'Ticket Box'), 'transform': link_to_parent}) return tuple(columns)