Passed
Push — master ( 224b38...057b67 )
by Jordi
06:13 queued 01:53
created

bika.lims.browser.log.LogView.is_versionable()   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
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
# Copyright 2018 by it's authors.
6
# Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst.
7
8
import collections
9
10
from bika.lims import api
11
from bika.lims import bikaMessageFactory as _
12
from bika.lims.browser.bika_listing import BikaListingView
13
from plone.memoize import view
14
from DateTime import DateTime
15
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
16
from plone.app.layout.viewlets.content import ContentHistoryView
17
18
19
class LogView(BikaListingView):
20
    """Review/Revision log view
21
    """
22
23
    template = ViewPageTemplateFile("templates/log.pt")
24
25
    def __init__(self, context, request):
26
        super(LogView, self).__init__(context, request)
27
28
        self.show_select_column = False
29
        self.pagesize = 999999
30
        self.show_search = False
31
32
        self.icon = "{}/{}/{}".format(
33
            self.portal_url,
34
            "++resource++bika.lims.images",
35
            "%s_big.png" % context.portal_type.lower(),
36
        )
37
38
        self.title = "{} Log".format(api.get_title(context))
39
40
        self.columns = collections.OrderedDict((
41
            ("Version", {
42
                "title": _("Version"), "sortable": False}),
43
            ("Date", {
44
                "title": _("Date"), "sortable": False}),
45
            ("Actor", {
46
                "title": _("Actor"), "sortable": False}),
47
            ("Action", {
48
                "title": _("Action"), "sortable": False}),
49
            ("State", {
50
                "title": _("Outcome state"), "sortable": False}),
51
        ))
52
53
        # Do not display Version column if the content is not versionable
54
        if not self.is_versionable():
55
            del(self.columns["Version"])
56
57
        self.review_states = [
58
            {
59
                "id": "default",
60
                "title": "All",
61
                "contentFilter": {},
62
                "columns": self.columns.keys(),
63
            }
64
        ]
65
66
67
    def is_versionable(self):
68
        """Checks if the content is versionable
69
        """
70
        pr = api.get_tool("portal_repository")
71
        return pr.isVersionable(self.context)
72
73
    def update(self):
74
        """Update hook
75
        """
76
        super(LogView, self).update()
77
        self.total = len(self.get_full_history())
78
79
    def is_versioning_entry(self, entry):
80
        """Checks if the entry is a versioning entry
81
        """
82
        return entry.get("type") == "versioning"
83
84
    def to_title(self, id):
85
        """Convert an id to a human readable title
86
        """
87
        if not isinstance(id, basestring):
88
            return id
89
        return id.capitalize().replace("_", " ")
90
91
    def get_revision_history(self):
92
        """Return the revision history of the current context
93
        """
94
        chv = ContentHistoryView(self.context, self.request)
95
        return chv.revisionHistory()
96
97
    def get_review_history(self):
98
        """Return the review history of the current context
99
        """
100
        return api.get_review_history(self.context)
101
102
    @view.memoize
103
    def get_full_history(self):
104
        history = self.get_revision_history() + self.get_review_history()
105
        if len(history) == 0:
106
            return []
107
        history.sort(key=lambda x: x["time"], reverse=True)
108
        return history
109
110
    def get_entry_version(self, entry, default=0):
111
        """Return the version of the entry
112
        """
113
        version = entry.get("version_id", default) or default
114
        return version
115
116
    def get_entry_date(self, entry):
117
        """Return the action date
118
        """
119
        date = DateTime(entry.get("time"))
120
        return self.ulocalized_time(date, long_format=1),
121
122
    def get_entry_actor(self, entry):
123
        """Return the fullname of the actor
124
        """
125
        actor = None
126
        if self.is_versioning_entry(entry):
127
            # revision entries have an actor dict
128
            actor_dict = entry.get("actor")
129
            actor = actor_dict.get("fullname") or actor_dict.get("actorid")
130
        else:
131
            # review history items have only an actor id
132
            actor = entry.get("actor")
133
            # try to get the fullname
134
            props = api.get_user_properties(actor)
135
            actor = props.get("fullname") or actor
136
        # automatic transitions have no actor
137
        if actor is None:
138
            return ""
139
        return actor
140
141
    def get_entry_action(self, entry):
142
        """Return the action
143
        """
144
        action = None
145
        if self.is_versioning_entry(entry):
146
            # revision entries have a transition_title
147
            action = entry.get("transition_title")
148
        else:
149
            # review history items have only an action
150
            action = entry.get("action")
151
        # automatic transitions have no action
152
        if action is None:
153
            return ""
154
        # make the action human readable
155
        return _(self.to_title(action))
156
157
    def get_entry_state(self, entry):
158
        """Return the state
159
        """
160
        state = None
161
        if self.is_versioning_entry(entry):
162
            # revision entries have no state
163
            new_version = self.get_entry_version(entry)
164
            state = "{}: {}".format(_("Version"), new_version)
165
        else:
166
            # review history items have a state id
167
            state = entry.get("review_state")
168
        if not state:
169
            return ""
170
        return _(self.to_title(state))
171
172 View Code Duplication
    def make_empty_item(self, **kw):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
173
        """Create a new empty item
174
        """
175
        item = {
176
            "uid": None,
177
            "before": {},
178
            "after": {},
179
            "replace": {},
180
            "allow_edit": [],
181
            "disabled": False,
182
            "state_class": "state-active",
183
        }
184
        item.update(**kw)
185
        return item
186
187
    def make_log_entry(self, entry, index):
188
        """Create a log entry
189
        """
190
        item = self.make_empty_item(**entry)
191
192
        item["Version"] = self.get_entry_version(entry)
193
        item["Date"] = self.get_entry_date(entry)
194
        item["Actor"] = self.get_entry_actor(entry)
195
        item["Action"] = self.get_entry_action(entry)
196
        item["State"] = self.get_entry_state(entry)
197
198
        return item
199
200
    def folderitems(self):
201
        """Generate folderitems for each review history item
202
        """
203
        items = []
204
205
        history = self.get_full_history()
206
        for num, entry in enumerate(history):
207
            items.append(self.make_log_entry(entry, num))
208
        return items
209