def setUp(self): self.app = self.layer['app'] self.portal = self.layer['portal'] self.portal_url = self.portal.absolute_url() self.request = self.portal.REQUEST self.catalog = getToolByName(self.portal, 'portal_catalog') self.api_session = RelativeSession(self.portal_url) self.api_session.headers.update({'Accept': 'application/json'}) self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) # /plone/folder self.folder = createContentInContainer(self.portal, u'Folder', id=u'folder', title=u'Some Folder') # /plone/folder/doc self.doc = createContentInContainer( self.folder, u'DXTestDocument', id='doc', title=u'Lorem Ipsum', start=DateTime(1950, 1, 1, 0, 0), effective=DateTime(1995, 1, 1, 0, 0), expires=DateTime(1999, 1, 1, 0, 0), test_int_field=42, test_list_field=['Keyword1', 'Keyword2', 'Keyword3'], test_bool_field=True, test_richtext_field=RichTextValue(raw=u'<p>Some Text</p>', mimeType='text/html', outputMimeType='text/html'), ) IMutableUUID(self.doc).set('77779ffa110e45afb1ba502f75f77777') self.doc.reindexObject() # /plone/folder/other-document self.doc2 = createContentInContainer( self.folder, u'DXTestDocument', id='other-document', title=u'Other Document', description=u'\xdcbersicht', start=DateTime(1975, 1, 1, 0, 0), effective=DateTime(2015, 1, 1, 0, 0), expires=DateTime(2020, 1, 1, 0, 0), test_list_field=['Keyword2', 'Keyword3'], test_bool_field=False, ) # /plone/folder2 self.folder2 = createContentInContainer(self.portal, u'Folder', id=u'folder2', title=u'Another Folder') # /plone/folder2/doc createContentInContainer( self.folder2, u'DXTestDocument', id='doc', title=u'Document in second folder', start=DateTime(1975, 1, 1, 0, 0), effective=DateTime(2015, 1, 1, 0, 0), expires=DateTime(2020, 1, 1, 0, 0), test_bool_field=False, ) # /plone/doc-outside-folder createContentInContainer( self.portal, u'DXTestDocument', id='doc-outside-folder', title=u'Doc outside folder', ) transaction.commit()
def test_MailerXMLAttachments(self): """ Test mailer with dummy_send """ mailer = get_actions(self.ff1)["mailer"] mailer.sendXML = True mailer.sendCSV = False context = get_context(mailer) # Test all dexterity field type listed at https://docs.plone.org/external/plone.app.dexterity/docs/reference/fields.html fields = dict( replyto="*****@*****.**", topic="test subject", richtext=RichTextValue(raw="Raw"), comments=u"test comments😀", datetime=datetime.datetime(2019, 4, 1), date=datetime.date(2019, 4, 2), delta=datetime.timedelta(1), bool=True, number=1981, floating=3.14, tuple=("elemenet1", "element2"), list=[1, 2, 3, 4], map=dict(fruit="apple"), choices=set(["A", "B"]), empty_string="", zero_value=0, none_value=None, empty_tuple=(), empty_list=[], empty_set=set(), empty_map=dict(), ) request = self.LoadRequestForm(**fields) attachments = mailer.get_attachments(fields, request) self.assertEqual(1, len(attachments)) self.assertIn( u"Content-Type: application/xml\nMIME-Version: 1.0\nContent-Transfer-Encoding: base64\nContent-Disposition: attachment", mailer.get_mail_text(fields, request, context), ) name, mime, enc, xml = attachments[0] output_nodes = ( b'<field name="replyto">[email protected]</field>', b'<field name="topic">test subject</field>', b'<field name="richtext">Raw</field>', b'<field name="comments">test comments\xf0\x9f\x98\x80</field>', b'<field name="datetime">2019/04/01, 00:00:00</field>', b'<field name="date">2019/04/02</field>', b'<field name="delta">1 day, 0:00:00</field>', b'<field name="bool">True</field>', b'<field name="number">1981</field>', b'<field name="floating">3.14</field>', b'<field name="tuple">["elemenet1", "element2"]</field>', b'<field name="list">["1", "2", "3", "4"]</field>', b'<field name="map">{"fruit": "apple"}</field>', b'<field name="empty_string" />', b'<field name="zero_value">0</field>', b'<field name="none_value" />', b'<field name="empty_tuple">[]</field>', b'<field name="empty_list">[]</field>', b'<field name="empty_set">[]</field>', b'<field name="empty_map">{}</field>', ) self.assertIn(b"<?xml version='1.0' encoding='utf-8'?>\n<form>", xml) # the order of the nodes can change ... check each line for node in output_nodes: self.assertIn(node, xml) # the order of ["A", "B"] can change ... check separately self.assertIn(b'"A"', xml) self.assertIn(b'"B"', xml)
def testTransformNone(self): from plone.app.textfield.value import RichTextValue value = RichTextValue() # Mostly, these calls simply should not give an error. self.assertEquals(None, value.raw) self.assertEquals(u'', value.output)
def handleApply(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return utils._send_emails = False try: en_folder = self.context.restrictedTraverse('en') if 'organisations' in en_folder: org_folder = en_folder.restrictedTraverse('organisations') else: org_folder = content.create( en_folder, type='osha.hwccontent.organisationfolder', title='Organisations') if 'focalpoints' in en_folder: fop_folder = en_folder.restrictedTraverse('focalpoints') else: fop_folder = content.create( en_folder, type='osha.hwccontent.organisationfolder', title='Focalpoints') type_mapping = { u'Organisation': { 'type': 'osha.hwccontent.organisation', 'schema': dict(getFieldsInOrder(IOrganisation)), 'folder': org_folder, 'wf_actions': ('approve_phase_1', ), }, u'Focalpoint': { 'type': 'osha.hwccontent.focalpoint', 'schema': dict(getFieldsInOrder(IFocalPoint)), 'folder': fop_folder, 'wf_actions': ('publish', ), } } count = 0 for data in json.loads(data['json']): # Only keep the data that's in the main schema: type_info = type_mapping[data['_type']] schema = type_info['schema'] fields = {} if data['title'].startswith('MC-'): continue for name, field in schema.items(): if name in data: value = data[name] if value and INamedImageField.providedBy(field): content_type = data.get('_%s_content_type' % name, '') filename = data.get('_%s_filename' % name, None) value = NamedBlobImage(base64.b64decode(value), str(content_type), filename) elif value and IRichText.providedBy(field): content_type = data.get('_%s_content_type', None) value = RichTextValue(value, mimeType=content_type) elif name.find("email") >= 0: value = value.strip() fields[name] = value new_obj = content.create(container=type_info['folder'], type=type_info['type'], id=data['id'], **fields) for transition in type_info['wf_actions']: try: content.transition(new_obj, transition) except Exception: logger.exception( 'Could not execute %s transition for %s' % (transition, '/'.join(new_obj.getPhysicalPath()))) logger.info('Imported %s' % new_obj.getId()) count += 1 # Set status on this form page self.status = "%s partners imported" % count except Exception: # Enable emails again: utils._send_emails = True raise
def _create_page(self, _id='test-snippet', title='Test Snippet', text='<p>foobar</p>'): page = api.content.create(type='Document', id=_id, title=title, container=self.portal, text=RichTextValue(text, 'text/html', 'text/html')) return page
def encode_after_json(value): """ Is the opposite of decode_for_json """ # there should not be any encoded strings if isinstance(value, str): value = unicode(value) # unicode if isinstance(value, unicode): encoding, nval = unicode(value).split(':', 1) if encoding == u'unicode': return nval else: return nval.encode(encoding) # list, tuple, set elif isinstance(value, list): new_value = map(encode_after_json, value) if len(new_value) == 2 and new_value[0] == 'tuple': return tuple(new_value[1]) elif len(new_value) == 2 and new_value[0] == 'set': return set(new_value[1]) elif len(new_value) == 2 and new_value[0] == 'PersistentList': return PersistentList(new_value[1]) elif len(new_value) == 2 and new_value[0] == 'PersistentMapping': return PersistentMapping(new_value[1]) else: return new_value # OOBTree elif isinstance(value, dict) and \ value.get('utf8:publisher-wrapper', False) \ and value.get('utf8:type', None) == 'utf8:OOBTree': return OOBTree(value.get('utf8:value')) # PortletAssignmentSettings elif isinstance(value, dict) and \ value.get('utf8:publisher-wrapper', False) \ and value.get('utf8:type', None) == \ 'utf8:PortletAssignmentSettings': settings = PortletAssignmentSettings() for key, val in value.get('utf8:value').items(): settings[key] = val return settings # python datetime elif isinstance(value, dict) and \ value.get('publisher-wrapper', False) \ and value.get('type', None) == 'datetime': if value['tzinfo']: tzinfo = timezone(value['tzinfo']) else: tzinfo = None return datetime(*value['timetuple'], tzinfo=tzinfo) # zope datetime elif isinstance(value, dict) and \ value.get('publisher-wrapper', False) \ and value.get('type', None) == 'DateTime': return DateTime(value.get('value')) # RichTextValue elif isinstance(value, dict) and value.get('utf8:publisher-wrapper', False) \ and value.get('utf8:type', None) == 'utf8:RichTextValue': return RichTextValue(**encode_after_json(value['utf8:value'])) # RelationValue elif isinstance(value, dict) and value.get('utf8:publisher-wrapper', False) \ and value.get('utf8:type', None) == 'utf8:RelationValue': data = encode_after_json(value['utf8:data']) obj = get_obj_by_relative_path(data['to_path']) if not obj: # The target object does not exist on the receiver side. # We cannot make a relation at this point. return None rel = create_relation_for(obj) rel.from_attribute = data['from_attribute'] return rel # dicts elif isinstance(value, dict): nval = {} for key, sval in value.items(): key = encode_after_json(key) sval = encode_after_json(sval) nval[key] = sval return nval # other types else: return value
def set_text(obj): if IDexterityContent.providedBy(obj): obj.text = RichTextValue(LOREMIPSUM_HTML_10_PARAGRAPHS, 'text/html', 'text/x-html-safe') else: obj.setText(LOREMIPSUM_HTML_10_PARAGRAPHS)
def test_parseField_value_is_not_none(self): value = RichTextValue(u'foo') diff = CMFDTHtmlDiff(DummyType(value), DummyType(value), 'body') self.assertEqual(diff._parseField(value), [u'foo'])
def test_anon_only(self): # Add folder content setRoles(self.portal, TEST_USER_ID, ('Manager', )) self.portal.invokeFactory('Folder', 'f1') self.portal['f1'].title = u"Folder one" self.portal['f1'].description = u"Folder one description" self.portal['f1'].reindexObject() # Add page content self.portal['f1'].invokeFactory('Document', 'd1') self.portal['f1']['d1'].title = u"Document one" self.portal['f1']['d1'].description = u"Document one description" testText = "Testing... body one" self.portal['f1']['d1'].text = RichTextValue(testText, 'text/plain', 'text/html') self.portal['f1']['d1'].reindexObject() # Publish the folder and page self.portal.portal_workflow.doActionFor(self.portal['f1'], 'publish') self.portal.portal_workflow.doActionFor(self.portal['f1']['d1'], 'publish') # Set pages to have weak caching and test anonymous self.cacheSettings.operationMapping = { 'plone.content.itemView': 'plone.app.caching.weakCaching' } transaction.commit() # View the page as anonymous browser = Browser(self.app) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) self.assertTrue(testText in browser.contents) self.assertEqual('max-age=0, must-revalidate, private', browser.headers['Cache-Control']) # Set pages to have moderate caching so that we can see the difference # between logged in and anonymous self.cacheSettings.operationMapping = { 'plone.content.itemView': 'plone.app.caching.moderateCaching' } self.registry['plone.app.caching.moderateCaching.smaxage'] = 60 self.registry['plone.app.caching.moderateCaching.vary'] = 'X-Anonymous' self.registry['plone.app.caching.moderateCaching.anonOnly'] = True transaction.commit() # View the page as anonymous browser = Browser(self.app) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.moderateCaching', browser.headers['X-Cache-Operation']) self.assertTrue(testText in browser.contents) self.assertEqual('max-age=0, s-maxage=60, must-revalidate', browser.headers['Cache-Control']) self.assertEqual('X-Anonymous', browser.headers['Vary']) self.assertFalse('Etag' in browser.headers) # View the page as logged-in browser = Browser(self.app) browser.addHeader( 'Authorization', 'Basic %s:%s' % ( TEST_USER_NAME, TEST_USER_PASSWORD, )) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.moderateCaching', browser.headers['X-Cache-Operation']) self.assertTrue(testText in browser.contents) self.assertEqual('max-age=0, must-revalidate, private', browser.headers['Cache-Control']) self.assertTrue('Etag' in browser.headers) # Set pages to have strong caching so that we can see the difference # between logged in and anonymous self.cacheSettings.operationMapping = { 'plone.content.itemView': 'plone.app.caching.strongCaching' } self.registry['plone.app.caching.strongCaching.vary'] = 'X-Anonymous' self.registry['plone.app.caching.strongCaching.anonOnly'] = True transaction.commit() # View the page as anonymous browser = Browser(self.app) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.strongCaching', browser.headers['X-Cache-Operation']) self.assertTrue(testText in browser.contents) self.assertEqual('max-age=86400, proxy-revalidate, public', browser.headers['Cache-Control']) self.assertEqual('X-Anonymous', browser.headers['Vary']) self.assertFalse('Etag' in browser.headers) # View the page as logged-in browser = Browser(self.app) browser.addHeader( 'Authorization', 'Basic %s:%s' % ( TEST_USER_NAME, TEST_USER_PASSWORD, )) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.strongCaching', browser.headers['X-Cache-Operation']) self.assertTrue(testText in browser.contents) self.assertEqual('max-age=0, must-revalidate, private', browser.headers['Cache-Control']) self.assertTrue('Etag' in browser.headers) # Check an edge case that has had a problem in the past: # setting strongCaching maxage to zero. self.registry['plone.app.caching.strongCaching.maxage'] = 0 self.registry['plone.app.caching.strongCaching.smaxage'] = 60 transaction.commit() # View the page as anonymous browser = Browser(self.app) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('max-age=0, s-maxage=60, must-revalidate', browser.headers['Cache-Control'])
def add_resolveuid(context): story_brains = api.content.find(portal_type="story") count = 0 for brain in story_brains: story = brain.getObject() # A broken text field contains an <img> tag with class="image-inline caption" \ # and src attribute does not contain 'resolveuid' #example: <p><img src="200803-PH-covid-inside.jpg" class="image-inline captioned" /></p> if story.text is None: continue soup = BeautifulSoup(story.text.raw, "html.parser") images = soup.findAll('img', class_="image-inline") changed = False story_path = '/'.join(story.getPhysicalPath()) logger.info(f"processing {story_path}") for image in images: if 'resolveuid' not in image['src']: #we found a broken one. #get uid of image: #handle image scale - ex: 'foo.jpeg/@@images/image/thumb' image_split = image['src'].split('@@images') image_id = image_split[0] if len(image_split) > 1: image_scale = image_split[1] else: image_scale = None try: image_object = context.unrestrictedTraverse(story_path + '/' + image_id) except zExceptions.NotFound: logger.warning("couldn't find image: " + story_path + '/' + image_id) continue except KeyError: logger.warning(f"image doesn't exist: {image_id}") continue except IndexError: #string index out of range logger.warning(f"Couldn't fix image at: " + story_path + '/' + image_id) #Honestly don't know why this happens continue uuid = IUUID(image_object) #replace <img> src with 'resolveuid/{uuid}' if image_scale is not None: image['src'] = f'resolveuid/{uuid}/@@images/{image_scale}' else: image['src'] = f'resolveuid/{uuid}' changed = True if changed: count = count + 1 new = RichTextValue(str(soup), story.text.mimeType, story.text.outputMimeType) story.text = new logger.info("fixed " + '/'.join(story.getPhysicalPath())) if count >= 100: transaction.commit() count = 0 transaction.commit() logger.info("Done")
def workspaces_spec(context): now = localized_now() budget_proposal_filename = u'budget-proposal.png' budget_proposal_path = os.path.join('images', budget_proposal_filename) budget_proposal_img = NamedBlobImage( data=context.openDataFile(budget_proposal_path).read(), filename=budget_proposal_filename) minutes_filename = u'minutes.docx' minutes_path = os.path.join('files', minutes_filename) minutes_file = NamedBlobImage( data=context.openDataFile(minutes_path).read(), filename=minutes_filename) tomorrow = (now + timedelta(days=1)).replace(hour=9, minute=0, second=0, microsecond=0) next_month = (now + timedelta(days=30)).replace(hour=9, minute=0, second=0, microsecond=0) # Create workspaces workspaces = [ { 'title': 'Open Market Committee', 'description': 'The OMC holds eight regularly scheduled meetings ' 'during the year and other meetings as needed.', 'transition': 'make_private', 'participant_policy': 'publishers', 'members': { 'allan_neece': [u'Members'], 'christian_stoney': [u'Admins', u'Members'], 'neil_wichmann': [u'Members'], 'francois_gast': [u'Members'], 'jamie_jacko': [u'Members'], 'jesse_shaik': [u'Members'], 'jorge_primavera': [u'Members'], 'silvio_depaoli': [u'Members'], 'lance_stockstill': [u'Members'], 'pearlie_whitby': [u'Members'], 'dollie_nocera': [u'Members'], 'esmeralda_claassen': [u'Members'], 'rosalinda_roache': [u'Members'], 'guy_hackey': [u'Members'], }, 'contents': [{ 'title': 'Manage Information', 'type': 'Folder', 'contents': [ { 'title': 'Preparation of Records', 'description': 'How to prepare records', 'state': 'published', 'subject': 'Read carefully', 'type': 'File', }, { 'title': 'Public bodies reform', 'description': 'Making arrangements for the transfer of ' 'information, records and knowledge is a ' 'key part of any Machinery of Government ' 'change.', 'type': 'Document', 'state': 'published' }, { 'title': 'Repurchase Agreements', 'description': 'A staff presentation outlined several ' 'approaches to raising shortterm interest ' 'rates when it becomes appropriate to do ' 'so, and to controlling the level of ' 'short-term interest rates ', 'owner': 'allan_neece', 'type': 'Document' }, { 'title': u'Budget Proposal', 'description': (u'A diagram of the factors impacting the budget and ' u'results'), 'owner': 'allan_neece', 'image': budget_proposal_img, 'type': 'Image', }, { 'title': u'Minutes', 'owner': 'allan_neece', 'description': u'Meeting Minutes', 'file': minutes_file, 'type': 'File', }, { 'title': u'Minutes Overview', 'owner': 'allan_neece', 'description': u'Meeting Minutes Overview', 'type': 'Document', 'modification_date': now - timedelta(days=60), }, { 'title': 'Open Market Day', 'type': 'Event', 'state': 'published', 'start': tomorrow, 'end': tomorrow + timedelta(hours=8) }, { 'title': 'Plone Conf', 'type': 'Event', 'state': 'published', 'start': next_month, 'end': next_month + timedelta(days=3, hours=8) }, { 'title': "Yesterday's gone", 'type': 'Event', 'state': 'published', 'owner': 'allan_neece', 'start': tomorrow - timedelta(days=3), 'end': tomorrow - timedelta(days=2) }, ] }, { 'title': 'Projection Materials', 'type': 'Folder', 'contents': [{ 'title': 'Projection Material', 'type': 'File' }] }, { 'title': 'Future Event', 'type': 'Event', 'start': now + timedelta(days=7), 'end': now + timedelta(days=14) }, { 'title': 'Past Event', 'type': 'Event', 'start': now + timedelta(days=-7), 'end': now + timedelta(days=-14) }, { 'title': 'Files for application 2837', 'type': 'ploneintranet.workspace.mail', 'mail_from': u'*****@*****.**', 'mail_to': ( u'*****@*****.**', u'*****@*****.**', ), 'mail_body': RichTextValue(u''' <p>Dear mister Kolbach,</p> <p>We’ll process your application with the shortest delay.</p> <p>Yours sincerely, <br> Alexander Pilz</p> <blockquote> <p>Dear Sir or Madam,</p> <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p> <p>Kind regards,<br> Cornelis G. A. Kolbach</p> </blockquote> '''), 'contents': [ { 'title': 'Budget proposal', 'type': 'Image', 'image': budget_proposal_img, }, { 'title': u'Minutes', 'owner': 'allan_neece', 'description': u'Meeting Minutes', 'file': minutes_file, 'type': 'File', }, ] }], }, { 'title': 'Parliamentary papers guidance', 'description': '"Parliamentary paper" is a term used to describe a ' 'document which is laid before Parliament. Most ' 'government organisations will produce at least one ' 'parliamentary paper per year.', 'transition': 'make_private', 'participant_policy': 'producers', 'members': { 'allan_neece': [u'Members'], 'christian_stoney': [u'Admins', u'Members'], 'francois_gast': [u'Members'], 'jamie_jacko': [u'Members'], 'fernando_poulter': [u'Members'], 'jesse_shaik': [u'Members'], 'jorge_primavera': [u'Members'], 'silvio_depaoli': [u'Members'], 'kurt_weissman': [u'Members'], 'esmeralda_claassen': [u'Members'], 'rosalinda_roache': [u'Members'], 'guy_hackey': [u'Members'], }, 'contents': [{ 'title': 'Test Document', 'description': 'A document just for testing', 'type': 'Document' }] }, { 'title': u'Shareholder information', 'description': u'"Shareholder information" contains all documents, ' u'papers and diagrams for keeping shareholders informed about the ' u'current state of affairs.', 'transition': 'make_private', 'participant_policy': 'consumers', 'members': { 'allan_neece': [u'Members'], 'christian_stoney': [u'Admins', u'Members'], 'francois_gast': [u'Members'], 'jamie_jacko': [u'Members'], 'fernando_poulter': [u'Members'], 'jesse_shaik': [u'Members'], 'jorge_primavera': [u'Members'], 'silvio_depaoli': [u'Members'], 'kurt_weissman': [u'Members'], 'esmeralda_claassen': [u'Members'], 'rosalinda_roache': [u'Members'], 'guy_hackey': [u'Members'], }, 'contents': [{ 'title': 'Test Document', 'description': 'A document just for testing', 'type': 'Document', 'state': 'published' }] }, { 'title': u'Service announcements', 'description': u'Public service announcements can be found here.', 'transition': 'make_open', 'participant_policy': 'consumers', 'members': { 'allan_neece': [u'Members'], 'christian_stoney': [u'Admins', u'Members'], 'francois_gast': [u'Members'], 'jamie_jacko': [u'Members'], 'fernando_poulter': [u'Members'], 'jesse_shaik': [u'Members'], 'jorge_primavera': [u'Members'], 'silvio_depaoli': [u'Members'], 'kurt_weissman': [u'Members'], 'esmeralda_claassen': [u'Members'], 'rosalinda_roache': [u'Members'], 'guy_hackey': [u'Members'], }, 'contents': [ { 'title': 'Terms and conditions', 'description': 'A document just for testing', 'type': 'Document', 'state': 'published' }, { 'title': 'Customer satisfaction survey', 'description': 'A private document', 'type': 'Document' }, ] }, ] return workspaces
def addMail(self, mailString): """ Store mail as news item Returns created item """ pw = self.context.portal_workflow (header, body) = splitMail(mailString) # if 'keepdate' is set, get date from mail, # XXX 'time' is unused if self.getValueFor('keepdate'): timetuple = rfc822.parsedate_tz(header.get('date')) time = DateTime(rfc822.mktime_tz(timetuple)) # ... take our own date, clients are always lying! else: time = DateTime() (TextBody, ContentType, HtmlBody, Attachments) = unpackMail(mailString) # Test Zeitangabe hinter Subject today = date.today() mydate = today.strftime("%d.%m.%Y") # let's create the news item subject = mime_decode_header(header.get('subject', 'No Subject')) sender = mime_decode_header(header.get('from', 'No From')) title = "%s" % (subject) new_id = IUserPreferredURLNormalizer(self.request).normalize(title) id = self._findUniqueId(new_id) # ContentType is only set for the TextBody if ContentType: body = TextBody else: body = self.HtmlToText(HtmlBody) # XXX als vorlaeufige Loesung from zope.component import getMultiAdapter plone_view = getMultiAdapter((self.context, self.request), name='plone') desc = plone_view.cropText(body, 60) body = '\n'.join([wrap_line(line) for line in body.splitlines()]) uni_aktuell_body = ("<p><strong>%s: %s</strong></p> " "<p> </p><pre>%s</pre>" % (mydate, sender, body)) objid = self.context.invokeFactory( 'News Item', id=id, title=title, text=RichTextValue(uni_aktuell_body), description=desc, ) mailObject = getattr(self.context, objid) images = [ att for att in Attachments if att['maintype'] == 'image' and att['filename'] ] if images and hasattr(mailObject, 'image'): image = Attachments[0] mailObject.image = NamedBlobImage( filename=safe_unicode(image['filename']), data=image['filebody'], ) try: pw.doActionFor(mailObject, 'publish') except Exception as e: log.exception(e) return mailObject
def test_GetSpecificAssemblyFor(self): """ This method aimed to ease printings should return formated assembly """ self.changeUser('pmManager') m1 = self._createMeetingWithItems() m1.assembly = RichTextValue( 'Pierre Dupont - Bourgmestre,\n' 'Charles Exemple - 1er Echevin,\n' 'Echevin Un, Echevin Deux, Echevin Trois - Echevins,\n' 'Jacqueline Exemple, Responsable du CPAS') attendee = '<p class="mltAssembly">Pierre Dupont - Bourgmestre,<br />' \ 'Charles Exemple - 1er Echevin,<br />Echevin Un, Echevin Deux, ' \ 'Echevin Trois - Echevins,<br />Jacqueline Exemple, Responsable du CPAS</p>' self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='')[0], attendee) self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='Absent'), '') self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='Excus'), '') m1.assembly = RichTextValue( 'Pierre Dupont - Bourgmestre,\n' 'Charles Exemple - 1er Echevin,\n' 'Echevin Un, Echevin Deux, Echevin Trois - Echevins,\n' 'Jacqueline Exemple, Responsable du CPAS \n' 'Excusés: \n ' 'Monsieur x, Mesdames Y et Z') self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='')[0], attendee) self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='Absent'), '') self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='Excus')[0], 'Excusés:') self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='Excus')[1], '<p class="mltAssembly">Monsieur x, Mesdames Y et Z</p>') m1.assembly = RichTextValue( 'Pierre Dupont - Bourgmestre,\n' 'Charles Exemple - 1er Echevin,\n' 'Echevin Un, Echevin Deux, Echevin Trois - Echevins,\n' 'Jacqueline Exemple, Responsable du CPAS \n' 'Absent: \n ' 'Monsieur tartenpion \n' 'Excusés: \n ' 'Monsieur x, Mesdames Y et Z') self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='')[0], attendee) self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='Absent')[0], 'Absent:') self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='Absent')[1], '<p class="mltAssembly">Monsieur tartenpion</p>') self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='Excus')[0], 'Excusés:') self.assertEqual( self.tool.adapted().getSpecificAssemblyFor(m1.get_assembly(), startTxt='Excus')[1], '<p class="mltAssembly">Monsieur x, Mesdames Y et Z</p>')
def set(self, instance, value, **kw): from plone.app.textfield.value import RichTextValue value = RichTextValue(raw=value, outputMimeType=self.field.output_mime_type) return self._set(instance, value, **kw)
def setUp(self): """Construct sample contents. These are all events: 'Long Event: 2013-04-25T10:00:00+02:00 - 2013-06-04T10:00:00+02:00' 'Past Event: 2013-04-25T00:00:00+02:00 - 2013-04-25T23:59:59+02:00' 'Past Event: 2013-04-26T00:00:00+02:00 - 2013-04-26T23:59:59+02:00' 'Past Event: 2013-04-27T00:00:00+02:00 - 2013-04-27T23:59:59+02:00' 'Now Event: 2013-05-05T10:00:00+02:00 - 2013-05-05T11:00:00+02:00' 'Now Event: 2013-05-07T10:00:00+02:00 - 2013-05-07T11:00:00+02:00' 'Now Event: 2013-05-09T10:00:00+02:00 - 2013-05-09T11:00:00+02:00' 'Future Event: 2013-05-15T10:00:00+02:00 - 2013-05-15T11:00:00+02:00' """ self.portal = self.layer['portal'] self.app = self.layer['app'] self.request = self.layer['request'] set_browserlayer(self.request) set_timezone(TEST_TIMEZONE) now, past, future, far, duration = self.make_dates() setRoles(self.portal, TEST_USER_ID, ['Manager']) workflow = getToolByName(self.portal, 'portal_workflow') workflow.setDefaultChain("simple_publication_workflow") factory = self.event_factory self.past_event = factory(container=self.portal, id='past', title=u'Past Event', start=past, end=past + duration, location=u"Vienna", whole_day=True, recurrence='RRULE:FREQ=DAILY;COUNT=3') workflow.doActionFor(self.past_event, 'publish') # adjust start and end according to whole_day and open_end self.past_event.reindexObject() self.now_event = factory( container=self.portal, id='now', title=u'Now Event', start=now, end=now + duration, location=u"Vienna", recurrence="""RRULE:FREQ=DAILY;COUNT=3;INTERVAL=1 RDATE:20130509T000000 EXDATE:20130506T000000,20140404T000000""", contact_name='Auto Testdriver', contact_email='*****@*****.**', contact_phone='+123456789', event_url='http://plone.org', subject=('plone', 'testing')) # change to subjects, once this is # fixed: # https://github.com/plone/plone.dexterity/pull/18 # https://github.com/plone/plone.app.dexterity/issues/118 workflow.doActionFor(self.now_event, 'publish') self.now_event.reindexObject() self.future_event = factory( container=self.portal, id='future', title=u'Future Event', text=RichTextValue( u'Überraschung! Du kannst nach mir suchen', 'text/plain', 'text/html', ), start=future, end=future + duration, location=u'Graz') workflow.doActionFor(self.future_event, 'publish') self.future_event.reindexObject() self.portal.invokeFactory('Folder', 'sub', title=u'sub') self.long_event = factory(container=self.portal.sub, id='long', title=u'Long Event', start=past, end=far, location=u'Schaftal') workflow.doActionFor(self.long_event, 'publish') self.long_event.reindexObject() # plone.app.contenttypes ICollection type self.portal.invokeFactory('Collection', 'collection', title=u'Col') collection = self.portal.collection collection.sort_on = u'start' collection.reverse_sort = True collection.query = [ { 'i': 'portal_type', 'o': 'plone.app.querystring.operation.selection.any', 'v': ['Event', 'plone.app.event.dx.event'] }, ] collection.reindexObject()
def test_composite_views(self): catalog = self.portal['portal_catalog'] default_skin = self.portal['portal_skins'].default_skin # Add folder content setRoles(self.portal, TEST_USER_ID, ('Manager',)) self.portal.invokeFactory('Folder', 'f1') self.portal['f1'].title = u"Folder one" self.portal['f1'].description = u"Folder one description" self.portal['f1'].reindexObject() # Add page content self.portal['f1'].invokeFactory('Document', 'd1') self.portal['f1']['d1'].title = u"Document one" self.portal['f1']['d1'].description = u"Document one description" testText = "Testing... body one" self.portal['f1']['d1'].text = RichTextValue( testText, 'text/plain', 'text/html' ) self.portal['f1']['d1'].reindexObject() # Publish the folder and page self.portal.portal_workflow.doActionFor(self.portal['f1'], 'publish') self.portal.portal_workflow.doActionFor(self.portal['f1']['d1'], 'publish') # Should we set up the etag components? # - set member? No # - reset catalog counter? Maybe # - set server language? # - turn on gzip? # - set skin? Maybe # - leave status unlocked # - set the mod date on the resource registries? Probably. import transaction; transaction.commit() # Request the quthenticated folder now = stable_now() browser = Browser(self.app) browser.addHeader('Authorization', 'Basic %s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD,)) browser.open(self.portal['f1'].absolute_url()) self.assertEqual('plone.content.folderView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) # This should use cacheInBrowser self.assertEqual('max-age=0, must-revalidate, private', browser.headers['Cache-Control']) self.assertEqual('"|test_user_1_|%d|en|0|%s|0|0' % (catalog.getCounter(), default_skin), _normalize_etag(browser.headers['ETag'])) self.assertTrue(now > dateutil.parser.parse(browser.headers['Expires'])) # Set the copy/cut cookie and then request the folder view again browser.cookies.create('__cp', 'xxx') browser.open(self.portal['f1'].absolute_url()) # The response should be the same as before except for the etag self.assertEqual('plone.content.folderView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) self.assertEqual('max-age=0, must-revalidate, private', browser.headers['Cache-Control']) self.assertEqual('"|test_user_1_|%d|en|0|%s|0|1' % (catalog.getCounter(), default_skin), _normalize_etag(browser.headers['ETag'])) # Request the authenticated page now = stable_now() browser = Browser(self.app) browser.addHeader('Authorization', 'Basic %s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD,)) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertTrue(testText in browser.contents) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) # This should use cacheInBrowser self.assertEqual('max-age=0, must-revalidate, private', browser.headers['Cache-Control']) self.assertEqual('"|test_user_1_|%d|en|0|%s|0' % (catalog.getCounter(), default_skin), _normalize_etag(browser.headers['ETag'])) self.assertTrue(now > dateutil.parser.parse(browser.headers['Expires'])) # Request the authenticated page again -- to test RAM cache. browser = Browser(self.app) browser.addHeader('Authorization', 'Basic %s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD,)) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) # Authenticated should NOT be RAM cached self.assertEqual(None, browser.headers.get('X-RAMCache')) # Request the authenticated page again -- with an INM header to test 304 etag = browser.headers['ETag'] browser = Browser(self.app) browser.raiseHttpErrors = False # we really do want to see the 304 browser.addHeader('Authorization', 'Basic %s:%s' % (TEST_USER_NAME, TEST_USER_PASSWORD,)) browser.addHeader('If-None-Match', etag) browser.open(self.portal['f1']['d1'].absolute_url()) # This should be a 304 response self.assertEqual('304 Not Modified', browser.headers['Status']) self.assertEqual('', browser.contents) # Request the anonymous folder now = stable_now() browser = Browser(self.app) browser.open(self.portal['f1'].absolute_url()) self.assertEqual('plone.content.folderView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) # This should use cacheInBrowser self.assertEqual('max-age=0, must-revalidate, private', browser.headers['Cache-Control']) self.assertEqual('"||%d|en|0|%s|0|0' % (catalog.getCounter(), default_skin), _normalize_etag(browser.headers['ETag'])) self.assertTrue(now > dateutil.parser.parse(browser.headers['Expires'])) # Request the anonymous page now = stable_now() browser = Browser(self.app) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) self.assertTrue(testText in browser.contents) # This should use cacheInBrowser self.assertEqual('max-age=0, must-revalidate, private', browser.headers['Cache-Control']) self.assertEqual('"||%d|en|0|%s|0' % (catalog.getCounter(), default_skin), _normalize_etag(browser.headers['ETag'])) self.assertTrue(now > dateutil.parser.parse(browser.headers['Expires'])) # Request the anonymous page again -- to test RAM cache. # Anonymous should be RAM cached now = stable_now() browser = Browser(self.app) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) # This should come from RAM cache self.assertEqual('plone.app.caching.operations.ramcache', browser.headers['X-RAMCache']) self.assertTrue(testText in browser.contents) self.assertEqual('max-age=0, must-revalidate, private', browser.headers['Cache-Control']) self.assertEqual('"||%d|en|0|%s|0'% (catalog.getCounter(), default_skin), _normalize_etag(browser.headers['ETag'])) self.assertTrue(now > dateutil.parser.parse(browser.headers['Expires'])) # Request the anonymous page again -- with an INM header to test 304. etag = browser.headers['ETag'] browser = Browser(self.app) browser.raiseHttpErrors = False browser.addHeader('If-None-Match', etag) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) # This should be a 304 response self.assertEqual('304 Not Modified', browser.headers['Status']) self.assertEqual('', browser.contents) # Edit the page to update the etag testText2 = "Testing... body two" self.portal['f1']['d1'].text = RichTextValue( testText2, 'text/plain', 'text/html' ) self.portal['f1']['d1'].reindexObject() transaction.commit() # Request the anonymous page again -- to test expiration of 304 and RAM. etag = browser.headers['ETag'] browser = Browser(self.app) browser.addHeader('If-None-Match', etag) browser.open(self.portal['f1']['d1'].absolute_url()) self.assertEqual('plone.content.itemView', browser.headers['X-Cache-Rule']) self.assertEqual('plone.app.caching.weakCaching', browser.headers['X-Cache-Operation']) # The etag has changed so we should get a fresh page. self.assertEqual(None, browser.headers.get('X-RAMCache')) self.assertEqual('200 Ok', browser.headers['Status'])
def __call__(self): request = self.request courseUID = request.form.get('id', '') course = api.content.find(portal_type='Course', UID=courseUID, sort_on='getObjPositionInParent') if len(course) == 1: teacher_uid = self.request.cookies.get("teacher_login", "") teacher = api.content.get(UID=teacher_uid) if not teacher: return self.request.response.redirect( '{}/teacher-area/teacher-login'.format( self.context.portal_url())) self.teacher = teacher self.course = course[0] if self.course.course_teacher != self.teacher.UID(): return self.request.response.redirect( '{}/teacher-area/teacher-area'.format( self.context.portal_url())) prepareUIDList = [item.UID for item in self.getPrepare()] if request.form.has_key('file-upload-widget'): course_outline = request.get('course_outline', '') if course_outline: alsoProvides(self.request, IDisableCSRFProtection) self.course.getObject().course_outline = RichTextValue( course_outline) for uid in prepareUIDList: item = api.content.get(UID=uid) url = item.absolute_url() upload_file = request.form['file-' + uid] upload_text = request.form['text-' + uid] headers = { 'Accept': "application/json", 'Content-Type': "application/json", 'Authorization': "Basic YWRtaW46MTIzNDU2", } data = {"description": upload_text} file_data = upload_file.read() if file_data: data.update( { \ "file": { \ "content-type": upload_file.headers['content-type'], \ "filename": upload_file.filename, \ "encoding": "base64", \ "data": file_data.encode('base64') \ } \ } \ ) response = requests.request("PATCH", url, headers=headers, json=data) self.request.response.redirect(self.request.URL) return self.template() else: return self.request.response.redirect( '{}/teacher-area/teacher-area'.format( self.context.portal_url()))
def setUp(self): self.app = self.layer["app"] self.portal = self.layer["portal"] self.portal_url = self.portal.absolute_url() self.request = self.portal.REQUEST self.catalog = getToolByName(self.portal, "portal_catalog") self.api_session = RelativeSession(self.portal_url) self.api_session.headers.update({"Accept": "application/json"}) self.api_session.auth = (SITE_OWNER_NAME, SITE_OWNER_PASSWORD) # /plone/folder self.folder = createContentInContainer(self.portal, u"Folder", id=u"folder", title=u"Some Folder") # /plone/folder/doc self.doc = createContentInContainer( self.folder, u"DXTestDocument", id="doc", title=u"Lorem Ipsum", start=DateTime(1950, 1, 1, 0, 0), effective=DateTime(1995, 1, 1, 0, 0), expires=DateTime(1999, 1, 1, 0, 0), test_int_field=42, test_list_field=["Keyword1", "Keyword2", "Keyword3"], test_bool_field=True, test_richtext_field=RichTextValue( raw=u"<p>Some Text</p>", mimeType="text/html", outputMimeType="text/html", ), ) IMutableUUID(self.doc).set("77779ffa110e45afb1ba502f75f77777") self.doc.reindexObject() # /plone/folder/other-document self.doc2 = createContentInContainer( self.folder, u"DXTestDocument", id="other-document", title=u"Other Document", description=u"\xdcbersicht", start=DateTime(1975, 1, 1, 0, 0), effective=DateTime(2015, 1, 1, 0, 0), expires=DateTime(2020, 1, 1, 0, 0), test_list_field=["Keyword2", "Keyword3"], test_bool_field=False, ) # /plone/folder2 self.folder2 = createContentInContainer(self.portal, u"Folder", id=u"folder2", title=u"Another Folder") # /plone/folder2/doc createContentInContainer( self.folder2, u"DXTestDocument", id="doc", title=u"Document in second folder", start=DateTime(1975, 1, 1, 0, 0), effective=DateTime(2015, 1, 1, 0, 0), expires=DateTime(2020, 1, 1, 0, 0), test_bool_field=False, ) # /plone/doc-outside-folder createContentInContainer( self.portal, u"DXTestDocument", id="doc-outside-folder", title=u"Doc outside folder", ) transaction.commit()
def dexterity_save(self, fieldname, text): from plone.app.textfield.value import RichTextValue value = RichTextValue(text) setattr(self.context, fieldname, value) return "saved"
def text(self, value): self.context.text = RichTextValue(raw=safe_unicode(value))
def text(self, value): behavior = IEventSummary(self.context) behavior.text = RichTextValue(raw=safe_unicode(value))
def creatItem(folder, row, zipFolderName): portal = api.portal.get() logger.info('Begin Create Content, %s' % safe_unicode(row['title'])) if row['listPrice'] and row['salePrice'] and row['standardShippingCost']: pass else: logger.error('Lost data, title:%s, please check "listPirce, saleprice, standardShippingCost"' % row['title']) message = _(u"Lost data, title:%s, please check 'listPirce, saleprice, standardShippingCost'") api.portal.show_message(message=message, request=folder.REQUEST, type='error') item = api.content.create( type='Product', title=row['title'], productId=row['productId'], description=row['description'], productUrl=row['productUrl'], inStock=True if row['inStock'].strip().lower() == 'y' else False, brand=row['brand'], listPrice=int(row['listPrice']), salePrice=int(row['salePrice']), standardShippingCost=int(row['standardShippingCost']), container=portal['products'][folder.id], ) logger.info('Content Created, %s' % safe_unicode(row['title'])) item.setSubject(tuple(row['subjects'].split(','))) if row['image_1'].strip(): with open('%s/%s' % (zipFolderName, safe_unicode(row['image_1'].strip()))) as file: item.image_1 = namedfile.NamedBlobImage(data=file, filename=safe_unicode('%s' % file.name.split('/')[-1])) try: if row['image_2'].strip(): with open('%s/%s' % (zipFolderName, safe_unicode(row['image_2'].strip()))) as file: item.image_2 = namedfile.NamedBlobImage(data=file, filename=safe_unicode('%s' % file.name.split('/')[-1])) except: logger.error('creatItem position 1, title:%s' % title) pass try: if row['image_3'].strip(): with open('%s/%s' % (zipFolderName, safe_unicode(row['image_3'].strip()))) as file: item.image_3 = namedfile.NamedBlobImage(data=file, filename=safe_unicode('%s' % file.name.split('/')[-1])) except: logger.error('creatItem position 2, title:%s' % title) pass try: if row['image_4'].strip(): with open('%s/%s' % (zipFolderName, safe_unicode(row['image_4'].strip()))) as file: item.image_4 = namedfile.NamedBlobImage(data=file, filename=safe_unicode('%s' % file.name.split('/')[-1])) except: logger.error('creatItem position 3, title:%s' % title) pass try: if row['image_5'].strip(): with open('%s/%s' % (zipFolderName, safe_unicode(row['image_5'].strip()))) as file: item.image_5 = namedfile.NamedBlobImage(data=file, filename=safe_unicode('%s' % file.name.split('/')[-1])) except: logger.error('creatItem position 4, title:%s' % title) pass item.promotionalText = RichTextValue(safe_unicode(row['promotionalText'])) item.reindexObject() transaction.commit() logger.info('Commit OK, %s' % safe_unicode(row['title']))
'normal', 'min_allowable_score': 0, 'max_allowable_score': 10, 'general_help': RichTextValue(u""" <ol> <li>First think, then write. It can be helpful to scribble some rough ideas on a piece of paper and quietly reflect on whether they make sense before starting to type into a screen that is much more formal. </li> <li>Revise. Do not try to write the perfect text in the first round. Rather, plan to go back and revise. Really good texts are rewritten several times before they become that good. You are no exception, especially if you are just getting started. Revisiting your text after some time or having it read by others can work miracles to improve your text. </li> <li>Practical tips for writing in Plone. In the sections of the ResearchVee in addition to text you can add a broad range of different types of content like tables, images, links, just like on any Plone page you write. </li> </ul>"""), 'assessment_schema': RichTextValue(u""" <p>How well does the solution fulfill the tasks laid out for that section? This is a scale that reviewers and instructors and authors use to assess the quality of an entry:</p> <table class="listing">
def addDemoData(context): ''' ''' if isNotMeetingCommunesDemoProfile(context): return site = context.getSite() tool = api.portal.get_tool('portal_plonemeeting') cfg = tool.objectValues('MeetingConfig')[0] wfTool = api.portal.get_tool('portal_workflow') pTool = api.portal.get_tool('plone_utils') mTool = api.portal.get_tool('portal_membership') # first we need to be sure that our IPoneMeetingLayer is set correctly # https://dev.plone.org/ticket/11673 from zope.event import notify from zope.traversing.interfaces import BeforeTraverseEvent notify(BeforeTraverseEvent(site, site.REQUEST)) # we will create elements for some users, make sure their personal # area is correctly configured # first make sure the 'Members' folder exists members = mTool.getMembersFolder() if members is None: _createObjectByType('Folder', site, id='Members') mTool.createMemberArea('agentPers') mTool.createMemberArea('agentInfo') mTool.createMemberArea('agentCompta') # create 5 meetings : 2 passed, 1 current and 2 future today = datetime.now() dates = [ today - timedelta(days=13), today - timedelta(days=6), today + timedelta(days=1), today + timedelta(days=8), today + timedelta(days=15) ] # items dict here : the key is the user we will create the item for # we use item templates so content is created for the demo items = { 'agentPers': ( { 'templateId': 'template3', 'title': u'Engagement temporaire d\'un informaticien', 'budgetRelated': True, 'review_state': 'validated', }, { 'templateId': 'template2', 'title': u'Contrôle médical de Mr Antonio', 'budgetRelated': False, 'review_state': 'proposed', }, { 'templateId': 'template2', 'title': u'Contrôle médical de Mlle Debbeus', 'budgetRelated': False, 'review_state': 'proposed', }, { 'templateId': 'template2', 'title': u'Contrôle médical de Mme Hanck', 'budgetRelated': False, 'review_state': 'validated', }, { 'templateId': 'template4', 'title': u'Prestation réduite Mme Untelle, instritutrice maternelle', 'budgetRelated': False, 'review_state': 'validated', }, ), 'agentInfo': ( { 'templateId': 'template5', 'title': u'Achat nouveaux serveurs', 'budgetRelated': True, 'review_state': 'validated', }, { 'templateId': 'template5', 'title': u'Marché public, contestation entreprise Untelle SA', 'budgetRelated': False, 'review_state': 'validated', }, ), 'agentCompta': ( { 'templateId': 'template5', 'title': u'Présentation budget 2014', 'budgetRelated': True, 'review_state': 'validated', }, { 'templateId': 'template5', 'title': u'Plainte de Mme Daise, taxe immondice', 'budgetRelated': False, 'review_state': 'validated', }, { 'templateId': 'template5', 'title': u'Plainte de Mme Uneautre, taxe piscine', 'budgetRelated': False, 'review_state': 'proposed', }, ), 'dgen': ( { 'templateId': 'template1', 'title': u'Tutelle CPAS : point 1 BP du 15 juin', 'budgetRelated': False, 'review_state': 'created', }, { 'templateId': 'template5', 'title': u'Tutelle CPAS : point 2 BP du 15 juin', 'budgetRelated': False, 'review_state': 'proposed', }, { 'templateId': 'template5', 'title': u'Tutelle CPAS : point 16 BP du 15 juin', 'budgetRelated': True, 'review_state': 'validated', }, ), } # login as 'dgen' mTool.createMemberArea('dgen') for cfg in tool.objectValues('MeetingConfig'): # cleanMemoize so ToolPloneMeeting.getMeetingConfig returns the correct MeetingConfig cleanMemoize(site) secrFolder = tool.getPloneMeetingFolder(cfg.getId(), 'dgen') # build attendees and signatories passed to Meeting._doUpdateContacts # attendees OrderedDict([('uid1', 'attendee'), ('uid2', 'attendee'), ('uid3', 'absent')]) # signatories {'uid1': '1'} attendees = OrderedDict() signatories = {} for hp_uid in cfg.getOrderedContacts(): attendees[hp_uid] = 'attendee' signatories = {attendees.keys()[1]: '1', attendees.keys()[0]: '2'} # create meetings for date in dates: meetingId = secrFolder.invokeFactory(cfg.getMeetingTypeName(), id=date.strftime('%Y%m%d'), date=date) meeting = getattr(secrFolder, meetingId) pTool.changeOwnershipOf(meeting, 'dgen') meeting._do_update_contacts(attendees=attendees, signatories=signatories) # -13 meeting is closed if date == today - timedelta(days=13): wfTool.doActionFor(meeting, 'freeze') wfTool.doActionFor(meeting, 'decide') wfTool.doActionFor(meeting, 'close') # -6 meeting is frozen if date == today - timedelta(days=6): wfTool.doActionFor(meeting, 'freeze') wfTool.doActionFor(meeting, 'decide') meeting.reindexObject() for item in meeting.get_items(): pTool.changeOwnershipOf(item, 'dgen') # create items for userId in items: userFolder = tool.getPloneMeetingFolder(cfg.getId(), userId) for item in items[userId]: # get the template then clone it template = getattr( tool.getMeetingConfig(userFolder).itemtemplates, item['templateId']) with api.env.adopt_user(username=userId): tool.invalidateAllCache() newItem = template.clone( newOwnerId=userId, destFolder=userFolder, newPortalType=cfg.getItemTypeName()) newItem.setTitle(item['title']) newItem.setBudgetRelated(item['budgetRelated']) if item['review_state'] == 'proposed': wfTool.doActionFor(newItem, 'propose') if item['review_state'] == 'validated': wfTool.doActionFor(newItem, 'validate') # add annexe and advice for one item in College if item['templateId'] == 'template3' and cfg.id == 'meeting-config-college': cpt = 1 annexes_config_root = get_config_root(newItem) for annexType in ('annexe', 'annexe', 'annexeBudget', 'annexeCahier'): annex_title = u'CV Informaticien N°2016-%s' % (cpt) annex_file = namedfile.NamedBlobFile( 'Je suis le contenu du fichier', filename=u'CV-0%s.txt' % (cpt)) annexTypeId = calculate_category_id( annexes_config_root.get(annexType)) annex_id = normalize_name(site.REQUEST, annex_title) api.content.create(container=newItem, id=annex_id, type='annex', title=annex_title, file=annex_file, content_category=annexTypeId, to_print=False, confidential=False) cpt += 1 newItem.setOptionalAdvisers( ('{0}__rowid__unique_id_003'.format( org_id_to_uid('dirfin')), org_id_to_uid('informatique'))) newItem.at_post_create_script() createContentInContainer( newItem, 'meetingadvice', **{ 'advice_group': org_id_to_uid('informatique'), 'advice_type': u'positive', 'advice_comment': RichTextValue(SAMPLE_TEXT), 'advice_observations': RichTextValue() }) if item['templateId'] == 'template5' and cfg.id == 'meeting-config-college': newItem.setOptionalAdvisers((org_id_to_uid('dirgen'), )) newItem.at_post_create_script() createContentInContainer( newItem, 'meetingadvice', **{ 'advice_group': org_id_to_uid('dirgen'), 'advice_type': u'negative', 'advice_comment': RichTextValue(SAMPLE_TEXT), 'advice_observations': RichTextValue(SAMPLE_TEXT) }) newItem.reindexObject() # adapt some parameters for config cfg.setAnnexToPrintMode('enabled_for_info')
def test_getSize(self): from plone.app.textfield.value import RichTextValue value = RichTextValue(u'\u2603') self.assertEqual(3, value.getSize())
def set_field_value(self, uid, field, value, field_type): """Set field value with a specific type XXX: Only dexterity fields are supported """ pc = getToolByName(self, 'portal_catalog') results = pc.unrestrictedSearchResults(UID=uid) obj = results[0]._unrestrictedGetObject() if field_type == 'float': value = float(value) if field_type == 'int': value = int(value) if field_type == 'list': value = eval(value) if field_type.startswith('datetime'): # field_type must begin with 'datetime' # followed by optional format 'datetime%Y%m%d%H%M' # without format: %Y%m%d%H%M is used field_type = field_type[8:] fmt = field_type and field_type or '%Y%m%d%H%M' value = datetime.strptime(value, fmt) if field_type.startswith('date'): # field_type must begin with 'date' # followed by optional format 'date%Y%m%d' # without format: %Y%m%d is used field_type = field_type[4:] fmt = field_type and field_type or '%Y%m%d' value = datetime.strptime(value, fmt).date() if field_type == 'reference' and HAS_DEXTERITY_RELATIONS: results_referenced = pc.unrestrictedSearchResults(UID=value) referenced_obj = results_referenced[0]._unrestrictedGetObject() intids = getUtility(IIntIds) referenced_obj_intid = intids.getId(referenced_obj) value = RelationValue(referenced_obj_intid) if field_type == 'references' and HAS_DEXTERITY_RELATIONS: values = eval(value) intids = getUtility(IIntIds) value = [] for uid in values: results_referenced = pc.unrestrictedSearchResults(UID=uid) referenced_obj = results_referenced[ 0]._unrestrictedGetObject() referenced_obj_intid = intids.getId(referenced_obj) value.append(RelationValue(referenced_obj_intid)) if field_type == 'text/html': value = RichTextValue(value, 'text/html', 'text/html') obj.text = value if field_type == 'file': pdf_file = os.path.join(os.path.dirname(__file__), 'content', u'file.pdf') value = NamedBlobFile(data=open(pdf_file, 'r').read(), contentType='application/pdf', filename=u'file.pdf') if field_type == 'image': image_file = os.path.join(os.path.dirname(__file__), u'image.jpg') value = NamedBlobImage(data=open(image_file, 'r').read(), contentType='image/jpg', filename=u'image.jpg') setattr(obj, field, value) obj.reindexObject() notify(ObjectModifiedEvent(obj))
def test_MailerCSVAttachments(self): """ Test mailer with dummy_send """ mailer = get_actions(self.ff1)["mailer"] mailer.sendXML = False mailer.sendCSV = True context = get_context(mailer) # Test all dexterity field type listed at https://docs.plone.org/external/plone.app.dexterity/docs/reference/fields.html fields = dict( topic="test subject", replyto="*****@*****.**", richtext=RichTextValue(raw="Raw"), comments=u"test comments😀", datetime=datetime.datetime(2019, 4, 1), date=datetime.date(2019, 4, 2), delta=datetime.timedelta(1), bool=True, number=1981, floating=3.14, tuple=("elemenet1", "element2"), list=[1, 2, 3, 4], map=dict(fruit="apple"), choices=set(["A", "B"]), empty_string="", zero_value=0, none_value=None, empty_tuple=(), empty_list=[], empty_set=set(), empty_map=dict(), ) request = self.LoadRequestForm(**fields) attachments = mailer.get_attachments(fields, request) self.assertEqual(1, len(attachments)) self.assertIn( u"Content-Type: application/csv\nMIME-Version: 1.0\nContent-Transfer-Encoding: base64\nContent-Disposition: attachment", mailer.get_mail_text(fields, request, context), ) name, mime, enc, csv = attachments[0] output = ( b"*****@*****.**", b"test subject", b"Raw", b"test comments\xf0\x9f\x98\x80", b"2019/04/01, 00:00:00", b"2019/04/02", b"1 day, 0:00:00", b"True", b"1981", b"3.14", b'[""elemenet1"", ""element2""]', b'[""1"", ""2"", ""3"", ""4""]', b'{""fruit"": ""apple""}', b"", b"0", b"", b"[]", b"[]", b"[]", b"{}", ) # the order of the columns can change ... check each # TODO should really have a header row for value in output: self.assertIn(value, csv) # the order of [""A"", ""B""] can change ... check separately self.assertIn(b'""A""', csv) self.assertIn(b'""B""', csv)
def __getattribute__(self, name): if name.startswith('_') or name.startswith( 'portal_') or name.startswith('@@') or name == 'sql_id': return super(SQLDexterityItem, self).__getattribute__(name) connection = queryUtility(ISQLConnectionsUtility, name=self.portal_type, default=None) if connection == None and self.portal_type: fti = queryUtility(IDexterityFTI, name=self.portal_type, default=None) if not fti: return None updateConnectionsForFti(fti) connection = queryUtility(ISQLConnectionsUtility, name=self.portal_type, default=None) if name == 'view': #be sure session and sqlitem are up to date self._v_sql_item = None connection.session.close() if not connection: return super(SQLDexterityItem, self).__getattribute__(name) if name == 'UID' and self.sql_virtual: return self.portal_type + '-' + connection.sql_table + '-' + str( self.sql_id) if name == 'id' and 'id' not in connection.fieldnames.keys(): if not self.sql_virtual: return super(SQLDexterityItem, self).__getattribute__(name) fti = ISQLTypeSettings( getUtility(IDexterityFTI, name=self.portal_type)) nameFromTitle = INameFromTitle(self, None) if nameFromTitle is not None and nameFromTitle.title: sql_folder_id = getattr(fti, 'sql_folder_id', 'data-' + self.portal_type) title = nameFromTitle.title folder = None if IRelationValue.providedBy(sql_folder_id): folder = sql_folder_id.to_object elif sql_folder_id and sql_folder_id.startswith('/'): portal = getToolByName(getSite(), 'portal_url').getPortalObject() folder = portal.restrictedTraverse(sql_folder_id) if folder: name = INameChooser(folder).chooseName(title, self) return name # return INameChooser(getSite()).chooseName(title, self) # return getUtility(IURLNormalizer).normalize(title) return self.sql_id if name in connection.fieldnames.keys(): sql_column = connection.fieldnames[name] sql_item = self.getSQLItem() try: sql_id = getattr(sql_item, connection.sql_id_column, None) except orm_exc.DetachedInstanceError: self._v_sql_item = None sql_item = self.getSQLItem() sql_id = getattr(sql_item, connection.sql_id_column, None) fieldname = 'name' if sql_item and sql_column: while '.' in sql_column: sql_key = sql_column.split('.')[0] sql_item = getattr(sql_item, sql_key, None) if isinstance(sql_item, list): value = sql_item fieldname = sql_column.split('.')[-1] break sql_column = '.'.join(sql_column.split('.')[1:]) else: if not isinstance(sql_item, list): value = getattr(sql_item, sql_column, None) if not value and (isinstance(value, list) or hasattr(value, '_sa_instance_state')): value = '' elif (isinstance(value, list) or hasattr(value, '_sa_instance_state')): sqlftis = [ a for a in getAllUtilitiesRegisteredFor(IDexterityFTI) if 'collective.behavior.sql.behavior.behaviors.ISQLContent' in a.behaviors and getattr(a, 'sql_table', None) ] if name == 'subject': return tuple( [getattr(a, fieldname, '') for a in value]) tableftis = [] for iface in iterSchemataForType(self.portal_type): if name in iface.names(): field = iface[name] if IRelationChoice.providedBy( field) or IRelationList.providedBy(field): if IRelationChoice.providedBy(field): allowed_types = field.source.query.get( 'portal_type', []) else: allowed_types = field.value_type.source.query.get( 'portal_type', []) tableftis = [] for sqlfti in sqlftis: adapted = ISQLTypeSettings(sqlfti, None) if isinstance(value, list): classname = value[0].__class__.__name__ else: classname = value.__class__.__name__ if adapted and getattr( adapted, 'sql_table', None) == classname: if not allowed_types or sqlfti.id in allowed_types: tableftis.append(adapted) catalog = getToolByName( getSite(), 'portal_catalog') relations = [] for tablefti in tableftis: sql_id_column = getattr( tablefti, 'sql_id_column', 'id') valueids = [] if isinstance(value, list): valueids = [ getattr(a, sql_id_column, None) for a in value if getattr(a, sql_id_column, None) ] else: valueids = getattr( value, sql_id_column, None) valueids = [str(a) for a in valueids] brains = catalog.unrestrictedSearchResults( portal_type=tablefti.id, sql_id=valueids) for brain in brains: relations.append( SQLRelationValue( brain.portal_type, brain.UID, self)) if IRelationChoice.providedBy( field) and relations: return relations[0] elif IRelationList.providedBy( field) and relations: return relations elif ITuple.providedBy(field): return tuple( [getattr(a, fieldname, '') for a in value]) elif IList.providedBy(field): return [ getattr(a, fieldname, '') for a in value ] elif value and isinstance(value, list): value = getattr(value[0], fieldname, '') for iface in iterSchemataForType(self.portal_type): if name == 'subject': try: return tuple([ a.decode('utf-8') for a in literal_eval(value) ]) except: return tuple([a.strip() for a in value.split(',')]) if name in iface.names(): field = iface[name] if IRichText.providedBy(field): if not value: return '' if not '<p' in value or not '<br' in value: value = '<p>' + '</p><p>'.join([ a for a in value.split('\n') if a.strip() ]) + '</p>' # try: # value = str(value) # except: # try: # value = value.decode('utf-8') # except: # try: # value = value.encode('utf-8') # except: # pass return RichTextValue(unidecode(value)) elif INamedBlobImage.providedBy(field): return NamedBlobImage( base64.b64decode(value), filename=unicode(self.portal_type + self.id + ".jpg")) elif ITuple.providedBy(field): if not value: return tuple([]) try: return tuple([ a.decode('utf-8') for a in literal_eval(value) ]) except: return tuple( [a.strip() for a in value.split(',')]) elif IList.providedBy(field): if not value: return [] try: return [ a.decode('utf-8') for a in literal_eval(value) ] except: return [a.strip() for a in value.split(',')] elif IDatetime.providedBy(field) and hasattr( value, 'day') and not hasattr(value, 'hour'): value = datetime.datetime.combine( value, datetime.datetime.min.time()) if name in [ 'expiration_date', 'effective_date', 'effective', 'expires' ] and hasattr(value, 'day') and not hasattr(value, 'hour'): value = datetime.datetime.combine( value, datetime.datetime.min.time()) if isinstance(value, unicode) or name == 'id': try: value = str(value) except: pass return value return super(SQLDexterityItem, self).__getattribute__(name)
def import_content(self): username = getattr(self.context, 'username', None) if username: try: data = self.get_publications_json(username) except: pass else: if data and isinstance(data, (list, tuple)): publications = [] for __ in data: _ = __.get('attributes', {}) contributors = [ "%s, %s" % ( x.get('last_name', ''), x.get('first_name', ''), ) for x in _.get('contributors', []) if x.get('last_name', '') ] try: published_on = localize( DateTime("%s 00:00:00 US/Eastern" % _['published_on'])) except: published_on = None abstract = _.get('abstract', None) if abstract: abstract = RichTextValue( raw=abstract, mimeType=u'text/html', outputMimeType='text/x-html-safe') publications.append({ 'ai_id': __.get('id', None), 'title': _.get('title', None), 'doi': _.get('doi', None), 'journal_title': _.get('journal_title', None), 'published_on': published_on, 'abstract': abstract, 'contributors': contributors, }) self.context.publications = self.sort_filter(publications) self.context.reindexObject() transaction.commit() self.log(u"Imported %d publications for %s" % (len(publications), username))
def _deserialize(cls, data): return RichTextValue(raw=data['raw'], mimeType=data['mimeType'], outputMimeType=data['outputMimeType'], encoding=data['encoding'])