Passed
Push — 2.x ( 7c9886...165ef1 )
by Jordi
07:30
created

senaite.core.browser.widgets.queryselect   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 107
Duplicated Lines 13.08 %

Importance

Changes 0
Metric Value
wmc 14
eloc 76
dl 14
loc 107
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A QuerySelectWidget.get_api_url() 0 9 2
A QuerySelectWidget.get_input_widget_attributes() 0 26 2
A QuerySelectWidget.to_value() 0 12 4
B QuerySelectWidget.attr() 14 14 6

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
# -*- coding: utf-8 -*-
2
3
import json
4
5
import six
6
7
from bika.lims import api
8
from AccessControl import ClassSecurityInfo
9
from Products.Archetypes.Registry import registerWidget
10
from Products.Archetypes.Widget import TypesWidget
11
from Products.CMFPlone.utils import base_hasattr
12
13
_marker = object
14
15
16
class QuerySelectWidget(TypesWidget):
17
    """AT Backport of Dexterity Queryselect Widget
18
19
    https://github.com/senaite/senaite.core/pull/2177
20
    """
21
    security = ClassSecurityInfo()
22
    _properties = TypesWidget._properties.copy()
23
    _properties.update({
24
        "macro": "senaite_widgets/queryselectwidget",
25
        "query": {},
26
        "limit": 25,
27
        "catalog": "portal_catalog",
28
        "api_url": None,
29
        "disabled": False,
30
        "readonly": False,
31
        "multi_valued": False,
32
        "allow_user_value": False,
33
        "search_wildcard": True,
34
        "value_key": "uid",
35
        "padding": 3,
36
        "display_template": None,
37
        "hide_input_after_select": False,
38
    })
39
40 View Code Duplication
    def attr(self, context, name, default=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
41
        """Get the named attribute of the widget or from the context
42
        """
43
        value = getattr(self, name, _marker)
44
        if value is _marker:
45
            return default
46
        if isinstance(value, six.string_types):
47
            if base_hasattr(context, value):
48
                attr = getattr(context, value)
49
                if callable(attr):
50
                    attr = attr()
51
                if attr:
52
                    value = attr
53
        return value
54
55
    def to_value(self, value):
56
        """Extract the value from the request or get it from the field
57
        """
58
        # the value might come from the request, e.g. on object creation
59
        if isinstance(value, six.string_types):
60
            value = filter(None, value.split("\r\n"))
61
        # we handle always lists in the templates
62
        if value is None:
63
            return []
64
        if not isinstance(value, (list, tuple)):
65
            value = [value]
66
        return value
67
68
    def get_api_url(self, context):
69
        """JSON API URL to use for this widget
70
        """
71
        portal = api.get_portal()
72
        portal_url = api.get_url(portal)
73
        api_url = self.attr(context, "api_url")
74
        if not api_url:
75
            api_url = "{}/@@API/senaite/v1".format(portal_url)
76
        return api_url
77
78
    def get_input_widget_attributes(self, context, field, value):
79
        """Return input widget attributes for the ReactJS component
80
        """
81
        attributes = {
82
            "data-id": field.getName(),
83
            "data-name": field.getName(),
84
            "data-values": self.to_value(value),
85
            "data-value_key": self.attr(context, "value_key"),
86
            "data-columns": self.attr(context, "columns"),
87
            "data-query": self.attr(context, "query"),
88
            "data-multi_valued": self.attr(context, "multi_valued"),
89
            "data-api_url": self.get_api_url(context),
90
            "data-search_index": self.attr(context, "search_index"),
91
            "data-search_wildcard": self.attr(context, "search_wildcard"),
92
            "data-limit": self.attr(context, "limit"),
93
            "data-catalog": self.attr(context, "catalog"),
94
            "data-allow_user_value": self.attr(context, "allow_user_value"),
95
            "data-hide_input_after_select": self.attr(
96
                context, "hide_input_after_select"),
97
        }
98
99
        # convert all attributes to JSON
100
        for key, value in attributes.items():
101
            attributes[key] = json.dumps(value)
102
103
        return attributes
104
105
106
registerWidget(QuerySelectWidget, title="QuerySelectWidget")
107