Passed
Pull Request — 2.x (#1864)
by Ramon
05:46
created

UIDReferenceDataConverter.toFieldValue()   A

Complexity

Conditions 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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