Passed
Push — master ( faba06...81555f )
by Guangyu
08:00 queued 11s
created

core.wechatmessage   F

Complexity

Total Complexity 69

Size/Duplication

Total Lines 330
Duplicated Lines 57.58 %

Importance

Changes 0
Metric Value
wmc 69
eloc 256
dl 190
loc 330
rs 2.88
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A WechatMessageItem.__init__() 4 4 1
B WechatMessageItem.on_delete() 33 33 8
F WechatMessageCollection.on_get() 73 73 14
A WechatMessageCollection.__init__() 0 4 1
F WechatMessageCollection.on_post() 35 152 35
A WechatMessageItem.on_options() 3 3 1
B WechatMessageItem.on_get() 38 38 8
A WechatMessageCollection.on_options() 0 3 1

How to fix   Duplicated Code    Complexity   

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:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like core.wechatmessage often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
import re
2
import falcon
3
import simplejson as json
4
import mysql.connector
5
import config
6
from datetime import datetime, timedelta, timezone
7
from core.useractivity import user_logger, access_control
8
9
10
class WechatMessageCollection(object):
11
    @staticmethod
12
    def __init__():
13
        """"Initializes WechatMessageCollection"""
14
        pass
15
16
    @staticmethod
17
    def on_options(req, resp):
18
        resp.status = falcon.HTTP_200
19
20 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
21
    def on_get(req, resp):
22
        access_control(req)
23
24
        start_datetime_local = req.params.get('startdatetime')
25
        end_datetime_local = req.params.get('enddatetime')
26
27
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
28
        if config.utc_offset[0] == '-':
29
            timezone_offset = -timezone_offset
30
31
        if start_datetime_local is None:
32
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
33
                                   description="API.INVALID_START_DATETIME_FORMAT")
34
        else:
35
            start_datetime_local = str.strip(start_datetime_local)
36
            try:
37
                start_datetime_utc = datetime.strptime(start_datetime_local,
38
                                                       '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
39
                                     timedelta(minutes=timezone_offset)
40
            except ValueError:
41
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
42
                                       description="API.INVALID_START_DATETIME_FORMAT")
43
44
        if end_datetime_local is None:
45
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
46
                                   description="API.INVALID_END_DATETIME_FORMAT")
47
        else:
48
            end_datetime_local = str.strip(end_datetime_local)
49
            try:
50
                end_datetime_utc = datetime.strptime(end_datetime_local,
51
                                                     '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
52
                                   timedelta(minutes=timezone_offset)
53
            except ValueError:
54
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
55
                                       description="API.INVALID_END_DATETIME_FORMAT")
56
57
        if start_datetime_utc >= end_datetime_utc:
58
            raise falcon.HTTPError(falcon.HTTP_400,
59
                                   title='API.BAD_REQUEST',
60
                                   description='API.START_DATETIME_MUST_BE_EARLIER_THAN_END_DATETIME')
61
        cnx = mysql.connector.connect(**config.myems_fdd_db)
62
        cursor = cnx.cursor()
63
64
        query = (" SELECT id, recipient_name, recipient_openid, message_template_id, "
65
                 "        message_data, created_datetime_utc, scheduled_datetime_utc, "
66
                 "        acknowledge_code, status "
67
                 " FROM tbl_wechat_messages_outbox "
68
                 " WHERE created_datetime_utc >= %s AND created_datetime_utc < %s "
69
                 " ORDER BY created_datetime_utc DESC ")
70
        cursor.execute(query, (start_datetime_utc, end_datetime_utc))
71
        rows = cursor.fetchall()
72
73
        if cursor:
74
            cursor.close()
75
        if cnx:
76
            cnx.disconnect()
77
78
        result = list()
79
        if rows is not None and len(rows) > 0:
80
            for row in rows:
81
                meta_result = {"id": row[0],
82
                               "recipient_name": row[1],
83
                               "recipient_openid": row[2],
84
                               "message_template_id": row[3],
85
                               "message_data": row[4],
86
                               "created_datetime_utc": row[5].timestamp() * 1000 if isinstance(row[5], datetime) else None,
87
                               "scheduled_datetime_utc": row[6].timestamp() * 1000 if isinstance(row[6], datetime) else None,
88
                               "acknowledge_code": row[7],
89
                               "status": row[8]}
90
                result.append(meta_result)
91
92
        resp.text = json.dumps(result)
93
94
    @staticmethod
95
    @user_logger
96
    def on_post(req, resp):
97
        """Handles POST requests"""
98
        access_control(req)
99
100
        try:
101
            raw_json = req.stream.read().decode('utf-8')
102
        except Exception as ex:
103
            raise falcon.HTTPError(falcon.HTTP_400, title='API.ERROR', description=ex)
104
105
        new_values = json.loads(raw_json)
106
107
        if 'rule_id' in new_values['data'].keys():
108
            if new_values['data']['rule_id'] <= 0:
109
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
110
                                       description='API.INVALID_RULE_ID')
111
            rule_id = new_values['data']['rule_id']
112
        else:
113
            rule_id = None
114
115
        if 'recipient_name' not in new_values['data'].keys() or \
116
                not isinstance(new_values['data']['recipient_name'], str) or \
117
                len(str.strip(new_values['data']['recipient_name'])) == 0:
118
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
119
                                   description='API.INVALID_RECIPIENT_NAME')
120
        recipient_name = str.strip(new_values['data']['recipient_name'])
121
122
        if 'recipient_openid' not in new_values['data'].keys() or \
123
                not isinstance(new_values['data']['recipient_openid'], str) or \
124
                len(str.strip(new_values['data']['recipient_openid'])) == 0:
125
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
126
                                   description='API.INVALID_RECIPIENT_OPENID')
127
        recipient_openid = str.strip(new_values['data']['recipient_openid'])
128
        match = re.match(r'^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[\da-zA-Z-_]{28}$', recipient_openid)
129
        if match is None:
130
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
131
                                   description='API.INVALID_OPENID')
132
133
        if 'message_template_id' not in new_values['data'].keys() or \
134
                not isinstance(new_values['data']['message_template_id'], str) or \
135
                len(str.strip(new_values['data']['message_template_id'])) == 0:
136
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
137
                                   description='API.INVALID_MESSAGE_TEMPLATE_ID')
138
        message_template_id = str.strip(new_values['data']['message_template_id'])
139
        match = re.match(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[\w-]{43}$', message_template_id)
140
        if match is None:
141
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
142
                                   description='API.INVALID_MESSAGE_TEMPLATE_ID')
143
144
        if 'message_data' not in new_values['data'].keys() or \
145
                not isinstance(new_values['data']['message_data'], str) or \
146
                len(str.strip(new_values['data']['message_data'])) == 0:
147
            raise falcon.HTTPError(falcon.HTTP_400,
148
                                   title='API.BAD_REQUEST',
149
                                   description='API.INVALID_MESSAGE_DATA')
150
        message_data = str.strip(new_values['data']['message_data'])
151
        # validate expression in json
152
        try:
153
            json.loads(message_data)
154
        except Exception as ex:
155
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST', description=ex)
156
157
        if 'acknowledge_code' not in new_values['data'].keys() or \
158
                not isinstance(new_values['data']['acknowledge_code'], str) or \
159
                len(str.strip(new_values['data']['acknowledge_code'])) == 0:
160
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
161
                                   description='API.INVALID_ACKNOWLEDGE_CODE')
162
        acknowledge_code = str.strip(new_values['data']['acknowledge_code'])
163
164
        if 'created_datetime' not in new_values['data'].keys() or \
165
                not isinstance(new_values['data']['created_datetime'], str) or \
166
                len(str.strip(new_values['data']['created_datetime'])) == 0:
167
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
168
                                   description='API.INVALID_CREATED_DATETIME')
169
        created_datetime_local = str.strip(new_values['data']['created_datetime'])
170
171
        if 'scheduled_datetime' not in new_values['data'].keys() or \
172
                not isinstance(new_values['data']['scheduled_datetime'], str) or \
173
                len(str.strip(new_values['data']['scheduled_datetime'])) == 0:
174
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
175
                                   description='API.INVALID_SCHEDULED_DATETIME')
176
        scheduled_datetime_local = str.strip(new_values['data']['scheduled_datetime'])
177
178
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
179
        if config.utc_offset[0] == '-':
180
            timezone_offset = -timezone_offset
181
182 View Code Duplication
        if created_datetime_local is None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
183
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
184
                                   description="API.INVALID_CREATED_DATETIME")
185
        else:
186
            created_datetime_local = str.strip(created_datetime_local)
187
            try:
188
                created_datetime_utc = datetime.strptime(created_datetime_local,
189
                                                         '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
190
                                     timedelta(minutes=timezone_offset)
191
            except ValueError:
192
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
193
                                       description="API.INVALID_CREATED_DATETIME")
194
195 View Code Duplication
        if scheduled_datetime_local is None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
196
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
197
                                   description="API.INVALID_SCHEDULED_DATETIME")
198
        else:
199
            scheduled_datetime_local = str.strip(scheduled_datetime_local)
200
            try:
201
                scheduled_datetime_utc = datetime.strptime(scheduled_datetime_local,
202
                                                           '%Y-%m-%dT%H:%M:%S').replace(tzinfo=timezone.utc) - \
203
                                     timedelta(minutes=timezone_offset)
204
            except ValueError:
205
                raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
206
                                       description="API.INVALID_SCHEDULED_DATETIME")
207
208
        status = 'new'
209
210
        cnx = mysql.connector.connect(**config.myems_fdd_db)
211
        cursor = cnx.cursor()
212
213 View Code Duplication
        if rule_id is not None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
214
            cursor.execute(" SELECT name "
215
                           " FROM tbl_rules "
216
                           " WHERE id = %s ",
217
                           (new_values['data']['rule_id'],))
218
            row = cursor.fetchone()
219
            if row is None:
220
                cursor.close()
221
                cnx.disconnect()
222
                raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
223
                                       description='API.RULE_NOT_FOUND')
224
225
        add_row = (" INSERT INTO tbl_wechat_messages_outbox"
226
                   "             (rule_id, recipient_name, recipient_openid, message_template_id, message_data,"
227
                   "              acknowledge_code, created_datetime_utc, scheduled_datetime_utc, status) "
228
                   " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) ")
229
230
        cursor.execute(add_row, (rule_id,
231
                                 recipient_name,
232
                                 recipient_openid,
233
                                 message_template_id,
234
                                 message_data,
235
                                 acknowledge_code,
236
                                 created_datetime_utc,
237
                                 scheduled_datetime_utc,
238
                                 status))
239
        new_id = cursor.lastrowid
240
        cnx.commit()
241
        cursor.close()
242
        cnx.disconnect()
243
244
        resp.status = falcon.HTTP_201
245
        resp.location = '/wechatmessages/' + str(new_id)
246
247
248 View Code Duplication
class WechatMessageItem:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
249
    @staticmethod
250
    def __init__():
251
        """"Initializes WechatMessageItem"""
252
        pass
253
254
    @staticmethod
255
    def on_options(req, resp, id_):
256
        resp.status = falcon.HTTP_200
257
258
    @staticmethod
259
    def on_get(req, resp, id_):
260
        access_control(req)
261
        if not id_.isdigit() or int(id_) <= 0:
262
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
263
                                   description='API.INVALID_WECHAT_MESSAGE_ID')
264
265
        cnx = mysql.connector.connect(**config.myems_fdd_db)
266
        cursor = cnx.cursor()
267
268
        query = (" SELECT id, recipient_name, recipient_openid, message_template_id, "
269
                 "        message_data, created_datetime_utc, scheduled_datetime_utc, "
270
                 "        acknowledge_code, status "
271
                 " FROM tbl_wechat_messages_outbox "
272
                 " WHERE id = %s ")
273
        cursor.execute(query, (id_,))
274
        row = cursor.fetchone()
275
276
        if cursor:
277
            cursor.close()
278
        if cnx:
279
            cnx.disconnect()
280
281
        if row is None:
282
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
283
                                   description='API.WECHAT_MESSAGE_NOT_FOUND')
284
285
        result = {"id": row[0],
286
                  "recipient_name": row[1],
287
                  "recipient_openid": row[2],
288
                  "recipient_template_id": row[3],
289
                  "message_data": row[4],
290
                  "created_datetime_utc": row[5].timestamp() * 1000 if isinstance(row[5], datetime) else None,
291
                  "scheduled_datetime_utc": row[6].timestamp() * 1000 if isinstance(row[6], datetime) else None,
292
                  "acknowledge_code": row[7],
293
                  "status": row[8]}
294
295
        resp.text = json.dumps(result)
296
297
    @staticmethod
298
    @user_logger
299
    def on_delete(req, resp, id_):
300
        access_control(req)
301
        if not id_.isdigit() or int(id_) <= 0:
302
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
303
                                   description='API.INVALID_WECHAT_MESSAGE_ID')
304
305
        cnx = mysql.connector.connect(**config.myems_fdd_db)
306
        cursor = cnx.cursor()
307
308
        cursor.execute(" SELECT id "
309
                       " FROM tbl_wechat_messages_outbox "
310
                       " WHERE id = %s ", (id_,))
311
        row = cursor.fetchone()
312
313
        if row is None:
314
            if cursor:
315
                cursor.close()
316
            if cnx:
317
                cnx.disconnect()
318
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
319
                                   description='API.WECHAT_MESSAGE_NOT_FOUND')
320
321
        cursor.execute(" DELETE FROM tbl_wechat_messages_outbox WHERE id = %s ", (id_,))
322
        cnx.commit()
323
324
        if cursor:
325
            cursor.close()
326
        if cnx:
327
            cnx.disconnect()
328
329
        resp.status = falcon.HTTP_204
330