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": ""},
     )
Beispiel #2
0
 def yes_no(self):
     """return displaylist with two static rows
     contents: yes and no
     """
     return DisplayList((
             ("1", _(u"yes")),
             ("0", _(u"no")),
             ))
Beispiel #3
0
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()
Beispiel #4
0
    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
Beispiel #5
0
    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())
Beispiel #6
0
    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())
Beispiel #7
0
    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
Beispiel #8
0
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
Beispiel #9
0
    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
Beispiel #10
0
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
Beispiel #12
0
    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())
Beispiel #13
0
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',
Beispiel #14
0
 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)
Beispiel #15
0
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(
Beispiel #16
0
 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)