Passed
Push — master ( e3f582...5930d4 )
by Ramon
03:43
created

AuditLogView.before_render()   A

Complexity

Conditions 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
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
# SENAITE.CORE is free software: you can redistribute it and/or modify it under
6
# the terms of the GNU General Public License as published by the Free Software
7
# Foundation, version 2.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12
# details.
13
#
14
# You should have received a copy of the GNU General Public License along with
15
# this program; if not, write to the Free Software Foundation, Inc., 51
16
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
#
18
# Copyright 2018-2020 by it's authors.
19
# Some rights reserved, see README and LICENSE.
20
21
import collections
22
23
from bika.lims import api
24
from bika.lims import bikaMessageFactory as _
25
from bika.lims.api.snapshot import compare_snapshots
26
from bika.lims.api.snapshot import get_last_snapshot
27
from bika.lims.api.snapshot import get_snapshot_by_version
28
from bika.lims.api.snapshot import get_snapshot_metadata
29
from bika.lims.api.snapshot import get_snapshot_version
30
from bika.lims.browser.bika_listing import BikaListingView
31
from bika.lims.config import PROJECTNAME
32
from bika.lims.interfaces import IAuditLog
33
from bika.lims.utils import get_link
34
from plone.app.folder.folder import ATFolder
35
from plone.app.folder.folder import ATFolderSchema
36
from Products.Archetypes import atapi
37
from Products.ATContentTypes.content import schemata
38
from zope.interface.declarations import implements
39
40
41
class AuditLogView(BikaListingView):
42
43
    def __init__(self, context, request):
44
        super(AuditLogView, self).__init__(context, request)
45
46
        self.catalog = "auditlog_catalog"
47
48
        self.contentFilter = {
49
            "sort_on": "snapshot_created",
50
            "sort_order": "desscending",
51
        }
52
53
        self.context_actions = {}
54
55
        self.title = self.context.translate(_("Audit Log"))
56
        self.icon = "{}/{}".format(
57
            self.portal_url,
58
            "/++resource++bika.lims.images/auditlog_big.png"
59
        )
60
61
        self.show_select_column = False
62
        self.pagesize = 25
63
64
        self.columns = collections.OrderedDict((
65
            ("title", {
66
                "title": _("Title"),
67
                "index": "title"}),
68
            ("version", {
69
                "title": _("Version"),
70
                "index": "snapshot_version",
71
                "sortable": True}),
72
            ("modified", {
73
                "title": _("Date Modified"),
74
                "index": "modified",
75
                "sortable": True}),
76
            ("actor", {
77
                "title": _("Actor"),
78
                "index": "actor",
79
                "sortable": True}),
80
            ("fullname", {
81
                "title": _("Fullname"),
82
                "index": "fullname",
83
                "sortable": True}),
84
            ("roles", {
85
                "title": _("Roles"),
86
                "sortable": False,
87
                "toggle": False}),
88
            ("remote_address", {
89
                "title": _("Remote IP"),
90
                "sortable": True}),
91
            ("action", {
92
                "title": _("Action"),
93
                "index": "action",
94
                "sortable": True}),
95
            ("review_state", {
96
                "title": _("Workflow State"),
97
                "index": "review_state",
98
                "sortable": True}),
99
            ("diff", {
100
                "title": _("Changes"),
101
                "sortable": False}),
102
        ))
103
104
        self.review_states = [
105
            {
106
                "id": "default",
107
                "title": _("Active"),
108
                "contentFilter": {},
109
                "columns": self.columns.keys(),
110
            }
111
        ]
112
113
    def before_render(self):
114
        """Before template render hook
115
        """
116
        # Don't allow any context actions
117
        self.request.set("disable_border", 1)
118
119
    def folderitem(self, obj, item, index):
120
        """Service triggered each time an item is iterated in folderitems.
121
        The use of this service prevents the extra-loops in child objects.
122
        :obj: the instance of the class to be foldered
123
        :item: dict containing the properties of the object to be used by
124
            the template
125
        :index: current index of the item
126
        """
127
        obj = api.get_object(obj)
128
129
        # We are using the existing logic from the auditview
130
        logview = api.get_view("auditlog", context=obj, request=self.request)
131
132
        # get the last snapshot
133
        snapshot = get_last_snapshot(obj)
134
        # get the metadata of the last snapshot
135
        metadata = get_snapshot_metadata(snapshot)
136
137
        title = obj.Title()
138
        url = obj.absolute_url()
139
        auditlog_url = "{}/@@auditlog".format(url)
140
141
        # Title
142
        item["title"] = title
143
        # Link the title to the auditlog of the object
144
        item["replace"]["title"] = get_link(auditlog_url, value=title)
145
146
        # Version
147
        version = get_snapshot_version(obj, snapshot)
148
        item["version"] = version
149
150
        # Modification Date
151
        m_date = metadata.get("modified")
152
        item["modified"] = logview.to_localized_time(m_date)
153
154
        # Actor
155
        actor = metadata.get("actor")
156
        item["actor"] = actor
157
158
        # Fullname
159
        properties = api.get_user_properties(actor)
160
        item["fullname"] = properties.get("fullname", actor)
161
162
        # Roles
163
        roles = metadata.get("roles", [])
164
        item["roles"] = ", ".join(roles)
165
166
        # Remote Address
167
        remote_address = metadata.get("remote_address")
168
        item["remote_address"] = remote_address
169
170
        # Action
171
        action = metadata.get("action")
172
        item["action"] = logview.translate_state(action)
173
174
        # Review State
175
        review_state = metadata.get("review_state")
176
        item["review_state"] = logview.translate_state(review_state)
177
178
        # get the previous snapshot
179
        prev_snapshot = get_snapshot_by_version(obj, version-1)
180 View Code Duplication
        if prev_snapshot:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
181
            prev_metadata = get_snapshot_metadata(prev_snapshot)
182
            prev_review_state = prev_metadata.get("review_state")
183
            if prev_review_state != review_state:
184
                item["replace"]["review_state"] = "{} → {}".format(
185
                    logview.translate_state(prev_review_state),
186
                    logview.translate_state(review_state))
187
188
            # Rendered Diff
189
            diff = compare_snapshots(snapshot, prev_snapshot)
190
            item["diff"] = logview.render_diff(diff)
191
192
        return item
193
194
195
schema = ATFolderSchema.copy()
196
197
198
class AuditLog(ATFolder):
199
    implements(IAuditLog)
200
    displayContentsTab = False
201
    schema = schema
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable schema does not seem to be defined.
Loading history...
202
203
204
schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False)
205
atapi.registerType(AuditLog, PROJECTNAME)
206