Passed
Push — 2.x ( e13cd6...c491e4 )
by Jordi
07:30
created

bika.lims.controlpanel.auditlog   A

Complexity

Total Complexity 5

Size/Duplication

Total Lines 209
Duplicated Lines 37.8 %

Importance

Changes 0
Metric Value
wmc 5
eloc 125
dl 79
loc 209
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
B AuditLogView.__init__() 68 68 1
A AuditLogView.isItemAllowed() 0 5 1
B AuditLogView.folderitem() 11 74 3

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
# 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-2025 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 senaite.core.catalog import AUDITLOG_CATALOG
39
from senaite.core.interfaces import IHideActionsMenu
40
from zope.interface.declarations import implements
41
42
43
class AuditLogView(BikaListingView):
44
45 View Code Duplication
    def __init__(self, context, request):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
46
        super(AuditLogView, self).__init__(context, request)
47
48
        self.catalog = AUDITLOG_CATALOG
49
50
        self.contentFilter = {
51
            "path": "/",
52
            "sort_on": "snapshot_created",
53
            "sort_order": "descending",
54
        }
55
56
        self.context_actions = {}
57
58
        self.title = self.context.translate(_("Audit Log"))
59
        self.icon = "{}/{}".format(
60
            self.portal_url,
61
            "/++resource++bika.lims.images/auditlog_big.png"
62
        )
63
64
        self.show_select_column = False
65
        self.pagesize = 25
66
67
        self.columns = collections.OrderedDict((
68
            ("title", {
69
                "title": _("Title"),
70
                "index": "title"}),
71
            ("version", {
72
                "title": _("Version"),
73
                "index": "snapshot_version",
74
                "sortable": True}),
75
            ("modified", {
76
                "title": _("Date Modified"),
77
                "index": "modified",
78
                "sortable": True}),
79
            ("actor", {
80
                "title": _("Actor"),
81
                "index": "actor",
82
                "sortable": True}),
83
            ("fullname", {
84
                "title": _("Fullname"),
85
                "index": "fullname",
86
                "sortable": True}),
87
            ("roles", {
88
                "title": _("Roles"),
89
                "sortable": False,
90
                "toggle": False}),
91
            ("remote_address", {
92
                "title": _("Remote IP"),
93
                "sortable": True}),
94
            ("action", {
95
                "title": _("Action"),
96
                "index": "action",
97
                "sortable": True}),
98
            ("review_state", {
99
                "title": _("Workflow State"),
100
                "index": "review_state",
101
                "sortable": True}),
102
            ("diff", {
103
                "title": _("Changes"),
104
                "sortable": False}),
105
        ))
106
107
        self.review_states = [
108
            {
109
                "id": "default",
110
                "title": _("Active"),
111
                "contentFilter": {},
112
                "columns": self.columns.keys(),
113
            }
114
        ]
115
116
    def isItemAllowed(self, obj):
117
        """Skip items without snapshots
118
        """
119
        obj = api.get_object(obj)
120
        return get_last_snapshot(obj) is not None
121
122
    def folderitem(self, obj, item, index):
123
        """Service triggered each time an item is iterated in folderitems.
124
        The use of this service prevents the extra-loops in child objects.
125
        :obj: the instance of the class to be foldered
126
        :item: dict containing the properties of the object to be used by
127
            the template
128
        :index: current index of the item
129
        """
130
        obj = api.get_object(obj)
131
132
        # We are using the existing logic from the auditview
133
        logview = api.get_view("auditlog", context=obj, request=self.request)
134
135
        # get the last snapshot
136
        snapshot = get_last_snapshot(obj)
137
        # get the metadata of the last snapshot
138
        metadata = get_snapshot_metadata(snapshot)
139
140
        title = obj.Title()
141
        url = obj.absolute_url()
142
        auditlog_url = "{}/@@auditlog".format(url)
143
144
        # Title
145
        item["title"] = title
146
        # Link the title to the auditlog of the object
147
        item["replace"]["title"] = get_link(auditlog_url, value=title)
148
149
        # Version
150
        version = get_snapshot_version(obj, snapshot)
151
        item["version"] = version
152
153
        # Modification Date
154
        m_date = metadata.get("modified")
155
        item["modified"] = logview.to_localized_time(m_date)
156
157
        # Actor
158
        actor = metadata.get("actor")
159
        item["actor"] = actor
160
161
        # Fullname
162
        properties = api.get_user_properties(actor)
163
        item["fullname"] = properties.get("fullname", actor)
164
165
        # Roles
166
        roles = metadata.get("roles", [])
167
        item["roles"] = ", ".join(roles)
168
169
        # Remote Address
170
        remote_address = metadata.get("remote_address")
171
        item["remote_address"] = remote_address
172
173
        # Action
174
        action = metadata.get("action")
175
        item["action"] = logview.translate_state(action)
176
177
        # Review State
178
        review_state = metadata.get("review_state")
179
        item["review_state"] = logview.translate_state(review_state)
180
181
        # get the previous snapshot
182
        prev_snapshot = get_snapshot_by_version(obj, version-1)
183 View Code Duplication
        if prev_snapshot:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
184
            prev_metadata = get_snapshot_metadata(prev_snapshot)
185
            prev_review_state = prev_metadata.get("review_state")
186
            if prev_review_state != review_state:
187
                item["replace"]["review_state"] = "{} → {}".format(
188
                    logview.translate_state(prev_review_state),
189
                    logview.translate_state(review_state))
190
191
            # Rendered Diff
192
            diff = compare_snapshots(snapshot, prev_snapshot)
193
            item["diff"] = logview.render_diff(diff)
194
195
        return item
196
197
198
schema = ATFolderSchema.copy()
199
200
201
class AuditLog(ATFolder):
202
    implements(IAuditLog, IHideActionsMenu)
203
    displayContentsTab = False
204
    schema = schema
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable schema does not seem to be defined.
Loading history...
205
206
207
schemata.finalizeATCTSchema(schema, folderish=True, moveDiscussion=False)
208
atapi.registerType(AuditLog, PROJECTNAME)
209