Passed
Push — master ( b77d42...61afd1 )
by Ramon
05:36
created

bika.lims.browser.get_date()   C

Complexity

Conditions 10

Size

Total Lines 46
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 36
dl 0
loc 46
rs 5.9999
c 0
b 0
f 0
cc 10
nop 2

How to fix   Complexity   

Complexity

Complex classes like bika.lims.browser.get_date() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of SENAITE.CORE
4
#
5
# Copyright 2018 by it's authors.
6
# Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst.
7
8
"""Bika's browser views are based on this one, for a nice set of utilities.
9
"""
10
import traceback
11
from datetime import datetime
12
from time import strptime
13
14
from AccessControl import ClassSecurityInfo
15
from DateTime.DateTime import DateTime, safelocaltime
16
from Products.ATContentTypes.utils import dt2DT
17
from Products.CMFCore.utils import getToolByName
18
from Products.CMFPlone.i18nl10n import ulocalized_time as _ut
19
from Products.Five.browser import BrowserView as BaseBrowserView
20
from bika.lims import logger
21
from zope.cachedescriptors.property import Lazy as lazy_property
22
from zope.i18n import translate
23
24
25
def get_date(context, value):
26
    """Tries to return a DateTime.DateTime object
27
    """
28
    if not value:
29
        return None
30
    if isinstance(value, DateTime):
31
        return value
32
    if isinstance(value, datetime):
33
        return dt2DT(value)
34
    if not isinstance(value, basestring):
35
        return None
36
37
    def try_parse(date_string, format):
38
        if not format:
39
            return None
40
        try:
41
            struct_time = strptime(date_string, format)
42
            return datetime(*struct_time[:6])
43
        except ValueError:
44
            pass
45
        return None
46
47
    def get_locale_format(key, context):
48
        format = context.translate(key, domain="senaite.core", mapping={})
49
        # TODO: Is this replacement below strictly necessary?
50
        return format.replace(r"${", '%').replace('}', '')
51
52
    # Try with prioritized formats
53
    formats = [get_locale_format("date_format_long", context),
54
               get_locale_format("date_format_short", context),
55
               "%Y-%m-%d %H:%M", "%Y-%m-%d", "%Y-%m-%d %H:%M:%S"]
56
    for pri_format in formats:
57
        val = try_parse(value, pri_format)
58
        if not val:
59
            continue
60
        val = dt2DT(val)
61
        if val.timezoneNaive():
62
            # Use local timezone for tz naive strings
63
            # see http://dev.plone.org/plone/ticket/10141
64
            zone = val.localZone(safelocaltime(val.timeTime()))
65
            parts = val.parts()[:-1] + (zone,)
66
            val = DateTime(*parts)
67
        return val
68
69
    logger.warn("Unable to convert {} to datetime".format(value))
70
    return None
71
72
73
def ulocalized_time(time, long_format=None, time_only=None, context=None,
74
                    request=None):
75
    """
76
    This function gets ans string as time or a DateTime objects and returns a
77
    string with the time formatted
78
79
    :param time: The time to process
80
    :type time: str/DateTime
81
    :param long_format:  If True, return time in ling format
82
    :type portal_type: boolean/null
83
    :param time_only: If True, only returns time.
84
    :type title: boolean/null
85
    :param context: The current context
86
    :type context: ATContentType
87
    :param request: The current request
88
    :type request: HTTPRequest object
89
    :returns: The formatted date as string
90
    :rtype: string
91
    """
92
    # if time is a string, we'll try pass it through strptime with the various
93
    # formats defined.
94
    time = get_date(context, time)
95
    if not time or not isinstance(time, DateTime):
96
        return ''
97
98
    # no printing times if they were not specified in inputs
99
    if time.second() + time.minute() + time.hour() == 0:
100
        long_format = False
101
    try:
102
        time_str = _ut(time, long_format, time_only, context, 'senaite.core', request)
103
    except ValueError:
104
        err_msg = traceback.format_exc() + '\n'
105
        logger.warn(
106
            err_msg + '\n' +
107
            "Error converting '{}' time to string in {}."
108
            .format(time, context))
109
        time_str = ''
110
    return time_str
111
112
113
class updateFilerByDepartmentCookie(BaseBrowserView):
114
    """
115
    This function updates or creates the cookie 'filter_by_department_info'
116
    in order to filter the lists by department.
117
    @context: is the current view.
118
    @value: is a list of UIDs of departments.
119
    """
120
121
    def __call__(self):
122
        # Getting the department uid from the submit
123
        dep_uid = self.request.form.get('department_filter_portlet', '')
124
        # Create/Update a cookie with the new department uid
125
        self.request.response.setCookie(
126
            'filter_by_department_info', dep_uid, path='/')
127
        # Redirect to the same page
128
        url = self.request.get('URL', '')\
129
            .replace('portletfilter_by_department', '')
130
        self.request.response.redirect(url)
131
132
133
class BrowserView(BaseBrowserView):
134
    security = ClassSecurityInfo()
135
136
    logger = logger
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable logger does not seem to be defined.
Loading history...
137
138
    def __init__(self, context, request):
139
        self.context = context
140
        self.request = request
141
        super(BrowserView, self).__init__(context, request)
142
143
    security.declarePublic('ulocalized_time')
144
145
    def ulocalized_time(self, time, long_format=None, time_only=None):
146
        return ulocalized_time(time, long_format, time_only,
147
                               context=self.context, request=self.request)
148
149
    @lazy_property
150
    def portal(self):
151
        return getToolByName(self.context, 'portal_url').getPortalObject()
152
153
    @lazy_property
154
    def portal_url(self):
155
        return self.portal.absolute_url().split("?")[0]
156
157
    @lazy_property
158
    def portal_catalog(self):
159
        return getToolByName(self.context, 'portal_catalog')
160
161
    @lazy_property
162
    def reference_catalog(self):
163
        return getToolByName(self.context, 'reference_catalog')
164
165
    @lazy_property
166
    def bika_analysis_catalog(self):
167
        return getToolByName(self.context, 'bika_analysis_catalog')
168
169
    @lazy_property
170
    def bika_setup_catalog(self):
171
        return getToolByName(self.context, 'bika_setup_catalog')
172
173
    @lazy_property
174
    def bika_catalog(self):
175
        return getToolByName(self.context, 'bika_catalog')
176
177
    @lazy_property
178
    def portal_membership(self):
179
        return getToolByName(self.context, 'portal_membership')
180
181
    @lazy_property
182
    def portal_groups(self):
183
        return getToolByName(self.context, 'portal_groups')
184
185
    @lazy_property
186
    def portal_workflow(self):
187
        return getToolByName(self.context, 'portal_workflow')
188
189
    @lazy_property
190
    def checkPermission(self, perm, obj):
191
        return self.portal_membership.checkPermission(perm, obj)
192
193
    # TODO: user_fullname is deprecated and will be removed in Bika LIMS 3.3.
194
    # Use bika.utils.user_fullnameinstead
195
    # I was having a problem trying to import the function from bika.lims.utils
196
    # so i copied the code here.
197
    def user_fullname(self, userid):
198
        member = self.portal_membership.getMemberById(userid)
199
        if member is None:
200
            return userid
201
        member_fullname = member.getProperty('fullname')
202
        portal_catalog = getToolByName(self, 'portal_catalog')
203
        c = portal_catalog(portal_type='Contact', getUsername=userid)
204
        contact_fullname = c[0].getObject().getFullname() if c else None
205
        return contact_fullname or member_fullname or userid
206
207
    # TODO: user_fullname is deprecated and will be removed in Bika LIMS 3.3.
208
    # Use bika.utils.user_fullnameinstead.
209
    # I was having a problem trying to import the function from bika.lims.utils
210
    # so i copied the code here.
211
    def user_email(self, userid):
212
        member = self.portal_membership.getMemberById(userid)
213
        if member is None:
214
            return userid
215
        member_email = member.getProperty('email')
216
        portal_catalog = getToolByName(self, 'portal_catalog')
217
        c = portal_catalog(portal_type='Contact', getUsername=userid)
218
        contact_email = c[0].getObject().getEmailAddress() if c else None
219
        return contact_email or member_email or ''
220
221
    def python_date_format(self, long_format=None, time_only=False):
222
        """This convert bika domain date format msgstrs to Python
223
        strftime format strings, by the same rules as ulocalized_time.
224
        XXX i18nl10n.py may change, and that is where this code is taken from.
225
        """
226
        # get msgid
227
        msgid = long_format and 'date_format_long' or 'date_format_short'
228
        if time_only:
229
            msgid = 'time_format'
230
        # get the formatstring
231
        formatstring = translate(msgid, domain="senaite.core",
232
                                 context=self.request)
233
234
        if formatstring is None or formatstring.startswith(
235
                'date_') or formatstring.startswith('time_'):
236
            self.logger.error("bika/%s/%s could not be translated" %
237
                              (self.request.get('LANGUAGE'), msgid))
238
            # msg catalog was not able to translate this msgids
239
            # use default setting
240
            properties = getToolByName(self.context,
241
                                       'portal_properties').site_properties
242
            if long_format:
243
                format = properties.localLongTimeFormat
244
            else:
245
                if time_only:
246
                    format = properties.localTimeOnlyFormat
247
                else:
248
                    format = properties.localTimeFormat
249
            return format
250
        return formatstring.replace(r"${", '%').replace('}', '')
251
252
    @lazy_property
253
    def date_format_long(self):
254
        fmt = self.python_date_format(long_format=1)
255
        if fmt == "date_format_long":
256
            fmt = "%Y-%m-%d %I:%M %p"
257
        return fmt
258
259
    @lazy_property
260
    def date_format_short(self):
261
        fmt = self.python_date_format()
262
        if fmt == "date_format_short":
263
            fmt = "%Y-%m-%d"
264
        return fmt
265
266
    @lazy_property
267
    def time_format(self):
268
        fmt = self.python_date_format(time_only=True)
269
        if fmt == "time_format":
270
            fmt = "%I:%M %p"
271
        return fmt
272