Beispiel #1
0
 def _giveFinanceAdvice(self, item, adviser_group_id):
     """Given an p_item in state 'proposed_to_finance_waiting_advices', give the p_adviser_group_id advice on it."""
     originalUserId = self.member.getId()
     self.changeUser('pmFinController')
     changeCompleteness = item.restrictedTraverse(
         '@@change-item-completeness')
     self.request.set('new_completeness_value', 'completeness_complete')
     self.request.form['form.submitted'] = True
     changeCompleteness()
     advice = createContentInContainer(
         item, 'meetingadvicefinances', **{
             'advice_group':
             adviser_group_id,
             'advice_type':
             u'positive_finance',
             'advice_comment':
             richtextval(u'<p>My comment finance</p>'),
             'advice_observations':
             richtextval(u'<p>My observation finance</p>')
         })
     self.do(advice,
             'proposeToFinancialReviewer',
             comment='My financial controller comment')
     # as finance reviewer
     self.changeUser('pmFinReviewer')
     self.do(advice,
             'proposeToFinancialManager',
             comment='My financial reviewer comment')
     # as finance manager
     self.changeUser('pmFinManager')
     self.do(advice,
             'signFinancialAdvice',
             comment='My financial manager comment')
     self.changeUser(originalUserId)
     return advice
Beispiel #2
0
 def test_AdviceTypeVocabulary(self):
     """'Products.PloneMeeting.content.advice.advice_type_vocabulary' was overrided
        to manage values of finance advice."""
     item, finance_advice = self._setupCollegeItemWithFinanceAdvice()
     self.changeUser('pmManager')
     vocab = queryUtility(
         IVocabularyFactory,
         "Products.PloneMeeting.content.advice.advice_type_vocabulary")
     # ask 'vendors' advice on item
     item.setOptionalAdvisers((self.vendors_uid, ))
     item._update_after_edit()
     self.do(item, 'backToProposedToDirector')
     vendors_advice = createContentInContainer(
         item, 'meetingadvice', **{
             'advice_group':
             self.vendors_uid,
             'advice_type':
             u'negative',
             'advice_comment':
             richtextval(u'<p>My comment vendors</p>'),
             'advice_observations':
             richtextval(u'<p>My observation vendors</p>')
         })
     finance_keys = vocab(finance_advice).by_value.keys()
     finance_keys.sort()
     self.assertEquals(finance_keys, [
         'negative_finance', 'not_required_finance', 'positive_finance',
         'positive_with_remarks_finance'
     ])
     vendors_keys = vocab(vendors_advice).by_value.keys()
     vendors_keys.sort()
     self.assertEquals(
         vendors_keys,
         ['negative', 'nil', 'positive', 'positive_with_remarks'])
Beispiel #3
0
    def _setupCollegeItemWithFinanceAdvice(self, ):
        """Setup, create a College item and give finance advice on it."""
        self.changeUser('admin')
        # add finance groups
        self._createFinanceGroups()
        # configure customAdvisers for 'meeting-config-college'
        _configureCollegeCustomAdvisers(self.portal)
        # define relevant users for finance groups
        self._setupFinanceGroups()

        # first 'return' an item and test
        self.changeUser('pmManager')
        item = self.create('MeetingItem', title='An item with finance advice')
        # ask finance advice and give it
        financial_group_uids = self.tool.finance_group_uids()
        item.setFinanceAdvice(financial_group_uids[0])
        item._update_after_edit()
        self.proposeItem(item)
        self.do(item, 'wait_advices_from_proposed_to_director')
        # make item completeness complete and add advice
        self.changeUser('pmFinController')
        changeCompleteness = item.restrictedTraverse(
            '@@change-item-completeness')
        self.request.set('new_completeness_value', 'completeness_complete')
        self.request.form['form.submitted'] = True
        changeCompleteness()
        advice = createContentInContainer(
            item, 'meetingadvicefinances', **{
                'advice_group':
                financial_group_uids[0],
                'advice_type':
                u'positive_finance',
                'advice_comment':
                richtextval(u'<p>My comment finance</p>'),
                'advice_observations':
                richtextval(u'<p>My observation finance</p>')
            })
        self.do(advice,
                'proposeToFinancialReviewer',
                comment='My financial controller comment')
        # as finance reviewer
        self.changeUser('pmFinReviewer')
        self.do(advice,
                'proposeToFinancialManager',
                comment='My financial reviewer comment')
        # as finance manager
        self.changeUser('pmFinManager')
        self.do(advice,
                'signFinancialAdvice',
                comment='My financial manager comment')
        return item, advice
Beispiel #4
0
    def insert_and_close_meeting(self, member_folder, csv_meeting):
        if not self._check_meeting_data(csv_meeting):
            return

        _id = "meetingimport.{external_id}".format(
            external_id=csv_meeting.external_id)

        meeting = self.object_already_exists(_id, csv_meeting.portal_type)
        if meeting and meeting[0]:
            message = "Skipping meeting {id} and it items because it already exists".format(
                id=_id)
            logger.info(message)
            self.errors["meeting"].append(message)
            return

        meeting_date = csv_meeting.date
        meetingid = member_folder.invokeFactory(
            type_name=csv_meeting.portal_type, id=_id, date=meeting_date)
        meeting = getattr(member_folder, meetingid)
        meeting.signatures = None
        if csv_meeting.assembly:
            meeting.assembly = richtextval(csv_meeting.assembly)
        meeting.date = meeting_date
        meeting.start_date = csv_meeting.started_on
        meeting.end_date = csv_meeting.ended_on

        meeting.creation_date = DateTime(csv_meeting.created_on)
        logger.info(u"Created {type} {id} {date}".format(
            type=csv_meeting.portal_type, id=_id, date=meeting.title))

        if csv_meeting.annexes:
            self.add_all_annexes_to_object(csv_meeting.annexes,
                                           meeting,
                                           confidential=True)
        else:
            meeting.observations = u"<p><strong>Cette séance n'a aucune annexe</strong></p>"

        logger.info(u"Adding {items} items to {type} of {date}".format(
            items=len(csv_meeting.items),
            type=csv_meeting.portal_type,
            date=meeting.title))

        self.portal.REQUEST["PUBLISHED"] = meeting
        for csv_item in csv_meeting.items:
            self.insert_and_present_item(member_folder, csv_item)

        if meeting.get_items():
            meeting.portal_workflow.doActionFor(meeting, "freeze")
            meeting.portal_workflow.doActionFor(meeting, "decide")
            meeting.portal_workflow.doActionFor(meeting, "close")

            for item in meeting.get_items():
                item.setModificationDate(meeting_date)
                item.reindexObject(idxs=["modified"])

        meeting.setModificationDate(DateTime(meeting_date))

        meeting.reindexObject(idxs=["modified"])
        self.meeting_counter += 1
        transaction.commit()
Beispiel #5
0
 def migrate_to_text_x_html_safe(self):
     """Migrate richtext's outputMimeType to text/x-html-safe."""
     for brain in self.catalog(object_provides='imio.project.core.content.project.IProject'):
         obj = brain.getObject()
         if obj.budget_comments:
             if obj.budget_comments.outputMimeType == 'text/html':
                 obj.budget_comments = richtextval(obj.budget_comments.raw)
                 obj.reindexObject()
         if obj.observation:
             if obj.observation.outputMimeType == 'text/html':
                 obj.observation = richtextval(obj.observation.raw)
                 obj.reindexObject()
         if obj.comments:
             if obj.comments.outputMimeType == 'text/html':
                 obj.comments = richtextval(obj.comments.raw)
                 obj.reindexObject()
Beispiel #6
0
 def migrate_projects_richtextvalues(self):
     project_brains = self.catalog(object_provides=IProject.__identifier__)
     for project_brain in project_brains:
         for field_name in ['budget_comments', 'observation', 'comments']:
             project_obj = project_brain.getObject()
             field_value = getattr(project_obj, field_name)
             if field_value:
                 if isinstance(field_value, RichTextValue):
                     setattr(project_obj, field_name,
                             richtextval(field_value.raw))
Beispiel #7
0
    def test_restapi_search_meetings_fullobjects(self):
        """ """
        endpoint_url = "{0}/@search?config_id={1}&type=meeting&fullobjects=True".format(
            self.portal_url, self.meetingConfig.getId())

        # create 2 meetings
        self.changeUser("pmManager")
        pattern = '<p>Text with image <img src="{0}"/> and more text.</p>'
        meeting = self.create("Meeting", date=datetime(2019, 11, 18))
        meeting2 = self.create("Meeting", date=datetime(2019, 11, 19))
        if HAS_MEETING_DX:
            meeting2.assembly = RichTextValue(
                u'Mr Present, [[Mr Absent]], Mr Present2')
            img = self._add_image(meeting2)
            text = pattern.format(img.absolute_url())
            meeting2.observations = richtextval(text)
        else:
            meeting2.setAssembly(u'Mr Present, [[Mr Absent]], Mr Present2')
            img = self._add_image(meeting2)
            text = pattern.format(img.absolute_url())
            meeting2.setObservations(text)

        self.assertEqual(self.get_review_state(meeting), "created")
        self.closeMeeting(meeting2)
        self.assertEqual(self.get_review_state(meeting2), "closed")
        transaction.commit()

        # found
        response = self.api_session.get(endpoint_url)
        self.assertEqual(response.status_code, 200, response.content)
        self.assertEqual(response.json()[u"items_total"], 2)
        # may still use additional search parameters
        endpoint_url += "&review_state=closed"
        response = self.api_session.get(endpoint_url)
        self.assertEqual(response.status_code, 200, response.content)
        resp_json = response.json()
        self.assertEqual(resp_json[u"items_total"], 1)
        self.assertEqual(resp_json[u"items"][0][u"review_state"], u"closed")

        # includes every data as well as extra formatted values
        self.assertTrue("date" in resp_json["items"][0])
        # AT/DX
        self.assertTrue("startDate" in resp_json["items"][0]
                        or "start_date" in resp_json["items"][0])
        self.assertTrue("notes" in resp_json["items"][0])
        self.assertEqual(
            resp_json["items"][0]["formatted_assembly"],
            u'<p>Mr Present, <strike>Mr Absent</strike>, Mr Present2</p>')
        self.assertEqual(resp_json["items"][0]["observations"]["data"],
                         pattern.format(IMG_BASE64_DATA))
        transaction.abort()
Beispiel #8
0
    def getAllMessages(self):
        """ Check if an address field is empty """
        if IContactContent.providedBy(self.context):
            contacts = [self.context]
        elif IImioDmsOutgoingMail.providedBy(self.context):
            contacts = []
            for rv in (self.context.recipients or []):
                if not rv.isBroken() and rv.to_path:
                    contacts.append(self.context.restrictedTraverse(
                        rv.to_path))
        if not contacts:
            return []
        errors = []
        for contact in contacts:
            address = get_address(contact)
            empty_keys = []
            for key in (
                    'street',
                    'number',
                    'zip_code',
                    'city',
            ):
                if not address.get(key, ''):
                    empty_keys.append(
                        translate(key,
                                  domain='imio.dms.mail',
                                  context=self.request))
            if empty_keys:
                errors.append((contact, empty_keys))

        ret = []
        for (contact, keys) in errors:
            msg = translate(
                u"This contact '${title}' has missing address fields: ${keys}",
                domain='imio.dms.mail',
                context=self.request,
                mapping={
                    'title':
                    object_link(contact,
                                view='edit',
                                attribute='get_full_title'),
                    'keys':
                    ', '.join(keys)
                })
            ret.append(
                PseudoMessage(msg_type='significant',
                              text=richtextval(msg),
                              hidden_uid=generate_uid(),
                              can_hide=False))
        return ret
Beispiel #9
0
 def migrate_description(self):
     """ Migrate description field to description_rich """
     for brain in self.catalog(
             object_provides='imio.project.core.content.project.IProject'):
         obj = brain.getObject()
         # old description contains something like : u'ligne1\r\nligne2\r\nligne3'
         if obj.description:
             new_val = []
             for line in obj.description.split('\r\n'):
                 new_val.append(line)
             obj.description_rich = richtextval(
                 u'<p>{}</p>'.format(u'<br />'.join(new_val),
                                     outputMimeType='text/x-html-safe'))
             obj.description = u''
             obj.reindexObject()
Beispiel #10
0
    def test_pm_TransformAllRichTextFields(self):
        """Test that it does not alterate field content, especially
           links to internal content or image that uses resolveuid."""

        # MeetingItem AT
        self.changeUser('pmCreator1')
        item = self.create('MeetingItem')
        # add image
        file_path = path.join(path.dirname(__file__), 'dot.gif')
        file_handler = open(file_path, 'r')
        data = file_handler.read()
        file_handler.close()
        img_id = item.invokeFactory('Image',
                                    id='dot.gif',
                                    title='Image',
                                    file=data)
        img = getattr(item, img_id)

        # link to image using resolveuid
        text = '<p>Internal image <img src="resolveuid/{0}" />.</p>'.format(
            img.UID())
        item.setDescription(text)
        self.assertEqual(item.objectIds(), ['dot.gif'])
        transformAllRichTextFields(item)
        self.assertEqual(item.getRawDescription(), text)
        transformAllRichTextFields(item, onlyField="description")
        self.assertEqual(item.getRawDescription(), text)

        # Meeting DX
        self.changeUser('pmManager')
        meeting = self.create('Meeting')
        # add image
        img_id = meeting.invokeFactory('Image',
                                       id='dot.gif',
                                       title='Image',
                                       file=data)
        img = getattr(meeting, img_id)

        # link to image using resolveuid
        text = '<p>Internal image <img src="resolveuid/{0}" />.</p>'.format(
            img.UID())
        meeting.observations = richtextval(text)
        self.assertEqual(meeting.objectIds(), ['dot.gif'])
        transformAllRichTextFields(meeting)
        self.assertEqual(meeting.observations.raw, text)
        transformAllRichTextFields(meeting, onlyField="observations")
        self.assertEqual(meeting.observations.raw, text)
Beispiel #11
0
    def test_restapi_search_data_are_anonymized(self):
        """Data collected from PloneMeeting are anonymized."""
        self._enableField("observations")
        self._enableField("observations", related_to="Meeting")

        # create 2 items
        text = '<p>Text shown<span class="pm-anonymize"> text hidden</span> and ' \
            'some <span class="highlight-red">highlighted text</span>.</p>'
        anonymized_text = '<p>Text shown<span class="pm-anonymize"></span> and ' \
            'some <span class="highlight-red">highlighted text</span>.</p>'
        self.changeUser("pmManager")
        item = self.create("MeetingItem")
        item.setObservations(text)
        item.setDecision(text)
        # in 4.1.x item observations was only readable until validated...
        self.validateItem(item)
        meeting = self.create("Meeting", date=datetime(2020, 6, 8, 8, 0))
        if HAS_MEETING_DX:
            meeting.observations = richtextval(text)
        else:
            meeting.setObservations(text)
        transaction.commit()

        # query to get meeting and item description
        endpoint_url = "{0}/@search?fullobjects" \
            "&include_all=false" \
            "&extra_include=public_deliberation" \
            "&metadata_fields=observations" \
            "&UID={2}&UID={3}&sort_on=getId".format(
                self.portal_url, self.meetingConfig.getId(),
                item.UID(), meeting.UID())
        response = self.api_session.get(endpoint_url)
        self.assertEqual(response.status_code, 200, response.content)
        resp_json = response.json()
        self.assertEqual(resp_json["items_total"], 2)
        # item
        # RichTextField
        self.assertEqual(resp_json["items"][0]["observations"]["data"],
                         anonymized_text)
        # RichText treated by printXhtml
        self.assertEqual(
            resp_json["items"][0]["extra_include_deliberation"]
            ["public_deliberation"], anonymized_text)
        # meeting
        # RichTextField
        self.assertEqual(resp_json["items"][1]["observations"]["data"],
                         anonymized_text)
Beispiel #12
0
 def various_update(self):
     # replace front-page
     frontpage = getattr(self.portal, 'front-page')
     frontpage.title = _translate("front_page_title")
     frontpage.description = _translate("front_page_descr")
     frontpage.text = richtextval(_translate("front_page_text"))
     transitions(frontpage, ('retract', 'publish_internally'))
     frontpage.reindexObject()
     self.portal.templates.layout = 'dg-templates-listing'
     # plonegroup-organization
     pgo = get_own_organization()
     behaviour = ISelectableConstrainTypes(pgo)
     behaviour.setConstrainTypesMode(1)
     behaviour.setLocallyAllowedTypes([])
     behaviour.setImmediatelyAddableTypes([])
     ISelectableConstrainTypes(pgo['echevins']).setConstrainTypesMode(0)
     ISelectableConstrainTypes(pgo['services']).setConstrainTypesMode(0)
Beispiel #13
0
 def various_update(self):
     # replace front-page
     frontpage = getattr(self.portal, 'front-page')
     frontpage.title = _translate("front_page_title")
     frontpage.description = _translate("front_page_descr")
     frontpage.text = richtextval(_translate("front_page_text"))
     transitions(frontpage, ('retract', 'publish_internally'))
     frontpage.reindexObject()
     self.portal.templates.layout = 'dg-templates-listing'
     self.portal.contacts.exclude_from_nav = True
     self.portal.contacts.reindexObject(['exclude_from_nav'])
     #Hiding folder contents
     self.portal.manage_permission('List folder contents', ('Manager', 'Site Administrator'), acquire=0)
     paob = self.portal.portal_actions.object_buttons
     for act in ('faceted.sync', 'faceted.disable', 'faceted.enable', 'faceted.search.disable',
                 'faceted.search.enable', 'faceted.actions.disable', 'faceted.actions.enable',
                 'ical_import_enable', 'ical_import_disable'):
         if act in paob:
             paob[act].visible = False
Beispiel #14
0
 def test_call(self):
     omail1 = get_object(oid='reponse1', ptype='dmsoutgoingmail')
     omail1.send_modes = [u'email']
     omail1.email_subject = u'Email subject'
     omail1.email_sender = u'*****@*****.**'
     omail1.email_recipient = u'*****@*****.**'
     omail1.email_body = richtextval(u'My email content.')
     view = omail1.unrestrictedTraverse('@@send_email')
     # Status before call
     self.assertEqual(api.content.get_state(omail1), 'created')
     self.assertIsNone(omail1.email_status)
     MockMailHost.secureSend = MockMailHost.send
     mail_host = get_mail_host()
     mail_host.reset()
     # view call
     view()
     self.assertIn('Subject: =?utf-8?q?Email_subject?=\n',
                   mail_host.messages[0])
     self.assertIn('My email content.', mail_host.messages[0])
     self.assertEqual(api.content.get_state(omail1), 'sent')
     self.assertIsNotNone(omail1.email_status)
Beispiel #15
0
    def various_update(self):
        # doc message
        for id in ('doc1-0', 'doc'):
            if id in self.portal['messages-config']:
                api.content.delete(self.portal['messages-config'][id])
        if ('indispo' in self.portal['messages-config']
                and api.content.get_state(
                    self.portal['messages-config']['indispo']) == 'activated'):
            api.content.transition(self.portal['messages-config']['indispo'],
                                   'deactivate')
        if 'doc' not in self.portal['messages-config']:
            add_message(
                'doc',
                'Documentation', u'<p>Vous pouvez consulter la '
                u'<a href="https://docs.imio.be/imio-doc/ia.pst/" target="_blank">documentation en ligne de la '
                u'dernière version</a>, ainsi que <a href="https://www.imio.be/nos-applications/ia-pst/'
                u'les-actus-de-pst/ia-pst-1-3" target="_blank">les nouveautés</a>.</p>',
                msg_type='significant',
                can_hide=True,
                req_roles=['Authenticated'],
                activate=True)
        # activate user external edit pref
        change_user_properties(self.portal, kw='ext_editor:True', dochange='1')
        # replace front-page
        frontpage = getattr(self.portal, 'front-page')
        frontpage.title = _tr("front_page_title")
        frontpage.description = _tr("front_page_descr")
        frontpage.text = richtextval(_tr("front_page_text"))
        transitions(frontpage, ('retract', 'publish_internally'))
        frontpage.reindexObject()
        # remove portlets on pst
        for brain in self.catalog(
                object_provides='imio.project.pst.interfaces.IImioPSTProject'):
            ann = IAnnotations(brain.getObject())
            if 'plone.portlets.contextassignments' in ann:
                if 'plone.leftcolumn' in ann[
                        'plone.portlets.contextassignments']:
                    for name in ('portlet_dashboard', 'navigation',
                                 'portlet_actions'):
                        if name in ann['plone.portlets.contextassignments'][
                                'plone.leftcolumn']:
                            del ann['plone.portlets.contextassignments'][
                                'plone.leftcolumn'][name]
                    if not len(ann['plone.portlets.contextassignments']
                               ['plone.leftcolumn']):
                        del ann['plone.portlets.contextassignments'][
                            'plone.leftcolumn']
                if not len(ann['plone.portlets.contextassignments']):
                    del ann['plone.portlets.contextassignments']
        # registry
        api.portal.set_registry_record(
            'collective.contact.core.interfaces.IContactCoreParameters.'
            'display_below_content_title_on_views', True)
        registry = getUtility(IRegistry)
        record = registry.records.get(
            'imio.pm.wsclient.browser.settings.IWS4PMClientSettings.generated_actions'
        )
        if record is not None:
            val = api.portal.get_registry_record(
                'imio.pm.wsclient.browser.settings.IWS4PMClientSettings.'
                'generated_actions')
            if val is not None:
                event.notify(RecordModifiedEvent(record, val, val))
        # update dashboard criterias
        for brain in self.catalog(
                object_provides='imio.project.pst.interfaces.IImioPSTProject'):
            pst = brain.getObject()
            mapping = {
                'strategicobjectives': 'strategicobjective',
                'operationalobjectives': 'operationalobjective',
                'pstactions': 'pstaction',
                'tasks': 'task'
            }
            for col_folder_id, content_type in mapping.iteritems():
                col_folder = pst[col_folder_id]
                reimport_faceted_config(col_folder,
                                        xml='{}.xml'.format(content_type),
                                        default_UID=col_folder['all'].UID())
        # rename pst
        titles = {
            u'PST (2012-2018)': u'PST 2013-2018',
            u'PST (2018-2024)': u'PST 2019-2024',
            u'PST (2019-2024)': u'PST 2019-2024',
            u'PST': u'PST 2019-2024'
        }
        values = titles.values()
        for brain in self.catalog(
                object_provides='imio.project.pst.interfaces.IImioPSTProject'):
            pst = brain.getObject()
            for tit in titles:
                if pst.title == tit:
                    pst.title = titles[tit]
                    modified(pst)
                    break
            else:
                if pst.title not in values:
                    logger.warning("PST rename: not replaced '{}'".format(
                        pst.title.encode('utf8')))
        # update ckeditor to remove format and avoid html <h> tags
        cke_props = self.portal.portal_properties.ckeditor_properties
        custom = (
            u"[\n['AjaxSave'],\n['Cut','Copy','Paste','PasteText','PasteFromWord','-',"
            u"'Scayt'],\n['Undo','Redo','-','RemoveFormat'],\n['Bold','Italic','Underline','Strike'],\n"
            u"['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],\n['JustifyLeft',"
            u"'JustifyCenter', 'JustifyRight','JustifyBlock'],\n['Table','SpecialChar','Link','Unlink'],\n'/',"
            u"\n['Styles'],\n['Maximize', 'ShowBlocks', 'Source']\n]")
        cke_props.toolbar_Custom = custom
        if cke_props.menuStyles.find(CKEDITOR_MENUSTYLES_CUSTOMIZED_MSG) == -1:
            enc = self.portal.portal_properties.site_properties.getProperty(
                'default_charset')
            msg_highlight_red = _tr('ckeditor_style_highlight_in_red').encode(
                'utf-8')
            msg_highlight_blue = _tr(
                'ckeditor_style_highlight_in_blue').encode('utf-8')
            msg_highlight_green = _tr(
                'ckeditor_style_highlight_in_green').encode('utf-8')
            msg_highlight_yellow = _tr(
                'ckeditor_style_highlight_in_yellow').encode('utf-8')
            msg_x_small = _tr('ckeditor_style_x_small').encode('utf-8')
            msg_small = _tr('ckeditor_style_small').encode('utf-8')
            msg_large = _tr('ckeditor_style_large').encode('utf-8')
            msg_x_large = _tr('ckeditor_style_x_large').encode('utf-8')
            msg_indent = _tr('ckeditor_style_indent_first_line').encode(
                'utf-8')
            msg_table_no_optimization = _tr(
                'ckeditor_style_table_no_optimization').encode('utf-8')

            menuStyles = unicode(
                "[\n{0}\n{{ name : '{1}'\t\t, element : 'span', attributes : {{ 'class' : 'highlight-red' }} }},\n"
                "{{ name : '{2}'\t\t, element : 'span', attributes : {{ 'class' : 'highlight-blue' }} }},\n"
                "{{ name : '{3}'\t\t, element : 'span', attributes : {{ 'class' : 'highlight-green' }} }},\n"
                "{{ name : '{4}'\t\t, element : 'span', attributes : {{ 'class' : 'highlight-yellow' }} }},\n"
                "{{ name : '{5}'\t\t, element : 'p', attributes : {{ 'class' : 'xSmallText' }} }},\n"
                "{{ name : '{6}'\t\t, element : 'p', attributes : {{ 'class' : 'smallText' }} }},\n"
                "{{ name : '{7}'\t\t, element : 'p', attributes : {{ 'class' : 'largeText' }} }},\n"
                "{{ name : '{8}'\t\t, element : 'p', attributes : {{ 'class' : 'xLargeText' }} }},\n"
                "{{ name : '{9}'\t\t, element : 'table', styles : {{ 'table-layout' : 'fixed' }} }},\n"
                "{{ name : '{10}'\t\t, element : 'p', attributes : {{ 'style' : 'text-indent: 40px;' }} }},\n]\n"
                .format(CKEDITOR_MENUSTYLES_CUSTOMIZED_MSG, msg_highlight_red,
                        msg_highlight_blue, msg_highlight_green,
                        msg_highlight_yellow, msg_x_small, msg_small,
                        msg_large, msg_x_large, msg_table_no_optimization,
                        msg_indent), enc)
            cke_props.menuStyles = menuStyles
Beispiel #16
0
    def test_FinancialManagerMayChangeAdviceDelayWhenAddableOrEditable(self):
        '''Check that a financial manager may still change advice asked to his financial
           group while the advice is still addable or editable.'''
        self.changeUser('admin')
        # add finance groups
        self._createFinanceGroups()
        # configure customAdvisers for 'meeting-config-college'
        _configureCollegeCustomAdvisers(self.portal)
        # define relevant users for finance groups
        self._setupFinanceGroups()

        # ask finance advice and ask advice (set item to 'proposed_to_finance_waiting_advices')
        # not need a finances advice
        self.changeUser('pmManager')
        item = self.create('MeetingItem', title='The first item')
        financial_group_uids = self.tool.finance_group_uids()
        item.setFinanceAdvice(financial_group_uids[0])
        item._update_after_edit()
        self.assertTrue(financial_group_uids[0] in item.adviceIndex)
        self.proposeItem(item)
        self.do(item, 'wait_advices_from_proposed_to_director')
        item.setCompleteness('completeness_complete')
        item._update_after_edit()
        # ok, now advice can be given
        # a financial manager may change delays
        self.changeUser('pmFinManager')
        delayView = item.restrictedTraverse('@@advice-available-delays')
        # advice has been asked automatically
        financial_group_uids = self.tool.finance_group_uids()
        isAutomatic = not bool(
            item.adviceIndex[financial_group_uids[0]]['optional'])
        # advice is addable, delays may be changed
        self.assertTrue(delayView._mayEditDelays(isAutomatic=isAutomatic))
        # add the advice, delay still changeable as advice is editable
        advice = createContentInContainer(
            item, 'meetingadvicefinances', **{
                'advice_group': financial_group_uids[0],
                'advice_type': u'positive_finance',
                'advice_comment': richtextval(u'My comment finance')
            })
        self.assertTrue(delayView._mayEditDelays(isAutomatic=isAutomatic))
        # other members of the finance group can not edit advice delay
        self.changeUser('pmFinController')
        self.assertTrue(not delayView._mayEditDelays(isAutomatic=isAutomatic))
        # send to financial reviewer
        self.do(advice, 'proposeToFinancialReviewer')
        self.assertTrue(not delayView._mayEditDelays(isAutomatic=isAutomatic))
        # delay editable by manager but not by others
        self.changeUser('pmFinManager')
        self.assertTrue(delayView._mayEditDelays(isAutomatic=isAutomatic))
        self.changeUser('pmFinReviewer')
        self.assertTrue(not delayView._mayEditDelays(isAutomatic=isAutomatic))
        # send to finance manager
        self.do(advice, 'proposeToFinancialManager')
        self.assertTrue(not delayView._mayEditDelays(isAutomatic=isAutomatic))
        # delay editable by finance manager but not by others
        self.changeUser('pmFinManager')
        self.assertTrue(delayView._mayEditDelays(isAutomatic=isAutomatic))
        # if manager sign the advice, so advice is no more editable
        # even the finance manager may no more edit advice delay
        self.do(advice, 'signFinancialAdvice')
        self.assertFalse(
            item.adviceIndex[financial_group_uids[0]]['advice_editable'])
        self.assertFalse(delayView._mayEditDelays(isAutomatic=isAutomatic))
Beispiel #17
0
    def run(self):
        logger.info('Migrating to imio.dms.mail 1.0...')
        self.cleanRegistries()
        self.upgradeProfile('collective.dms.mailcontent:default')
        # We have to reapply type info before doing other subproducts migration
        self.runProfileSteps('imio.dms.mail', steps=['typeinfo'])
        # We have to update type schema because plone.dexterity doesn't detect schema_policy modification. BUG #44
        for portal_type in ['dmsincomingmail', 'dmsoutgoingmail']:  # i_e ok
            schemaName = dxutils.portalTypeToSchemaName(portal_type)
            schema = getattr(plone.dexterity.schema.generated, schemaName)
            fti = getUtility(IDexterityFTI, name=portal_type)
            model = fti.lookupModel()
            syncSchema(model.schema, schema, overwrite=True, sync_bases=True)
            notify(plone.dexterity.schema.SchemaInvalidatedEvent(portal_type))

        self.upgradeProfile('collective.task:default')
        self.upgradeProfile('dexterity.localroles:default')
        self.upgradeProfile('dexterity.localrolesfield:default')
        self.upgradeProfile('collective.contact.plonegroup:default')
        self.runProfileSteps('imio.dms.mail',
                             steps=[
                                 'actions', 'componentregistry',
                                 'controlpanel', 'plone.app.registry',
                                 'portlets', 'repositorytool', 'rolemap',
                                 'sharing', 'workflow'
                             ])
        self.portal.portal_workflow.updateRoleMappings()
        self.runProfileSteps('collective.dms.mailcontent',
                             steps=['controlpanel'])
        self.runProfileSteps('collective.contact.plonegroup',
                             steps=['controlpanel'])
        self.reinstall([
            'collective.messagesviewlet:messages',
            'collective.querynextprev:default',
            'imio.dashboard:default',
        ])

        # set jqueryui autocomplete to False. If not, contact autocomplete doesn't work
        self.registry[
            'collective.js.jqueryui.controlpanel.IJQueryUIPlugins.ui_autocomplete'] = False

        # delete old dmsmail portlet
        self.delete_portlet(self.portal, 'portlet_maindmsmail')

        # remove deprecated interfaces
        self.remove_contact_interfaces()

        # moved notes content to task_description
        catalog = api.portal.get_tool('portal_catalog')
        brains = catalog.searchResults(portal_type='dmsincomingmail')  # i_e ok
        for brain in brains:
            obj = brain.getObject()
            if not base_hasattr(obj, 'notes') or not obj.notes:
                continue
            text = u'<p>%s</p>\r\n' % obj.notes.replace('\r\n', '<br />\r\n')
            obj.task_description = richtextval(text)
            delattr(obj, 'notes')
        #    obj.reindexObject()

        # replace collections by Dashboard collections
        im_folder = self.portal['incoming-mail']
        alsoProvides(im_folder, INextPrevNotNavigable)
        alsoProvides(im_folder, IIMDashboard)
        self.replaceCollections(im_folder)

        # apply contact faceted config
        reimport_faceted_config(self.portal['contacts'],
                                'contacts-faceted.xml')

        # add new indexes for dashboard
        addOrUpdateIndexes(self.portal,
                           indexInfos={
                               'mail_type': ('FieldIndex', {}),
                               'mail_date': ('DateIndex', {}),
                               'in_out_date': ('DateIndex', {}),
                           })

        # set dashboard on incoming mail
        configure_faceted_folder(
            im_folder,
            xml='default_dashboard_widgets.xml',
            default_UID=im_folder['mail-searches']['all_mails'].UID())

        # set task local roles configuration
        configure_task_rolefields(self.portal)

        # update dexterity local roles configuration
        self.update_local_roles()

        # add task actionspanel config
        if not self.registry[
                'imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions']:
            self.registry['imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions'] = []
        self.registry['imio.actionspanel.browser.registry.IImioActionsPanelConfig.transitions'] += \
            ['task.back_in_created|', 'task.back_in_to_assign|', 'task.back_in_to_do|',
             'task.back_in_progress|', 'task.back_in_realized|']

        # activate ckeditor
        configure_ckeditor(self.portal, custom='ged')

        # Set markup allowed types
        adapter = MarkupControlPanelAdapter(self.portal)
        adapter.set_allowed_types(['text/html'])

        # update searchabletext
        self.update_dmsmainfile()

        self.upgradeAll()
        for prod in [
                'plone.formwidget.autocomplete', 'collective.documentviewer',
                'plone.formwidget.masterselect', 'collective.contact.core',
                'collective.contact.duplicated', 'collective.dms.basecontent',
                'collective.dms.scanbehavior', 'collective.externaleditor',
                'plone.app.collection', 'plone.app.intid',
                'collective.contact.facetednav', 'plonetheme.imioapps',
                'PasswordStrength', 'imio.dms.mail'
        ]:
            mark_last_version(self.portal, product=prod)

        self.portal.manage_permission(
            'CMFEditions: Revert to previous versions',
            ('Manager', 'Site Administrator'),
            acquire=0)

        #self.refreshDatabase()
        self.finish()
Beispiel #18
0
 def getAllMessages(self):
     ret = []
     if self.context.portal_type == "operationalobjective":
         if self.context.planned_end_date:
             max_children_deadline = find_max_deadline_on_children(
                 self.context, {
                     "pstaction": "planned_end_date",
                     "action_link": "planned_end_date",
                     "pstsubaction": "planned_end_date",
                     "subaction_link": "planned_end_date",
                     "task": "due_date"
                 })
             if max_children_deadline:
                 if max_children_deadline > self.context.planned_end_date:
                     msg = _(
                         u"The deadline of any one of children is greater than those of this element"
                     )
                     ret.append(
                         PseudoMessage(
                             msg_type="significant",
                             text=richtextval(msg),
                             hidden_uid=generate_uid(),
                             can_hide=False,
                         ))
         else:
             msg = _(
                 u"The deadline is not fill on this element, the system displays the largest of its "
                 u"possible children")
             ret.append(
                 PseudoMessage(
                     msg_type="significant",
                     text=richtextval(msg),
                     hidden_uid=generate_uid(),
                     can_hide=False,
                 ))
     if self.context.portal_type == "pstaction":
         if self.context.planned_end_date:
             max_children_deadline = find_max_deadline_on_children(
                 self.context, {
                     "pstsubaction": "planned_end_date",
                     "subaction_link": "planned_end_date",
                     "task": "due_date"
                 })
             if max_children_deadline:
                 if max_children_deadline > self.context.planned_end_date:
                     msg = _(
                         u"The deadline of any one of children is greater than those of this element"
                     )
                     ret.append(
                         PseudoMessage(
                             msg_type="significant",
                             text=richtextval(msg),
                             hidden_uid=generate_uid(),
                             can_hide=False,
                         ))
             if is_smaller_deadline_on_parents(
                     self.context, {
                         "pstaction": "planned_end_date",
                         "operationalobjective": "planned_end_date"
                     }):
                 msg = _(
                     u"The deadline of this element is greater than one of its parents"
                 )
                 ret.append(
                     PseudoMessage(
                         msg_type="significant",
                         text=richtextval(msg),
                         hidden_uid=generate_uid(),
                         can_hide=False,
                     ))
         else:
             msg = _(
                 u"The deadline is not fill on this element, the system displays the largest of its "
                 u"possible children")
             ret.append(
                 PseudoMessage(
                     msg_type="significant",
                     text=richtextval(msg),
                     hidden_uid=generate_uid(),
                     can_hide=False,
                 ))
     if self.context.portal_type == "pstsubaction":
         if self.context.planned_end_date:
             max_children_deadline = find_max_deadline_on_children(
                 self.context, {
                     "pstsubaction": "planned_end_date",
                     "subaction_link": "planned_end_date",
                     "task": "due_date"
                 })
             if max_children_deadline:
                 if max_children_deadline > self.context.planned_end_date:
                     msg = _(
                         u"The deadline of any one of children is greater than those of this element"
                     )
                     ret.append(
                         PseudoMessage(
                             msg_type="significant",
                             text=richtextval(msg),
                             hidden_uid=generate_uid(),
                             can_hide=False,
                         ))
             if is_smaller_deadline_on_parents(
                     self.context, {
                         "pstsubaction": "planned_end_date",
                         "pstaction": "planned_end_date",
                         "operationalobjective": "planned_end_date"
                     }):
                 msg = _(
                     u"The deadline of this element is greater than one of its parents"
                 )
                 ret.append(
                     PseudoMessage(
                         msg_type="significant",
                         text=richtextval(msg),
                         hidden_uid=generate_uid(),
                         can_hide=False,
                     ))
         else:
             msg = _(
                 u"The deadline is not fill on this element, the system displays the largest of its "
                 u"possible children")
             ret.append(
                 PseudoMessage(
                     msg_type="significant",
                     text=richtextval(msg),
                     hidden_uid=generate_uid(),
                     can_hide=False,
                 ))
     if self.context.portal_type == "task":
         if self.context.due_date:
             if is_smaller_deadline_on_parents(
                     self.context, {
                         "task": "due_date",
                         "pstsubaction": "planned_end_date",
                         "pstaction": "planned_end_date",
                         "operationalobjective": "planned_end_date"
                     }):
                 msg = _(
                     u"The deadline of this element is greater than one of its parents"
                 )
                 ret.append(
                     PseudoMessage(
                         msg_type="significant",
                         text=richtextval(msg),
                         hidden_uid=generate_uid(),
                         can_hide=False,
                     ))
         else:
             msg = _(u"The deadline is not fill on this element")
             ret.append(
                 PseudoMessage(
                     msg_type="significant",
                     text=richtextval(msg),
                     hidden_uid=generate_uid(),
                     can_hide=False,
                 ))
     return ret
Beispiel #19
0
    def _checkItemSentBackToServiceWhenEveryAdvicesGiven(
            self,
            item,
            askAdvicesTr,
            availableBackTr,
            returnState,
            askAdvicesTr2=None):
        """Helper method for 'test_subproduct_ItemSentBackToAskerWhenEveryAdvicesGiven'."""
        # save current logged in user, the group asker user
        adviceAskerUserId = self.member.getId()
        # ask advices
        self.do(item, askAdvicesTr)
        # item can be sent back to returnState by creator even if every advices are not given
        self.assertTrue(availableBackTr in self.transitions(item))
        self.assertFalse(_everyAdvicesAreGivenFor(item))

        # now add advice as vendors and do not hide it, advice will be considered given
        self.changeUser('pmReviewer2')
        createContentInContainer(
            item, 'meetingadvice', **{
                'advice_group': self.vendors_uid,
                'advice_type': u'positive',
                'advice_hide_during_redaction': False,
                'advice_comment': richtextval(u'My comment')
            })
        # directly sent back to service
        self.assertEqual(item.query_state(), returnState)
        self.assertTrue(_everyAdvicesAreGivenFor(item))

        # now add advice as vendors and hide it, advice is considered not given
        self.changeUser('siteadmin')
        item.restrictedTraverse('@@delete_givenuid')(item.meetingadvice.UID())
        self.do(item, askAdvicesTr2 or askAdvicesTr)
        self.changeUser('pmReviewer2')
        advice = createContentInContainer(
            item, 'meetingadvice', **{
                'advice_group': self.vendors_uid,
                'advice_type': u'positive',
                'advice_hide_during_redaction': True,
                'advice_comment': richtextval(u'My comment')
            })
        # still waiting advices
        self.assertEqual(item.query_state(),
                         '{0}_waiting_advices'.format(returnState))
        self.assertFalse(_everyAdvicesAreGivenFor(item))
        # if we just change 'advice_hide_during_redaction', advice is given and item's sent back
        advice.advice_hide_during_redaction = False
        notify(ObjectModifiedEvent(advice))
        self.assertEqual(item.query_state(), returnState)
        self.assertTrue(_everyAdvicesAreGivenFor(item))

        # now test with 'asked_again'
        self.changeUser(adviceAskerUserId)
        advice.restrictedTraverse('@@change-advice-asked-again')()
        self.assertEqual(advice.advice_type, 'asked_again')
        self.do(item, askAdvicesTr2 or askAdvicesTr)
        self.changeUser('pmReviewer2')
        notify(ObjectModifiedEvent(advice))
        # still waiting advices
        self.assertEqual(item.query_state(),
                         '{0}_waiting_advices'.format(returnState))
        self.assertFalse(_everyAdvicesAreGivenFor(item))
        # change advice_type, it will be sent back then
        advice.advice_type = u'positive'
        notify(ObjectModifiedEvent(advice))
        self.assertEqual(item.query_state(), returnState)
        self.assertTrue(_everyAdvicesAreGivenFor(item))
Beispiel #20
0
 def __call__(self):
     rendered = self.pt.pt_render(self.namespace)
     return richtextval(rendered)