diff --git a/CHANGES.rst b/CHANGES.rst index 6fcc088bda..806be3dc3e 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,7 @@ Changelog **Added** +- #1507 Support for semi-colon character separator in CCEmails field - #1499 Moved navigation portlet into core - #1498 Moved all viewlets from senaite.lims to senaite.core - #1505 Display partition link in analyses listing diff --git a/bika/lims/browser/analysisrequest/add2.py b/bika/lims/browser/analysisrequest/add2.py index 00ab0d637c..460398c965 100644 --- a/bika/lims/browser/analysisrequest/add2.py +++ b/bika/lims/browser/analysisrequest/add2.py @@ -1064,7 +1064,7 @@ def get_primaryanalysisrequest_info(self, obj): "Client": self.to_field_value(client), "Contact": self.to_field_value(contact), "CCContact": map(self.to_field_value, cccontacts), - "CCEmails": obj.getCCEmails() or [], + "CCEmails": obj.getCCEmails(), "Batch": self.to_field_value(batch), "DateSampled": {"value": self.to_iso_date(obj.getDateSampled())}, "SamplingDate": {"value": self.to_iso_date(obj.getSamplingDate())}, diff --git a/bika/lims/browser/fields/__init__.py b/bika/lims/browser/fields/__init__.py index 5c37b80e51..d366dca597 100644 --- a/bika/lims/browser/fields/__init__.py +++ b/bika/lims/browser/fields/__init__.py @@ -29,3 +29,4 @@ from .reflexrulefield import ReflexRuleField from .proxyfield import ProxyField from .uidreferencefield import UIDReferenceField +from .emailsfield import EmailsField diff --git a/bika/lims/browser/fields/emailsfield.py b/bika/lims/browser/fields/emailsfield.py new file mode 100644 index 0000000000..3c394666fc --- /dev/null +++ b/bika/lims/browser/fields/emailsfield.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# +# This file is part of SENAITE.CORE. +# +# SENAITE.CORE is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, version 2. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 51 +# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Copyright 2018-2020 by it's authors. +# Some rights reserved, see README and LICENSE. + +import re + +from Products.Archetypes.Field import StringField +from Products.Archetypes.Registry import registerField + + +class EmailsField(StringField): + """Field for string representation of a list of emails + """ + _properties = StringField._properties.copy() + _properties.update({ + "type": "emails_field", + }) + + def set(self, instance, value, **kwargs): + if value: + # Standardize to comma-separated and remove duplicates + validator = instance.plone_utils.validateSingleEmailAddress + value = ", ".join(self.to_list(value, validator=validator)) + super(EmailsField, self).set(instance, value, **kwargs) + + def get(self, instance, **kwargs): + if kwargs.get("as_list", False): + # Return as a list + validator = instance.plone_utils.validateSingleEmailAddress + return self.to_list(self.get(instance), validator) + return super(EmailsField, self).get(instance, **kwargs) + + def to_list(self, value, validator=None): + """Transforms the value to a list of values + """ + if not value: + return [] + emails = map(lambda x: x.strip(), re.split("[;,]", value)) + emails = filter(None, emails) + if validator: + emails = filter(lambda email: validator(email), emails) + return emails + + +registerField(EmailsField, + title="Emails", + description="Used for storing e-mail addresses in string format") diff --git a/bika/lims/browser/publish/emailview.py b/bika/lims/browser/publish/emailview.py index 93bb984544..22450b4a66 100644 --- a/bika/lims/browser/publish/emailview.py +++ b/bika/lims/browser/publish/emailview.py @@ -20,6 +20,7 @@ import inspect import itertools +import re from collections import OrderedDict from string import Template @@ -728,7 +729,7 @@ def recipient_from_email(email): # CC Contacts cc = filter(None, map(recipient_from_contact, ar.getCCContact())) # CC Emails - cc_emails = map(lambda x: x.strip(), ar.getCCEmails().split(",")) + cc_emails = ar.getCCEmails(as_list=True) cc_emails = filter(None, map(recipient_from_email, cc_emails)) return to + cc + cc_emails diff --git a/bika/lims/browser/publish/reports_listing.py b/bika/lims/browser/publish/reports_listing.py index 018a3dcc89..4519662559 100644 --- a/bika/lims/browser/publish/reports_listing.py +++ b/bika/lims/browser/publish/reports_listing.py @@ -19,6 +19,7 @@ # Some rights reserved, see README and LICENSE. import collections +import re from bika.lims import api from bika.lims import bikaMessageFactory as _BMF @@ -242,7 +243,7 @@ def recipient_from_email(email): # CC Contacts cc = filter(None, map(recipient_from_contact, ar.getCCContact())) # CC Emails - cc_emails = map(lambda x: x.strip(), ar.getCCEmails().split(",")) + cc_emails = ar.getCCEmails(as_list=True) cc_emails = filter(None, map(recipient_from_email, cc_emails)) return to + cc + cc_emails diff --git a/bika/lims/content/analysisrequest.py b/bika/lims/content/analysisrequest.py index 53d5255680..8f97cc101c 100644 --- a/bika/lims/content/analysisrequest.py +++ b/bika/lims/content/analysisrequest.py @@ -33,6 +33,7 @@ from bika.lims.browser.fields import DateTimeField from bika.lims.browser.fields import DurationField from bika.lims.browser.fields import UIDReferenceField +from bika.lims.browser.fields import EmailsField from bika.lims.browser.fields.remarksfield import RemarksField from bika.lims.browser.widgets import DateTimeWidget from bika.lims.browser.widgets import DecimalWidget @@ -204,7 +205,7 @@ ), ), - StringField( + EmailsField( 'CCEmails', mode="rw", read_permission=View, diff --git a/bika/lims/content/client.py b/bika/lims/content/client.py index 79f9c650d5..1fb93c369a 100644 --- a/bika/lims/content/client.py +++ b/bika/lims/content/client.py @@ -36,6 +36,7 @@ from bika.lims import _ from bika.lims import api +from bika.lims.browser.fields import EmailsField from bika.lims.browser.widgets import ReferenceWidget from bika.lims.catalog.bikasetup_catalog import SETUP_CATALOG from bika.lims.config import ARIMPORT_OPTIONS @@ -73,7 +74,7 @@ ), ), - StringField( + EmailsField( "CCEmails", schemata="Preferences", mode="rw",