diff --git a/setup.py b/setup.py index 69f12cd..2666142 100644 --- a/setup.py +++ b/setup.py @@ -70,6 +70,7 @@ "souper.plone", "z3c.form", "z3c.jbot", + "defusedcsv", ], extras_require={ "test": [ diff --git a/src/rer/ufficiostampa/browser/configure.zcml b/src/rer/ufficiostampa/browser/configure.zcml index 250ba2f..40f167d 100644 --- a/src/rer/ufficiostampa/browser/configure.zcml +++ b/src/rer/ufficiostampa/browser/configure.zcml @@ -11,6 +11,7 @@ package="z3c.jbot" file="meta.zcml" /> + + + + + + + - - - Giunta Regionale - Agenzia di informazione e comunicazione - - - - N. ${comunicato_number} - - - Date - - - - All'attenzione dei Capi redattori - - - ${title} + \ No newline at end of file diff --git a/src/rer/ufficiostampa/interfaces/settings.py b/src/rer/ufficiostampa/interfaces/settings.py index c67a0a4..6408140 100644 --- a/src/rer/ufficiostampa/interfaces/settings.py +++ b/src/rer/ufficiostampa/interfaces/settings.py @@ -18,6 +18,30 @@ class IRerUfficiostampaSettings(model.Schema): required=False, ) + email_from_name = schema.TextLine( + title=_( + "email_from_name_label", + default="Email from name", + ), + description=_( + "email_from_name_help", + default="Insert the name of the sender for emails.", + ), + required=True, + ) + + email_from_address = schema.TextLine( + title=_( + "email_from_address_label", + default="Email from address", + ), + description=_( + "email_from_address_help", + default="Insert the email address of the sender for emails.", + ), + required=True, + ) + subscription_channels = schema.List( title=_("subscription_channels_label", default="Subscription Channels"), description=_( @@ -82,7 +106,7 @@ class IRerUfficiostampaSettings(model.Schema): "css_styles_help", default="Insert a list of CSS styles for received emails.", ), - required=True, + required=False, ) comunicato_number = schema.Int( title=_( @@ -141,3 +165,11 @@ class ILegislaturesRowSchema(model.Schema): class IUfficioStampaControlPanel(IControlpanel): """Control panel for Ufficio Stampa settings.""" + + +class IUfficioStampaManageChannels(IControlpanel): + """Schema for managing subscription channels.""" + + +class IUfficioStampaManageHistory(IControlpanel): + """Schema for managing subscription channels.""" diff --git a/src/rer/ufficiostampa/profiles/default/controlpanel.xml b/src/rer/ufficiostampa/profiles/default/controlpanel.xml index 05ac5c6..ef9e868 100644 --- a/src/rer/ufficiostampa/profiles/default/controlpanel.xml +++ b/src/rer/ufficiostampa/profiles/default/controlpanel.xml @@ -1,20 +1,46 @@ + rer.ufficiostampa: Manage Channels + + + + rer.ufficiostampa: Manage Channels + + rer.ufficiostampa: Manage Channels - + + \ No newline at end of file diff --git a/src/rer/ufficiostampa/profiles/default/metadata.xml b/src/rer/ufficiostampa/profiles/default/metadata.xml index 6413f75..98aa693 100644 --- a/src/rer/ufficiostampa/profiles/default/metadata.xml +++ b/src/rer/ufficiostampa/profiles/default/metadata.xml @@ -1,6 +1,6 @@ - 1400 + 2000 profile-souper.plone:default diff --git a/src/rer/ufficiostampa/profiles/uninstall/controlpanel.xml b/src/rer/ufficiostampa/profiles/uninstall/controlpanel.xml index f7b45d4..ecc0e08 100644 --- a/src/rer/ufficiostampa/profiles/uninstall/controlpanel.xml +++ b/src/rer/ufficiostampa/profiles/uninstall/controlpanel.xml @@ -10,4 +10,16 @@ title="Configurazione Ufficio Stampa" > + + + + diff --git a/src/rer/ufficiostampa/restapi/services/common.py b/src/rer/ufficiostampa/restapi/services/common.py index e1487eb..e08bcad 100644 --- a/src/rer/ufficiostampa/restapi/services/common.py +++ b/src/rer/ufficiostampa/restapi/services/common.py @@ -1,5 +1,6 @@ from copy import deepcopy from datetime import datetime +from defusedcsv import csv from io import StringIO from plone.protect.interfaces import IDisableCSRFProtection from plone.restapi.batching import HypermediaBatch @@ -14,7 +15,6 @@ from zope.interface import implementer from zope.publisher.interfaces import IPublishTraverse -import csv import logging @@ -66,7 +66,6 @@ def parse_query(self): class DataCSVGet(DataGet): def render(self): - data = self.get_data() if isinstance(data, dict): if data.get("error", False): @@ -77,7 +76,7 @@ def render(self): message="Unable export. Contact site manager.", ) ) - self.request.response.setHeader("Content-Type", "text/comma-separated-values") + self.request.response.setHeader("Content-Type", "text/csv") now = datetime.now() self.request.response.setHeader( "Content-Disposition", @@ -85,14 +84,15 @@ def render(self): type=self.type, date=now.strftime("%d%m%Y-%H%M%S") ), ) - self.request.response.write(data) + return data + # self.request.response.write(data) def get_data(self): + """get data for csv export""" tool = getUtility(self.store) query = self.parse_query() sbuf = StringIO() rows = [] - for item in tool.search(**query): data = {} for k, v in item.attrs.items(): @@ -100,11 +100,13 @@ def get_data(self): continue if isinstance(v, list): v = ", ".join(v) - if isinstance(v, int): + elif isinstance(v, int): v = str(v) - if v: - v = json_compatible(v) - v = v.encode("utf-8") + elif isinstance(v, datetime): + v = v.strftime("%Y-%m-%d %H:%M:%S") + # if v: + # v = json_compatible(v) + # v = v.encode("utf-8") data[k] = v rows.append(data) writer = csv.DictWriter(sbuf, fieldnames=self.columns, delimiter=",") @@ -179,6 +181,7 @@ class DataUpdate(TraversableService): def reply(self): alsoProvides(self.request, IDisableCSRFProtection) + if not self.id: raise BadRequest("Missing id") @@ -201,11 +204,12 @@ def reply(self): class DataDelete(TraversableService): def reply(self): - alsoProvides(self.request, IDisableCSRFProtection) - if not self.id: + form_data = json_body(self.request) + if not self.id and not form_data.get("id"): raise BadRequest("Missing id") + alsoProvides(self.request, IDisableCSRFProtection) tool = getUtility(self.store) - res = tool.delete(id=self.id) + res = tool.delete(id=self.id, ids=form_data.get("id")) if not res: return self.reply_no_content() if res.get("error", "") == "NotFound": diff --git a/src/rer/ufficiostampa/restapi/services/send_complete/configure.zcml b/src/rer/ufficiostampa/restapi/services/send_complete/configure.zcml index 2a4f6d1..f20ec93 100644 --- a/src/rer/ufficiostampa/restapi/services/send_complete/configure.zcml +++ b/src/rer/ufficiostampa/restapi/services/send_complete/configure.zcml @@ -4,12 +4,17 @@ xmlns:zcml="http://namespaces.zope.org/zcml" > - + + diff --git a/src/rer/ufficiostampa/restapi/services/send_complete/post.py b/src/rer/ufficiostampa/restapi/services/send_complete/post.py index 8afff7c..304b58c 100644 --- a/src/rer/ufficiostampa/restapi/services/send_complete/post.py +++ b/src/rer/ufficiostampa/restapi/services/send_complete/post.py @@ -1,64 +1,66 @@ -from datetime import datetime -from plone.protect.interfaces import IDisableCSRFProtection -from plone.restapi.deserializer import json_body -from plone.restapi.services import Service -from rer.ufficiostampa.interfaces import ISendHistoryStore -from zope.component import getUtility -from zope.interface import alsoProvides +# UNUSED -import logging +# from datetime import datetime +# from plone.protect.interfaces import IDisableCSRFProtection +# from plone.restapi.deserializer import json_body +# from plone.restapi.services import Service +# from rer.ufficiostampa.interfaces import ISendHistoryStore +# from zope.component import getUtility +# from zope.interface import alsoProvides +# import logging -logger = logging.getLogger(__name__) +# logger = logging.getLogger(__name__) -class SendCompletePost(Service): - def reply(self): - data = json_body(self.request) - send_uid = data.get("send_uid", None) - error = data.get("error", False) +# class SendCompletePost(Service): +# def reply(self): +# data = json_body(self.request) - if not send_uid: - self.request.response.setStatus(400) - return dict( - error=dict(type="BadRequest", message='Missing "send_uid" parameter') - ) - # Disable CSRF protection - alsoProvides(self.request, IDisableCSRFProtection) +# send_uid = data.get("send_uid", None) +# error = data.get("error", False) - tool = getUtility(ISendHistoryStore) - try: - tool = getUtility(ISendHistoryStore) - res = tool.update( - id=int(send_uid), - data={ - "completed_date": datetime.now(), - "status": error and "error" or "success", - }, - ) - except Exception as e: - logger.exception(e) - self.request.response.setStatus(500) - return dict(error=dict(type="InternalServerError", message=e.message)) - if res and "error" in res: - if res["error"] == "NotFound": - self.request.response.setStatus(500) - return dict( - error=dict( - type="InternalServerError", - message='Send history "{uid}" not found in "{title}".'.format( # noqa - uid=send_uid, title=self.context.title - ), - ) - ) - else: - self.request.response.setStatus(500) - return dict( - error=dict( - type="InternalServerError", - message="Unable to update end date. See application log for more details", # noqa - ) - ) - self.request.response.setStatus(204) - return +# if not send_uid: +# self.request.response.setStatus(400) +# return dict( +# error=dict(type="BadRequest", message='Missing "send_uid" parameter') +# ) +# # Disable CSRF protection +# alsoProvides(self.request, IDisableCSRFProtection) + +# tool = getUtility(ISendHistoryStore) +# try: +# tool = getUtility(ISendHistoryStore) +# res = tool.update( +# id=int(send_uid), +# data={ +# "completed_date": datetime.now(), +# "status": error and "error" or "success", +# }, +# ) +# except Exception as e: +# logger.exception(e) +# self.request.response.setStatus(500) +# return dict(error=dict(type="InternalServerError", message=e.message)) +# if res and "error" in res: +# if res["error"] == "NotFound": +# self.request.response.setStatus(500) +# return dict( +# error=dict( +# type="InternalServerError", +# message='Send history "{uid}" not found in "{title}".'.format( # noqa +# uid=send_uid, title=self.context.title +# ), +# ) +# ) +# else: +# self.request.response.setStatus(500) +# return dict( +# error=dict( +# type="InternalServerError", +# message="Unable to update end date. See application log for more details", # noqa +# ) +# ) +# self.request.response.setStatus(204) +# return diff --git a/src/rer/ufficiostampa/restapi/services/send_form/configure.zcml b/src/rer/ufficiostampa/restapi/services/send_form/configure.zcml index 3d31972..1bcc9f1 100644 --- a/src/rer/ufficiostampa/restapi/services/send_form/configure.zcml +++ b/src/rer/ufficiostampa/restapi/services/send_form/configure.zcml @@ -13,4 +13,13 @@ name="@send-comunicato-schema" /> + + diff --git a/src/rer/ufficiostampa/restapi/services/send_form/post.py b/src/rer/ufficiostampa/restapi/services/send_form/post.py new file mode 100644 index 0000000..6b45bc0 --- /dev/null +++ b/src/rer/ufficiostampa/restapi/services/send_form/post.py @@ -0,0 +1,462 @@ +from datetime import datetime +from email.message import EmailMessage +from plone import api +from plone.api.exc import InvalidParameterError +from plone.protect.interfaces import IDisableCSRFProtection +from plone.restapi.deserializer import json_body +from plone.restapi.services import Service +from rer.ufficiostampa import _ +from rer.ufficiostampa.interfaces import ISendHistoryStore +from rer.ufficiostampa.interfaces import ISubscriptionsStore +from rer.ufficiostampa.interfaces.settings import IRerUfficiostampaSettings +from rer.ufficiostampa.utils import decode_token +from rer.ufficiostampa.utils import get_site_title +from rer.ufficiostampa.utils import mail_from +from rer.ufficiostampa.utils import prepare_email_message +from smtplib import SMTPException +from zExceptions import BadRequest +from zope.component import getUtility +from zope.interface import alsoProvides +from zope.schema.interfaces import IVocabularyFactory + +import logging + + +logger = logging.getLogger(__name__) + + +class SendComunicato(Service): + def reply(self): + # TODO: use rer.ufficiostampa.browser.send.ISendForm + alsoProvides(self.request, IDisableCSRFProtection) + data = json_body(self.request) + rcpts = self.get_subscribers(data=data) + if not rcpts: + raise BadRequest( + _( + "empty_subscribers", + default="You need to provide at least one email address or channel.", # noqa + ) + ) + + # if errors: + # self.status = self.formErrorsMessage + # return + self.sendMessage(data=data) + + def get_value_from_settings(self, field): + try: + return api.portal.get_registry_record( + field, interface=IRerUfficiostampaSettings + ) + except (KeyError, InvalidParameterError): + return None + + def get_subscribers(self, data): + channels = data.get("channels", []) + subscribers = set() + tool = getUtility(ISubscriptionsStore) + vocab = getUtility( + IVocabularyFactory, name="rer.ufficiostampa.vocabularies.channels" + ) + for channel in channels: + try: + channel = vocab(self.context).getTermByToken(channel).value + except LookupError: + continue + records = tool.search(query={"channels": channel}) + subscribers.update([x.attrs.get("email", "").lower() for x in records]) + subscribers.update([x.lower() for x in data.get("additional_addresses", [])]) + return sorted(list(subscribers)) + + def sendMessage(self, data): + external_sender_url = self.get_value_from_settings(field="external_sender_url") + body = prepare_email_message( + context=self.context, + template="@@send_mail_template", + parameters={ + "notes": data.get("notes", ""), + "site_title": get_site_title(), + "date": datetime.now(), + # ??? perchè qui si usano i folder, poi nell'invio si usano gli attachments ? + "folders": self.get_folders_attachments(), + }, + ) + if external_sender_url: + return self.send_external(data=data, body=body) + else: + return self.send_internal(data=data, body=body) + + def get_folders_attachments(self): + # if self.context.portal_type == "InvitoStampa": + # return [] + return self.context.listFolderContents( + contentFilter={"portal_type": ["Folder"]} + ) + + # TODO: move to utility ? + def send_internal(self, data, body): + subscribers = self.get_subscribers(data) + encoding = api.portal.get_registry_record( + "plone.email_charset", default="utf-8" + ) + msg = EmailMessage() + msg.set_content(body) + msg["Subject"] = self.subject + msg["From"] = mail_from() + msg["Reply-To"] = mail_from() + msg.replace_header("Content-Type", 'text/html; charset="utf-8"') + + self.manage_attachments(data=data, msg=msg) + host = api.portal.get_tool(name="MailHost") + msg["Bcc"] = ", ".join(subscribers) + + # log start + send_id = self.set_history_start(data=data, subscribers=len(subscribers)) + + try: + host.send(msg, charset=encoding) + except (SMTPException, RuntimeError) as e: + logger.exception(e) + # self.add_send_error_message() + self.update_history(send_id=send_id, status="error") + raise BadRequest(_("Errore non previsto durante l'invio del comunicato")) + # api.portal.show_message( + # message=_( + # "success_send_mail", + # default="Send complete.", + # ), + # request=self.request, + # type="info", + # ) + + if send_id: + self.update_history(send_id=send_id, status="success") + + def manage_attachments(self, data, msg): + attachments = self.get_attachments(data=data) + for attachment in attachments: + msg.add_attachment( + attachment["data"], + maintype=attachment["content_type"], + subtype=attachment["content_type"], + filename=attachment["filename"], + ) + + def get_attachments(self, data): + attachments = [] + for uid in data.get("attachments", []): + item = api.content.get(UID=uid) + if not item: + continue + if item.portal_type == "Image": + field = item.image + elif item.portal_type == "File": + field = item.file + else: + raise BadRequest(_("Invalid attachment type")) + attachments.append( + { + "data": field.data, + "filename": field.filename, + "content_type": item.content_type(), + } + ) + return attachments + + @property + def subject(self): + value = "{type}: {title}".format( + type=self.context.portal_type == "ComunicatoStampa" + and "Comunicato Regione" # noqa + or "Invito Regione", # noqa + title=self.context.title, + ) + return value + + @property + def type_name(self): + types_tool = api.portal.get_tool(name="portal_types") + return types_tool.getTypeInfo(self.context.portal_type).title + + # TODO: move to utility ? + def set_history_start(self, data, subscribers): + # if it's a preview, do not store infos + if not data.get("channels", []): + return "" + # mark as sent + self.context.message_sent = True + tool = getUtility(ISendHistoryStore) + intid = tool.add( + { + "type": self.type_name, + "title": self.context.Title(), + "number": getattr(self.context, "comunicato_number", ""), + "url": self.context.absolute_url(), + "recipients": subscribers, + "channels": data.get("channels", []), + "status": "sending", + } + ) + return intid + + # TODO: move to utility ? + def update_history(self, send_id, status): + tool = getUtility(ISendHistoryStore) + res = tool.update( + id=send_id, + data={"completed_date": datetime.now(), "status": status}, + ) + if res and "error" in res: + logger.error( + 'Unable to update history with id "{}": {}'.format( + send_id, res["error"] + ) + ) + + +# from datetime import datetime +# from DateTime import DateTime +# from plone import api +# from plone import schema +# from plone.memoize.view import memoize +# from plone.registry.interfaces import IRegistry +# from requests.exceptions import ConnectionError +# from requests.exceptions import Timeout +# from rer.ufficiostampa import _ +# from rer.ufficiostampa.utils import get_site_title +# from rer.ufficiostampa.utils import mail_from +# from rer.ufficiostampa.utils import prepare_email_message +# from smtplib import SMTPException +# from z3c.form import button +# from z3c.form import field +# from z3c.form import form +# from z3c.form.browser.checkbox import CheckBoxFieldWidget +# from z3c.form.interfaces import ActionExecutionError +# from zope.component import getMultiAdapter +# from zope.interface import Interface +# from zope.interface import Invalid +# from zope.interface import provider +# from zope.schema.interfaces import IContextAwareDefaultFactory +# from zope.schema.interfaces import IVocabularyFactory +# from email.message import EmailMessage + +# import json +# import logging +# import requests + + +# logger = logging.getLogger(__name__) + + +# def check_emails(value): +# """Check that all values are valid email addresses""" +# reg_tool = api.portal.get_tool(name="portal_registration") +# for address in value: +# if not reg_tool.isValidEmail(address): +# raise Invalid( +# _( +# "validation_invalid_email", +# default="Invalid email address: ${address}", +# mapping={"address": address}, +# ) +# ) +# return True + + +# class SendForm(form.Form): +# description = _( +# "send_form_help", +# "Send this Comunicato or Invito to a list of recipients.", +# ) +# ignoreContext = True +# fields = field.Fields(ISendForm) +# fields["channels"].widgetFactory = CheckBoxFieldWidget +# fields["attachments"].widgetFactory = CheckBoxFieldWidget + +# @property +# def label(self): +# types_tool = api.portal.get_tool(name="portal_types") +# return _( +# "send_form_title", +# "Send ${type}", +# mapping={"type": types_tool.getTypeInfo(self.context.portal_type).title}, +# ) + +# @button.buttonAndHandler(_("send_button", default="Send")) +# def handleSave(self, action): +# data, errors = self.extractData() +# if not self.get_subscribers(data=data): +# raise ActionExecutionError( +# Invalid( +# _( +# "empty_subscribers", +# default="You need to provide at least one email address or channel.", # noqa +# ) +# ) +# ) +# if errors: +# self.status = self.formErrorsMessage +# return +# return self.sendMessage(data=data) + +# @button.buttonAndHandler(_("cancel_button", default="Cancel"), name="cancel") +# def handleCancel(self, action): +# api.portal.show_message( +# message=_( +# "cancel_action", +# default="Action cancelled", +# ), +# type="info", +# request=self.request, +# ) +# return self.request.response.redirect(self.context.absolute_url()) + + +# @property +# @memoize +# def subject(self): +# value = "{type}: {title}".format( +# type=self.context.portal_type == "ComunicatoStampa" +# and "Comunicato Regione" # noqa +# or "Invito Regione", # noqa +# title=self.context.title, +# ) +# return value + + +# def get_attachments_external(self, data): +# attachments = [] +# for item_id in data.get("attachments", []): +# item = self.context.get(item_id, None) +# if not item: +# continue +# field = item.portal_type == "Image" and item.image or item.file +# attachments.append( +# ( +# field.filename, +# (field.filename, field.open(), item.content_type()), +# ) +# ) +# return attachments + +# def manage_attachments(self, data, msg): +# attachments = self.get_attachments(data=data) +# for attachment in attachments: +# msg.add_attachment( +# attachment["data"], +# maintype=attachment["content_type"], +# subtype=attachment["content_type"], +# filename=attachment["filename"], +# ) + +# def add_send_error_message(self): +# api.portal.show_message( +# message=_( +# "error_send_mail", +# default="Error sending mail. Contact site administrator.", +# ), +# request=self.request, +# type="error", +# ) + +# # main methods + +# def send_internal(self, data, body): +# portal = api.portal.get() +# overview_controlpanel = getMultiAdapter( +# (portal, self.request), name="overview-controlpanel" +# ) +# if overview_controlpanel.mailhost_warning(): +# return {"error": "MailHost is not configured."} +# subscribers = self.get_subscribers(data) +# registry = getUtility(IRegistry) +# encoding = registry.get("plone.email_charset", "utf-8") + +# msg = EmailMessage() +# msg.set_content(body) +# msg["Subject"] = self.subject +# msg["From"] = mail_from() +# msg["Reply-To"] = mail_from() +# msg.replace_header("Content-Type", 'text/html; charset="utf-8"') + +# self.manage_attachments(data=data, msg=msg) +# host = api.portal.get_tool(name="MailHost") +# msg["Bcc"] = ", ".join(subscribers) +# send_id = self.set_history_start(data=data, subscribers=len(subscribers)) + +# try: +# host.send(msg, charset=encoding) +# except (SMTPException, RuntimeError) as e: +# logger.exception(e) +# self.add_send_error_message() +# self.update_history(send_id=send_id, status="error") +# return +# api.portal.show_message( +# message=_( +# "success_send_mail", +# default="Send complete.", +# ), +# request=self.request, +# type="info", +# ) + +# if send_id: +# self.update_history(send_id=send_id, status="success") + +# def send_external(self, data, body): +# frontend_url = self.get_value_from_settings(field="frontend_url") +# external_sender_url = self.get_value_from_settings(field="external_sender_url") + +# channel_url = api.portal.get().absolute_url() +# if frontend_url: +# channel_url = frontend_url +# subscribers = self.get_subscribers(data) +# send_uid = self.set_history_start(data=data, subscribers=len(subscribers)) + +# payload = { +# "channel_url": channel_url, +# "subscribers": subscribers, +# "subject": self.subject, +# "mfrom": mail_from(), +# "text": body, +# "send_uid": send_uid, +# } + +# params = {"url": external_sender_url} +# attachments = self.get_attachments_external(data) +# if attachments: +# params["data"] = payload +# params["files"] = self.get_attachments_external(data) +# else: +# params["data"] = json.dumps(payload) +# params["headers"] = {"Content-Type": "application/json"} + +# try: +# response = requests.post(**params) +# except (ConnectionError, Timeout) as e: +# logger.exception(e) +# self.add_send_error_message() +# if send_uid: +# self.update_history(send_id=send_uid, status="error") +# return +# if response.status_code != 200: +# logger.error( +# 'Unable to send "{message}": {reason}'.format( # noqa +# message=self.subject, +# reason=response.text, +# ) +# ) +# self.add_send_error_message() +# if send_uid: +# self.update_history(send_id=send_uid, status="error") +# return +# # finish status will be managed via async calls +# api.portal.show_message( +# message=_( +# "success_send_mail_async", +# default="Send queued with success. " "See the status in send history.", +# ), +# request=self.request, +# type="info", +# ) diff --git a/src/rer/ufficiostampa/restapi/services/subscriptions/configure.zcml b/src/rer/ufficiostampa/restapi/services/subscriptions/configure.zcml index 053529f..f77191d 100644 --- a/src/rer/ufficiostampa/restapi/services/subscriptions/configure.zcml +++ b/src/rer/ufficiostampa/restapi/services/subscriptions/configure.zcml @@ -12,6 +12,17 @@ layer="rer.ufficiostampa.interfaces.IRerUfficiostampaLayer" name="@subscriptions" /> + + + + + + diff --git a/src/rer/ufficiostampa/utils.py b/src/rer/ufficiostampa/utils.py index fe3c0a1..61060c1 100644 --- a/src/rer/ufficiostampa/utils.py +++ b/src/rer/ufficiostampa/utils.py @@ -132,9 +132,19 @@ def prepare_email_message(context, template, parameters): def mail_from(): - registry = getUtility(IRegistry) - mail_settings = registry.forInterface(IMailSchema, prefix="plone") - return formataddr((mail_settings.email_from_name, mail_settings.email_from_address)) + try: + email_from_name = api.portal.get_registry_record( + "email_from_name", interface=IRerUfficiostampaSettings + ) + email_from_address = api.portal.get_registry_record( + "email_from_address", interface=IRerUfficiostampaSettings + ) + except (KeyError, InvalidParameterError): + registry = getUtility(IRegistry) + mail_settings = registry.forInterface(IMailSchema, prefix="plone") + email_from_address = mail_settings.email_from_address + email_from_name = mail_settings.email_from_name + return formataddr((email_from_name, email_from_address)) def get_next_comunicato_number(): diff --git a/src/rer/ufficiostampa/vocabularies/vocabularies.py b/src/rer/ufficiostampa/vocabularies/vocabularies.py index 5878e85..fa79668 100644 --- a/src/rer/ufficiostampa/vocabularies/vocabularies.py +++ b/src/rer/ufficiostampa/vocabularies/vocabularies.py @@ -59,14 +59,15 @@ def __call__(self, context): class AttachmentsVocabularyFactory: def __call__(self, context): terms = [] - for child in context.listFolderContents( - contentFilter={"portal_type": ["File", "Image"]} + for brain in api.portal.get_tool("portal_catalog")( + portal_type=["File", "Image"], + path={"query": "/".join(context.getPhysicalPath())}, ): terms.append( SimpleTerm( - value=child.getId(), - token=child.getId(), - title=child.Title(), + value=brain.UID, + token=brain.UID, + title=brain.Title, ) ) return SimpleVocabulary(terms)
- All'attenzione dei Capi redattori -