senaite.core.content.person.Person.getUsername()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 5
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 1
nop 1
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of SENAITE.CORE.
4
#
5
# SENAITE.CORE is free software: you can redistribute it and/or modify it under
6
# the terms of the GNU General Public License as published by the Free Software
7
# Foundation, version 2.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
# details.
13
#
14
# You should have received a copy of the GNU General Public License along with
15
# this program; if not, write to the Free Software Foundation, Inc., 51
16
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
#
18
# Copyright 2018-2025 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
from AccessControl import ClassSecurityInfo
22
from bika.lims import senaiteMessageFactory as _
23
from bika.lims.api import mail
24
from plone.autoform import directives
25
from plone.supermodel import model
26
from Products.CMFCore import permissions
27
from Products.CMFPlone.utils import safe_unicode
28
from senaite.core.content.base import Container
29
from senaite.core.schema import AddressField
30
from senaite.core.schema import PhoneField
31
from senaite.core.schema.addressfield import PHYSICAL_ADDRESS
32
from senaite.core.schema.addressfield import POSTAL_ADDRESS
33
from senaite.core.z3cform.widgets.address import AddressWidget
34
from senaite.core.z3cform.widgets.phone import PhoneWidget
35
from zope import schema
36
from zope.interface import implementer
37
from zope.interface import invariant
38
from zope.interface.exceptions import Invalid
39
40
41
class IPersonSchema(model.Schema):
42
    """Base schema for Person-based content types
43
    """
44
45
    # Hidden fields
46
    directives.omitted("title")
47
    directives.omitted("description")
48
    directives.omitted("username")
49
50
    title = schema.TextLine(
51
        title=_(
52
            u"label_person_title",
53
            default=u"Title"
54
        ),
55
        required=False,
56
    )
57
58
    description = schema.Text(
59
        title=_(
60
            "label_person_description",
61
            default="Description",
62
        ),
63
        required=False,
64
    )
65
66
    salutation = schema.TextLine(
67
        title=_(
68
            u"label_person_salutation",
69
            default=u"Salutation"
70
        ),
71
        description=_(
72
            u"description_person_salutation",
73
            default=u"Greeting title eg. Mr, Mrs, Dr"
74
        ),
75
        required=False,
76
    )
77
78
    firstname = schema.TextLine(
79
        title=_(
80
            u"label_person_firstname",
81
            default=u"Firstname"
82
        ),
83
        required=True,
84
    )
85
86
    middleinitial = schema.TextLine(
87
        title=_(
88
            u"label_person_middleinitial",
89
            default=u"Middle initial"
90
        ),
91
        required=False,
92
    )
93
94
    middlename = schema.TextLine(
95
        title=_(
96
            u"label_person_middlename",
97
            default=u"Middle name"
98
        ),
99
        required=False,
100
    )
101
102
    surname = schema.TextLine(
103
        title=_(
104
            u"label_person_surname",
105
            default=u"Surname"
106
        ),
107
        required=True,
108
    )
109
110
    job_title = schema.TextLine(
111
        title=_(
112
            u"label_person_job_title",
113
            default=u"Job title"
114
        ),
115
        required=False,
116
    )
117
118
    department = schema.TextLine(
119
        title=_(
120
            u"label_person_department",
121
            default=u"Department"
122
        ),
123
        required=False,
124
    )
125
126
    username = schema.TextLine(
127
        title=_(
128
            u"label_person_username",
129
            default=u"Username"
130
        ),
131
        required=False,
132
    )
133
134
    # Contact information
135
    model.fieldset(
136
        "contact_information",
137
        label=_(
138
            u"label_contact_information",
139
            default=u"Email Telephone Fax"
140
        ),
141
        fields=[
142
            "email_address",
143
            "business_phone",
144
            "business_fax",
145
            "home_phone",
146
            "mobile_phone",
147
        ]
148
    )
149
150
    email_address = schema.TextLine(
151
        title=_(
152
            u"label_person_email_address",
153
            default=u"Email Address"
154
        ),
155
        required=False,
156
    )
157
158
    directives.widget("business_phone", PhoneWidget)
159
    business_phone = PhoneField(
160
        title=_(
161
            u"label_person_business_phone",
162
            default=u"Phone (business)"
163
        ),
164
        required=False,
165
    )
166
167
    directives.widget("business_fax", PhoneWidget)
168
    business_fax = PhoneField(
169
        title=_(
170
            u"label_person_business_fax",
171
            default=u"Fax (business)"
172
        ),
173
        required=False,
174
    )
175
176
    directives.widget("home_phone", PhoneWidget)
177
    home_phone = PhoneField(
178
        title=_(
179
            u"label_person_home_phone",
180
            default=u"Phone (home)"
181
        ),
182
        required=False,
183
    )
184
185
    directives.widget("mobile_phone", PhoneWidget)
186
    mobile_phone = PhoneField(
187
        title=_(
188
            u"label_person_mobile_phone",
189
            default=u"Phone (mobile)"
190
        ),
191
        required=False,
192
    )
193
194
    # Address
195
    model.fieldset(
196
        "address",
197
        label=_(
198
            u"label_address",
199
            default=u"Address"
200
        ),
201
        fields=[
202
            "physical_address",
203
            "postal_address",
204
        ]
205
    )
206
207
    directives.widget("physical_address", AddressWidget)
208
    physical_address = AddressField(
209
        address_types=(PHYSICAL_ADDRESS),
210
        title=_(
211
            u"label_person_physical_address",
212
            default=u"Physical address"
213
        ),
214
        required=False,
215
    )
216
217
    directives.widget("postal_address", AddressWidget)
218
    postal_address = AddressField(
219
        title=_(
220
            u"label_person_postal_address",
221
            default=u"Postal address"
222
        ),
223
        address_types=(POSTAL_ADDRESS),
224
        required=False,
225
    )
226
227
    @invariant
228
    def validate_email_address(data):
229
        """Checks if email address is valid
230
        """
231
        value = data.email_address
232
        if not value:
233
            return
234
235
        if not mail.is_valid_email_address(value):
236
            raise Invalid(_(u"Invalid email address"))
237
238
239
@implementer(IPersonSchema)
240
class Person(Container):
241
    """Base class for Person-based content types
242
    """
243
244
    security = ClassSecurityInfo()
245
246
    def Title(self):
247
        """Return the contact's Fullname as title
248
        """
249
        return safe_unicode(self.getFullname()).encode("utf-8")
250
251
    def getPossibleAddresses(self):
252
        """Return possible address types
253
        """
254
        return ["PhysicalAddress", "PostalAddress"]
255
256 View Code Duplication
    @security.protected(permissions.ModifyPortalContent)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
257
    def setFullname(self, value):
258
        parts = value.split(" ")
259
        length = len(parts)
260
        if length == 2:
261
            self.setFirstname(parts[0])
262
            self.setSurname(parts[1])
263
        elif length == 3:
264
            self.setFirstname(parts[0])
265
            self.setMiddlename(parts[1])
266
            self.setSurname(parts[2])
267
        elif length == 4:
268
            self.setFirstname(parts[0])
269
            self.setMiddleinitial(parts[1])
270
            self.setMiddlename(parts[2])
271
            self.setSurname(parts[3])
272
        else:
273
            self.setSurname(value)
274
275 View Code Duplication
    def getFullname(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
276
        """Person's Fullname
277
        """
278
        fn = self.getFirstname()
279
        mi = self.getMiddleinitial()
280
        md = self.getMiddlename()
281
        sn = self.getSurname()
282
        fullname = ""
283
        if fn or sn:
284
            if mi and md:
285
                fullname = "%s %s %s %s" % (
286
                    self.getFirstname(),
287
                    self.getMiddleinitial(),
288
                    self.getMiddlename(),
289
                    self.getSurname())
290
            elif mi:
291
                fullname = "%s %s %s" % (
292
                    self.getFirstname(),
293
                    self.getMiddleinitial(),
294
                    self.getSurname())
295
            elif md:
296
                fullname = "%s %s %s" % (
297
                    self.getFirstname(),
298
                    self.getMiddlename(),
299
                    self.getSurname())
300
            else:
301
                fullname = "%s %s" % (self.getFirstname(), self.getSurname())
302
        return fullname.strip()
303
304
    @security.protected(permissions.View)
305
    def getSalutation(self):
306
        accessor = self.accessor("salutation")
307
        value = accessor(self) or ""
308
        return safe_unicode(value).encode("utf-8")
309
310
    @security.protected(permissions.ModifyPortalContent)
311
    def setSalutation(self, value):
312
        mutator = self.mutator("salutation")
313
        mutator(self, safe_unicode(value))
314
315
    # BBB: AT schema field property
316
    Salutation = property(getSalutation, setSalutation)
317
318
    @security.protected(permissions.View)
319
    def getFirstname(self):
320
        accessor = self.accessor("firstname")
321
        value = accessor(self) or ""
322
        return safe_unicode(value).encode("utf-8")
323
324
    @security.protected(permissions.ModifyPortalContent)
325
    def setFirstname(self, value):
326
        mutator = self.mutator("firstname")
327
        mutator(self, safe_unicode(value))
328
329
    # BBB: AT schema field property
330
    Firstname = property(getFirstname, setFirstname)
331
332
    @security.protected(permissions.View)
333
    def getMiddleinitial(self):
334
        accessor = self.accessor("middleinitial")
335
        value = accessor(self) or ""
336
        return safe_unicode(value).encode("utf-8")
337
338
    @security.protected(permissions.ModifyPortalContent)
339
    def setMiddleinitial(self, value):
340
        mutator = self.mutator("middleinitial")
341
        mutator(self, safe_unicode(value))
342
343
    # BBB: AT schema field property
344
    Middleinitial = property(getMiddleinitial, setMiddleinitial)
345
346
    @security.protected(permissions.View)
347
    def getMiddlename(self):
348
        accessor = self.accessor("middlename")
349
        value = accessor(self) or ""
350
        return safe_unicode(value).encode("utf-8")
351
352
    @security.protected(permissions.ModifyPortalContent)
353
    def setMiddlename(self, value):
354
        mutator = self.mutator("middlename")
355
        mutator(self, safe_unicode(value))
356
357
    # BBB: AT schema field property
358
    Middlename = property(getMiddlename, setMiddlename)
359
360
    @security.protected(permissions.View)
361
    def getSurname(self):
362
        accessor = self.accessor("surname")
363
        value = accessor(self) or ""
364
        return safe_unicode(value).encode("utf-8")
365
366
    @security.protected(permissions.ModifyPortalContent)
367
    def setSurname(self, value):
368
        mutator = self.mutator("surname")
369
        mutator(self, safe_unicode(value))
370
371
    # BBB: AT schema field property
372
    Surname = property(getSurname, setSurname)
373
374
    # BBB: AT schema field property
375
    Fullname = property(getFullname, setFullname)
376
377
    @security.protected(permissions.View)
378
    def getUsername(self):
379
        accessor = self.accessor("username")
380
        value = accessor(self) or ""
381
        return safe_unicode(value).encode("utf-8")
382
383
    @security.protected(permissions.ModifyPortalContent)
384
    def setUsername(self, value):
385
        mutator = self.mutator("username")
386
        mutator(self, safe_unicode(value))
387
388
    # BBB: AT schema field property
389
    Username = property(getUsername, setUsername)
390
391
    @security.protected(permissions.View)
392
    def getEmailAddress(self):
393
        accessor = self.accessor("email_address")
394
        value = accessor(self) or ""
395
        return safe_unicode(value).encode("utf-8")
396
397
    @security.protected(permissions.ModifyPortalContent)
398
    def setEmailAddress(self, value):
399
        mutator = self.mutator("email_address")
400
        mutator(self, safe_unicode(value))
401
402
    # BBB: AT schema field property
403
    EmailAddress = property(getEmailAddress, setEmailAddress)
404
405
    @security.protected(permissions.View)
406
    def getBusinessPhone(self):
407
        accessor = self.accessor("business_phone")
408
        value = accessor(self) or ""
409
        return safe_unicode(value).encode("utf-8")
410
411
    @security.protected(permissions.ModifyPortalContent)
412
    def setBusinessPhone(self, value):
413
        mutator = self.mutator("business_phone")
414
        mutator(self, safe_unicode(value))
415
416
    # BBB: AT schema field property
417
    BusinessPhone = property(getBusinessPhone, setBusinessPhone)
418
419
    @security.protected(permissions.View)
420
    def getBusinessFax(self):
421
        accessor = self.accessor("business_fax")
422
        value = accessor(self) or ""
423
        return safe_unicode(value).encode("utf-8")
424
425
    @security.protected(permissions.ModifyPortalContent)
426
    def setBusinessFax(self, value):
427
        mutator = self.mutator("business_fax")
428
        mutator(self, safe_unicode(value))
429
430
    # BBB: AT schema field property
431
    BusinessFax = property(getBusinessFax, setBusinessFax)
432
433
    @security.protected(permissions.View)
434
    def getHomePhone(self):
435
        accessor = self.accessor("home_phone")
436
        value = accessor(self) or ""
437
        return safe_unicode(value).encode("utf-8")
438
439
    @security.protected(permissions.ModifyPortalContent)
440
    def setHomePhone(self, value):
441
        mutator = self.mutator("home_phone")
442
        mutator(self, safe_unicode(value))
443
444
    # BBB: AT schema field property
445
    HomePhone = property(getHomePhone, setHomePhone)
446
447
    @security.protected(permissions.View)
448
    def getMobilePhone(self):
449
        accessor = self.accessor("mobile_phone")
450
        value = accessor(self) or ""
451
        return safe_unicode(value).encode("utf-8")
452
453
    @security.protected(permissions.ModifyPortalContent)
454
    def setMobilePhone(self, value):
455
        mutator = self.mutator("mobile_phone")
456
        mutator(self, safe_unicode(value))
457
458
    # BBB: AT schema field property
459
    MobilePhone = property(getMobilePhone, setMobilePhone)
460
461
    @security.protected(permissions.View)
462
    def getJobTitle(self):
463
        accessor = self.accessor("job_title")
464
        value = accessor(self) or ""
465
        return safe_unicode(value).encode("utf-8")
466
467
    @security.protected(permissions.ModifyPortalContent)
468
    def setJobTitle(self, value):
469
        mutator = self.mutator("job_title")
470
        mutator(self, safe_unicode(value))
471
472
    # BBB: AT schema field property
473
    JobTitle = property(getJobTitle, setJobTitle)
474
475
    @security.protected(permissions.View)
476
    def getDepartment(self):
477
        accessor = self.accessor("department")
478
        value = accessor(self) or ""
479
        return safe_unicode(value).encode("utf-8")
480
481
    @security.protected(permissions.ModifyPortalContent)
482
    def setDepartment(self, value):
483
        mutator = self.mutator("department")
484
        mutator(self, safe_unicode(value))
485
486
    # BBB: AT schema field property
487
    Department = property(getDepartment, setDepartment)
488
489
    @security.protected(permissions.View)
490
    def getPhysicalAddress(self):
491
        accessor = self.accessor("physical_address")
492
        value = accessor(self)
493
        # The address field returns a list of address dicts
494
        if value and isinstance(value, list):
495
            value = value[0]
496
        if not isinstance(value, dict):
497
            value = self.get_empty_address(PHYSICAL_ADDRESS)
498
        return value
499
500
    @security.protected(permissions.ModifyPortalContent)
501
    def setPhysicalAddress(self, value):
502
        mutator = self.mutator("physical_address")
503
        mutator(self, value)
504
505
    # BBB: AT schema field property
506
    PhysicalAddress = property(getPhysicalAddress, setPhysicalAddress)
507
508
    @security.protected(permissions.View)
509
    def getPostalAddress(self):
510
        accessor = self.accessor("postal_address")
511
        value = accessor(self)
512
        # The address field returns a list of address dicts
513
        if value and isinstance(value, list):
514
            value = value[0]
515
        if not isinstance(value, dict):
516
            value = self.get_empty_address(POSTAL_ADDRESS)
517
        return value
518
519
    @security.protected(permissions.ModifyPortalContent)
520
    def setPostalAddress(self, value):
521
        mutator = self.mutator("postal_address")
522
        mutator(self, value)
523
524
    # BBB: AT schema field property
525
    PostalAddress = property(getPostalAddress, setPostalAddress)
526
527
    # Helper methods for address fields (computed fields in old Person schema)
528
    def getCity(self):
529
        """Return city from physical address
530
        """
531
        address = self.getPhysicalAddress()
532
        if not address:
533
            return ""
534
        return address.get("city", "")
535
536
    def getDistrict(self):
537
        """Return district from physical address
538
        """
539
        address = self.getPhysicalAddress()
540
        if not address:
541
            return ""
542
        return address.get("subdivison2", "")
543
544
    def getPostalCode(self):
545
        """Return postal code from physical address
546
        """
547
        address = self.getPhysicalAddress()
548
        if not address:
549
            return ""
550
        return address.get("postalCode", "")
551
552
    def getCountry(self):
553
        """Return country from physical address
554
        """
555
        address = self.getPhysicalAddress()
556
        if not address:
557
            return ""
558
        return address.get("country", "")
559
560
    @security.protected(permissions.ManagePortal)
561
    def hasUser(self):
562
        """Check if person has user
563
        """
564
        from plone import api
565
        return api.user.get(userid=self.getUsername()) is not None
566
567
    def get_empty_address(self, address_type):
568
        """Returns a dict that represents an empty address for the given type
569
        """
570
        return {
571
            "type": address_type,
572
            "address": "",
573
            "zip": "",
574
            "city": "",
575
            "subdivision2": "",
576
            "subdivision1": "",
577
            "country": "",
578
        }
579