Passed
Pull Request — 2.x (#1864)
by Ramon
09:00
created

senaite.core.z3cform.widgets.uidreference   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 18
eloc 90
dl 0
loc 138
rs 10
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A UIDReferenceWidget.get_api_url() 0 5 1
A UIDReferenceWidget.get_query() 0 2 1
A UIDReferenceWidget.get_input_widget_attributes() 0 26 2
A UIDReferenceWidget.get_obj_info() 0 8 1
A UIDReferenceWidget.render_reference() 0 6 1
A UIDReferenceWidget.__init__() 0 3 1
A UIDReferenceWidget.update() 0 3 1
A UIDReferenceWidget.get_catalog() 0 2 1
A UIDReferenceWidget.get_limit() 0 2 1
A UIDReferenceWidget.is_multi_valued() 0 2 1
A UIDReferenceDataConverter.toFieldValue() 0 6 1
A UIDReferenceWidget.get_value() 0 2 1
A UIDReferenceDataConverter.toWidgetValue() 0 9 2
A UIDReferenceWidget.get_display_template() 0 2 1
A UIDReferenceWidget.get_columns() 0 2 1

1 Function

Rating   Name   Duplication   Size   Complexity  
A UIDReferenceWidgetFactory() 0 6 1
1
# -*- coding: utf-8 -*-
2
3
import json
4
import string
5
from collections import OrderedDict
6
7
from bika.lims import api
8
from senaite.core.interfaces import ISenaiteFormLayer
9
from senaite.core.schema.interfaces import IUIDReferenceField
10
from senaite.core.z3cform.interfaces import IUIDReferenceWidget
11
from senaite.jsonapi.interfaces import IInfo
12
from z3c.form import interfaces
13
from z3c.form.browser import widget
14
from z3c.form.browser.textlines import TextLinesWidget
15
from z3c.form.converter import TextLinesConverter
16
from z3c.form.interfaces import IFieldWidget
17
from z3c.form.widget import FieldWidget
18
from zope.component import adapter
19
from zope.interface import implementer
20
21
DISPLAY_TEMPLATE = "<a href='${url}' _target='blank'>${title} ${uid}</a>"
22
23
24
@adapter(IUIDReferenceField, interfaces.IWidget)
25
class UIDReferenceDataConverter(TextLinesConverter):
26
    """Converts the raw field data for widget/field usage
27
    """
28
29
    def toWidgetValue(self, value):
30
        """Converts a list of UIDs for the display/hidden widget
31
32
        returns a list of UIDs when widget is in "display" mode
33
        returns a unicode string when widget is in "hidden" mode
34
        """
35
        if self.widget.mode == "display":
36
            return value
37
        return super(UIDReferenceDataConverter, self).toWidgetValue(value)
38
39
    def toFieldValue(self, value):
40
        """Converts a unicode string to a list of UIDs
41
        """
42
        # remove any blank lines at the end
43
        value = value.rstrip("\r\n")
44
        return super(UIDReferenceDataConverter, self).toFieldValue(value)
45
46
47
@implementer(IUIDReferenceWidget)
48
class UIDReferenceWidget(TextLinesWidget):
49
    """Senaite UID reference widget
50
    """
51
    klass = u"senaite-uidreference-widget"
52
53
    def __init__(self, request, *args, **kw):
54
        super(UIDReferenceWidget, self).__init__(request)
55
        self.request = request
56
57
    def update(self):
58
        super(UIDReferenceWidget, self).update()
59
        widget.addFieldClass(self)
60
61
    def get_display_template(self):
62
        return getattr(self, "display_template", DISPLAY_TEMPLATE)
63
64
    def get_value(self):
65
        return self.field.get_raw(self.context)
66
67
    def get_api_url(self):
68
        portal = api.get_portal()
69
        portal_url = api.get_url(portal)
70
        api_url = "{}/@@API/senaite/v1".format(portal_url)
71
        return api_url
72
73
    def get_catalog(self):
74
        return getattr(self, "catalog", "portal_catalog")
75
76
    def get_query(self):
77
        return getattr(self, "query", {})
78
79
    def get_columns(self):
80
        return getattr(self, "columns", [])
81
82
    def get_limit(self):
83
        return getattr(self, "limit", 25)
84
85
    def is_multi_valued(self):
86
        return getattr(self.field, "multi_valued", False)
87
88
    def get_input_widget_attributes(self):
89
        """Return input widget attributes for the ReactJS component
90
        """
91
        uids = self.get_value()
92
        attributes = {
93
            "data-id": self.id,
94
            "data-name": self.name,
95
            "data-uids": uids,
96
            "data-api_url": self.get_api_url(),
97
            "data-items": OrderedDict(zip(uids, map(self.get_obj_info, uids))),
98
            "data-query": self.get_query(),
99
            "data-catalog": self.get_catalog(),
100
            "data-columns": self.get_columns(),
101
            "data-display_field": self.get_display_field(),
102
            "data-display_template": self.get_display_template(),
103
            "data-limit": self.get_limit(),
104
            "data-multi_valued": self.is_multi_valued(),
105
            "data-disabled": self.disabled or False,
106
            "data-readonly": self.readonly or False,
107
        }
108
109
        # convert all attributes to JSON
110
        for key, value in attributes.items():
111
            attributes[key] = json.dumps(value)
112
113
        return attributes
114
115
    def get_obj_info(self, uid):
116
        """Returns a dictionary with the object info
117
        """
118
        obj = api.get_object(uid)
119
        obj_info = IInfo(obj).to_dict()
120
        obj_info["uid"] = uid
121
        obj_info["url"] = api.get_url(obj)
122
        return obj_info
123
124
    def render_reference(self, uid):
125
        """Returns a rendered HTML element for the reference
126
        """
127
        template = string.Template(self.get_display_template())
128
        obj_info = self.get_obj_info(uid)
129
        return template.safe_substitute(obj_info)
130
131
132
@adapter(IUIDReferenceField, ISenaiteFormLayer)
133
@implementer(IFieldWidget)
134
def UIDReferenceWidgetFactory(field, request):
135
    """Widget factory for UIDReferenceField
136
    """
137
    return FieldWidget(field, UIDReferenceWidget(request))
138