Passed
Push — develop ( b44848...2798d2 )
by Dean
02:44
created

Status()   C

Complexity

Conditions 7

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 28
rs 5.5
cc 7
1
from core.helpers import catch_errors, pad_title, try_convert, redirect
0 ignored issues
show
Bug introduced by
The name helpers does not seem to exist in module core.
Loading history...
Configuration introduced by
The import core.helpers could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
2
3
from plugin.core.constants import PLUGIN_PREFIX
0 ignored issues
show
Configuration introduced by
The import plugin.core.constants could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
4
from plugin.core.environment import translate as _
0 ignored issues
show
Configuration introduced by
The import plugin.core.environment could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
5
from plugin.core.message import InterfaceMessages
0 ignored issues
show
Configuration introduced by
The import plugin.core.message could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
6
from plugin.managers.exception import ExceptionManager, MessageManager, VERSION_BASE
0 ignored issues
show
Configuration introduced by
The import plugin.managers.exception could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
7
from plugin.models import Exception, Message
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in Exception.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
Configuration introduced by
The import plugin.models could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
8
9
from ago import human
0 ignored issues
show
Configuration introduced by
The import ago could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
10
from datetime import datetime, timedelta
11
import logging
12
13
log = logging.getLogger(__name__)
14
15
CONNECTION_TYPES = [
16
    Message.Type.Plex,
17
    Message.Type.Sentry,
18
    Message.Type.Trakt
19
]
20
21
ERROR_TYPES = [
22
    Message.Type.Exception,
23
24
    Message.Type.Warning,
25
    Message.Type.Error,
26
    Message.Type.Critical
27
]
28
29
30
@route(PLUGIN_PREFIX + '/messages/list')
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'route'
Loading history...
31
@catch_errors
32
def ListMessages(days=14, version='latest', viewed=False, *args, **kwargs):
0 ignored issues
show
Unused Code introduced by
The argument kwargs seems to be unused.
Loading history...
Unused Code introduced by
The argument args seems to be unused.
Loading history...
33
    # Cast `viewed` to boolean
34
    if type(viewed) is str:
35
        if viewed == 'None':
36
            viewed = None
37
        else:
38
            viewed = viewed == 'True'
39
40
    # Retrieve messages
41
    messages = list(List(
42
        days=try_convert(days, int),
43
        version=version,
44
        viewed=viewed
45
    ).order_by(
46
        Message.last_logged_at.desc()
47
    ).limit(50))
48
49
    total_messages = List(
50
        days=try_convert(days, int),
51
        version=version,
52
    ).count()
53
54
    # Construct container
55
    oc = ObjectContainer(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ObjectContainer'
Loading history...
56
        title2=_("Messages")
57
    )
58
59
    # Add "Dismiss All" button
60
    if viewed is False and len(messages) > 1:
61
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
62
            key=Callback(DismissMessages),
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
63
            title=pad_title(_("Dismiss all"))
64
        ))
65
66
    # Add interface messages
67
    for record in InterfaceMessages.records:
68
        # Pick object thumb
69
        if record.level >= logging.WARNING:
70
            thumb = R("icon-error.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
71
        else:
72
            thumb = R("icon-notification.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
73
74
        # Add object
75
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
76
            key=PLUGIN_PREFIX + '/messages/list',
77
            title=pad_title('[%s] %s' % (logging.getLevelName(record.level).capitalize(), record.message)),
78
            thumb=thumb
79
        ))
80
81
    # Add stored messages
82
    for m in messages:
83
        if m.type is None or\
84
           m.summary is None:
85
            continue
86
87
        # Pick thumb
88
        if m.type == Message.Type.Exception:
89
            thumb = R("icon-exception-viewed.png") if m.viewed else R("icon-exception.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
90
        elif m.type == Message.Type.Info:
91
            thumb = R("icon-notification-viewed.png") if m.viewed else R("icon-notification.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
92
        elif m.type in CONNECTION_TYPES:
93
            thumb = R("icon-connection-viewed.png") if m.viewed else R("icon-connection.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
94
        else:
95
            thumb = R("icon-error-viewed.png") if m.viewed else R("icon-error.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
96
97
        # Add object
98
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
99
            key=Callback(ViewMessage, error_id=m.id),
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
100
            title=pad_title('[%s] %s' % (Message.Type.title(m.type), m.summary)),
101
            thumb=thumb
102
        ))
103
104
    # Append "View All" button
105
    if len(messages) != 50 and len(messages) < total_messages:
106
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
107
            key=Callback(ListMessages, days=None, viewed=None),
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
108
            title=pad_title(_("View All"))
109
        ))
110
111
    return oc
112
113
@route(PLUGIN_PREFIX + '/messages/view')
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'route'
Loading history...
114
@catch_errors
115
def ViewMessage(error_id, *args, **kwargs):
0 ignored issues
show
Unused Code introduced by
The argument kwargs seems to be unused.
Loading history...
Unused Code introduced by
The argument args seems to be unused.
Loading history...
116
    # Retrieve message from database
117
    message = MessageManager.get.by_id(error_id)
118
119
    # Update `last_viewed_at` field
120
    message.last_viewed_at = datetime.utcnow()
121
    message.save()
122
123
    # Parse request headers
124
    web_client = Request.Headers.get('X-Plex-Product', '').lower() == 'plex web'
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Request'
Loading history...
125
126
    # Build objects
127
    oc = ObjectContainer(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ObjectContainer'
Loading history...
128
        title2='[%s] %s' % (Message.Type.title(message.type), Trim(message.summary))
129
    )
130
131
    if message.type == Message.Type.Exception:
132
        # Display exception samples
133
        for e in message.exceptions.order_by(Exception.timestamp.desc()).limit(50):
134
            since = datetime.utcnow() - e.timestamp
135
136
            callback = Callback(ViewMessage, error_id=error_id)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
137
138
            if web_client:
139
                # Display exception traceback in Plex/Web
140
                callback = Callback(ViewException, exception_id=e.id)
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
141
142
            oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
143
                key=callback,
144
                title=pad_title('[%s] %s: %s' % (human(since, precision=1), e.type, e.message)),
145
                thumb=R("icon-exception.png")
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'R'
Loading history...
146
            ))
147
    elif message.type in [Message.Type.Info, Message.Type.Warning, Message.Type.Error, Message.Type.Critical]:
148
        # Display message code
149
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
150
            key='',
151
            title=pad_title(_('Code: %s') % hex(message.code))
152
        ))
153
154
        # Display message description
155
        if message.description:
156
            oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
157
                key='',
158
                title=pad_title(_('Description: %s') % message.description)
159
            ))
160
161
    return oc
162
163
@route(PLUGIN_PREFIX + '/exceptions/view')
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'route'
Loading history...
164
@catch_errors
165
def ViewException(exception_id, *args, **kwargs):
0 ignored issues
show
Unused Code introduced by
The argument kwargs seems to be unused.
Loading history...
Unused Code introduced by
The argument args seems to be unused.
Loading history...
166
    # Retrieve exception from database
167
    exception = ExceptionManager.get.by_id(exception_id)
168
169
    # Split traceback into lines
170
    traceback = exception.traceback
171
172
    if traceback:
173
        traceback = traceback.split('\n')
174
175
    # Build exception view
176
    oc = ObjectContainer(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'ObjectContainer'
Loading history...
177
        title2='%s: %s' % (exception.type, Trim(exception.message))
178
    )
179
180
    if not traceback:
181
        return oc
182
183
    for line in traceback:
184
        if not line:
185
            continue
186
187
        oc.add(DirectoryObject(
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'DirectoryObject'
Loading history...
188
            key=Callback(ViewException, exception_id=exception_id),
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Callback'
Loading history...
189
            title=pad_title(line)
190
        ))
191
192
    return oc
193
194
195
@route(PLUGIN_PREFIX + '/messages/dismissAll')
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'route'
Loading history...
196
@catch_errors
197
def DismissMessages(days=14, version='latest', *args, **kwargs):
0 ignored issues
show
Unused Code introduced by
The argument kwargs seems to be unused.
Loading history...
Unused Code introduced by
The argument args seems to be unused.
Loading history...
198
    # Retrieve messages that match the specified criteria
199
    messages = List(
200
        days=days,
201
        version=version,
202
        viewed=False
203
    )
204
205
    # Mark all messages as viewed
206
    for message in messages:
207
        # Update `last_viewed_at` field
208
        message.last_viewed_at = datetime.utcnow()
209
        message.save()
210
211
    # Redirect back to the messages view
212
    return redirect(
213
        '/messages/list',
214
        days=days,
215
        version=version
216
    )
217
218
219
def Status(viewed=None):
220
    """Get the number and type of messages logged in the last week"""
221
    messages = List(
222
        days=14,
223
        version='latest',
224
        viewed=viewed
225
    )
226
227
    count = 0
228
    type = 'notification'
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in type.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
229
230
    # Process stored messages
231
    for message in messages:
232
        if message.type in ERROR_TYPES:
233
            type = 'error'
234
        elif message.type in CONNECTION_TYPES and type != 'error':
235
            type = 'connection'
236
237
        count += 1
238
239
    # Process interface messages
240
    for record in InterfaceMessages.records:
241
        if record.level >= logging.ERROR:
242
            type = 'error'
243
244
        count += 1
245
246
    return count, type
247
248
249
def List(days=None, version=None, viewed=None):
250
    """Get messages logged in the last week"""
251
    where = []
252
253
    # Days
254
    if days is not None:
255
        where.append(
256
            Message.last_logged_at > datetime.utcnow() - timedelta(days=days)
257
        )
258
259
    # Version
260
    if version == 'latest':
261
        where.append(
262
            Message.version_base == VERSION_BASE
263
        )
264
    elif version is not None:
265
        log.warn('Unknown version specified: %r', version)
266
267
    # Viewed state
268
    if viewed is True:
269
        where.append(
270
            ~(Message.last_viewed_at >> None),
271
            Message.last_viewed_at > Message.last_logged_at
272
        )
273
    elif viewed is False:
274
        where.append(
275
            (Message.last_viewed_at >> None) | (Message.last_viewed_at < Message.last_logged_at)
276
        )
277
278
    # Build query
279
    if where:
280
        return MessageManager.get.where(*where)
281
282
    return MessageManager.get.all()
283
284
285
def Trim(value, length=45):
286
    if value and len(value) > length:
287
        return value[:length - 3] + "..."
288
289
    return value
290