core.offlinemeter.OfflineMeterItem.on_delete()   F
last analyzed

Complexity

Conditions 23

Size

Total Lines 154
Code Lines 113

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 113
dl 0
loc 154
rs 0
c 0
b 0
f 0
cc 23
nop 3

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like core.offlinemeter.OfflineMeterItem.on_delete() 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 uuid
2
from datetime import datetime, timedelta
3
import falcon
4
import mysql.connector
5
import simplejson as json
6
from core.useractivity import user_logger, admin_control, access_control, api_key_control
7
import config
8
9
10
class OfflineMeterCollection:
11
    """
12
    Offline Meter Collection Resource
13
14
    This class handles CRUD operations for offline meter collection.
15
    It provides endpoints for listing all offline meters and creating new offline meters.
16
    Offline meters are used for manual energy data entry and tracking.
17
    """
18
    def __init__(self):
19
        """Initialize OfflineMeterCollection"""
20
        pass
21
22
    @staticmethod
23
    def on_options(req, resp):
24
        """Handle OPTIONS requests for CORS preflight"""
25
        _ = req
26
        resp.status = falcon.HTTP_200
27
28
    @staticmethod
29
    def on_get(req, resp):
30
        """
31
        Handle GET requests to retrieve all offline meters
32
33
        Returns a list of all offline meters with their metadata including:
34
        - Meter ID, name, and UUID
35
        - Energy category and energy item information
36
        - Cost center information
37
        - Counting status and hourly limits
38
        - Description
39
40
        Supports optional search query parameter 'q' for filtering by name or description.
41
42
        Args:
43
            req: Falcon request object
44
            resp: Falcon response object
45
        """
46
        # Check authentication - use API key if provided, otherwise use access control
47
        if 'API-KEY' not in req.headers or \
48
                not isinstance(req.headers['API-KEY'], str) or \
49
                len(str.strip(req.headers['API-KEY'])) == 0:
50
            access_control(req)
51
        else:
52
            api_key_control(req)
53
54
        # Get search query parameter
55
        search_query = req.get_param('q', default=None)
56
        if search_query is not None:
57
            search_query = search_query.strip()
58
        else:
59
            search_query = ''
60
61
        # Connect to database
62
        cnx = mysql.connector.connect(**config.myems_system_db)
63
        cursor = cnx.cursor()
64
65
        query = (" SELECT id, name, uuid "
66
                 " FROM tbl_energy_categories ")
67
        cursor.execute(query)
68
        rows_energy_categories = cursor.fetchall()
69
70
        energy_category_dict = dict()
71
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
72
            for row in rows_energy_categories:
73
                energy_category_dict[row[0]] = {"id": row[0],
74
                                                "name": row[1],
75
                                                "uuid": row[2]}
76
77
        query = (" SELECT id, name, uuid "
78
                 " FROM tbl_energy_items ")
79
        cursor.execute(query)
80
        rows_energy_items = cursor.fetchall()
81
82
        energy_item_dict = dict()
83
        if rows_energy_items is not None and len(rows_energy_items) > 0:
84
            for row in rows_energy_items:
85
                energy_item_dict[row[0]] = {"id": row[0],
86
                                            "name": row[1],
87
                                            "uuid": row[2]}
88
89
        query = (" SELECT id, name, uuid "
90
                 " FROM tbl_cost_centers ")
91
        cursor.execute(query)
92
        rows_cost_centers = cursor.fetchall()
93
94
        cost_center_dict = dict()
95
        if rows_cost_centers is not None and len(rows_cost_centers) > 0:
96
            for row in rows_cost_centers:
97
                cost_center_dict[row[0]] = {"id": row[0],
98
                                            "name": row[1],
99
                                            "uuid": row[2]}
100
101
        query = (" SELECT id, name, uuid, energy_category_id, "
102
                 "        is_counted, hourly_low_limit, hourly_high_limit, "
103
                 "        energy_item_id, cost_center_id, description "
104
                 " FROM tbl_offline_meters ")
105
        params = []
106
        if search_query:
107
            query += " WHERE name LIKE %s OR description LIKE %s "
108
            params = [f'%{search_query}%', f'%{search_query}%']
109
110
        query += " ORDER BY id "
111
        cursor.execute(query,params)
112
        rows_meters = cursor.fetchall()
113
114
        result = list()
115 View Code Duplication
        if rows_meters is not None and len(rows_meters) > 0:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
116
            for row in rows_meters:
117
                meta_result = {"id": row[0],
118
                               "name": row[1],
119
                               "uuid": row[2],
120
                               "energy_category": energy_category_dict.get(row[3], None),
121
                               "is_counted": True if row[4] else False,
122
                               "hourly_low_limit": row[5],
123
                               "hourly_high_limit": row[6],
124
                               "energy_item": energy_item_dict.get(row[7], None),
125
                               "cost_center": cost_center_dict.get(row[8], None),
126
                               "description": row[9]}
127
                result.append(meta_result)
128
129
        cursor.close()
130
        cnx.close()
131
        resp.text = json.dumps(result)
132
133
    @staticmethod
134
    @user_logger
135
    def on_post(req, resp):
136
        """Handles POST requests"""
137
        admin_control(req)
138
        try:
139
            raw_json = req.stream.read().decode('utf-8')
140
        except Exception as ex:
141
            print(str(ex))
142
            raise falcon.HTTPError(status=falcon.HTTP_400,
143
                                   title='API.BAD_REQUEST',
144
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
145
146
        new_values = json.loads(raw_json)
147
148
        if 'name' not in new_values['data'].keys() or \
149
                not isinstance(new_values['data']['name'], str) or \
150
                len(str.strip(new_values['data']['name'])) == 0:
151
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
152
                                   description='API.INVALID_OFFLINE_METER_NAME')
153
        name = str.strip(new_values['data']['name'])
154
155
        if 'energy_category_id' not in new_values['data'].keys() or \
156
                not isinstance(new_values['data']['energy_category_id'], int) or \
157
                new_values['data']['energy_category_id'] <= 0:
158
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
159
                                   description='API.INVALID_ENERGY_CATEGORY_ID')
160
        energy_category_id = new_values['data']['energy_category_id']
161
162
        if 'is_counted' not in new_values['data'].keys() or \
163
                not isinstance(new_values['data']['is_counted'], bool):
164
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
165
                                   description='API.INVALID_IS_COUNTED_VALUE')
166
        is_counted = new_values['data']['is_counted']
167
168
        if 'hourly_low_limit' not in new_values['data'].keys() or \
169
                not (isinstance(new_values['data']['hourly_low_limit'], float) or
170
                     isinstance(new_values['data']['hourly_low_limit'], int)):
171
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
172
                                   description='API.INVALID_HOURLY_LOW_LIMIT_VALUE')
173
        hourly_low_limit = new_values['data']['hourly_low_limit']
174
175
        if 'hourly_high_limit' not in new_values['data'].keys() or \
176
                not (isinstance(new_values['data']['hourly_high_limit'], float) or
177
                     isinstance(new_values['data']['hourly_high_limit'], int)):
178
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
179
                                   description='API.INVALID_HOURLY_HIGH_LIMIT_VALUE')
180
        hourly_high_limit = new_values['data']['hourly_high_limit']
181
182
        if 'cost_center_id' not in new_values['data'].keys() or \
183
                not isinstance(new_values['data']['cost_center_id'], int) or \
184
                new_values['data']['cost_center_id'] <= 0:
185
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
186
                                   description='API.INVALID_COST_CENTER_ID')
187
188
        cost_center_id = new_values['data']['cost_center_id']
189
190
        if 'energy_item_id' in new_values['data'].keys() and \
191
                new_values['data']['energy_item_id'] is not None:
192
            if not isinstance(new_values['data']['energy_item_id'], int) or \
193
                    new_values['data']['energy_item_id'] <= 0:
194
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
195
                                       description='API.INVALID_ENERGY_ITEM_ID')
196
            energy_item_id = new_values['data']['energy_item_id']
197
        else:
198
            energy_item_id = None
199
200
        if 'description' in new_values['data'].keys() and \
201
                new_values['data']['description'] is not None and \
202
                len(str(new_values['data']['description'])) > 0:
203
            description = str.strip(new_values['data']['description'])
204
        else:
205
            description = None
206
207
        cnx = mysql.connector.connect(**config.myems_system_db)
208
        cursor = cnx.cursor()
209
210
        cursor.execute(" SELECT name "
211
                       " FROM tbl_offline_meters "
212
                       " WHERE name = %s ", (name,))
213
        if cursor.fetchone() is not None:
214
            cursor.close()
215
            cnx.close()
216
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
217
                                   description='API.OFFLINE_METER_NAME_IS_ALREADY_IN_USE')
218
219
        cursor.execute(" SELECT name "
220
                       " FROM tbl_energy_categories "
221
                       " WHERE id = %s ",
222
                       (new_values['data']['energy_category_id'],))
223
        if cursor.fetchone() is None:
224
            cursor.close()
225
            cnx.close()
226
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
227
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
228 View Code Duplication
        if energy_item_id is not None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
229
            cursor.execute(" SELECT name, energy_category_id "
230
                           " FROM tbl_energy_items "
231
                           " WHERE id = %s ",
232
                           (new_values['data']['energy_item_id'],))
233
            row = cursor.fetchone()
234
            if row is None:
235
                cursor.close()
236
                cnx.close()
237
                raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
238
                                       description='API.ENERGY_ITEM_NOT_FOUND')
239
            else:
240
                if row[1] != energy_category_id:
241
                    cursor.close()
242
                    cnx.close()
243
                    raise falcon.HTTPError(status=falcon.HTTP_404, title='API.BAD_REQUEST',
244
                                           description='API.ENERGY_ITEM_IS_NOT_BELONG_TO_ENERGY_CATEGORY')
245
246
        cursor.execute(" SELECT name "
247
                       " FROM tbl_cost_centers "
248
                       " WHERE id = %s ",
249
                       (new_values['data']['cost_center_id'],))
250
        row = cursor.fetchone()
251
        if row is None:
252
            cursor.close()
253
            cnx.close()
254
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
255
                                   description='API.COST_CENTER_NOT_FOUND')
256
257
        add_values = (" INSERT INTO tbl_offline_meters "
258
                      "    (name, uuid, energy_category_id, "
259
                      "     is_counted, hourly_low_limit, hourly_high_limit, "
260
                      "     cost_center_id, energy_item_id, description) "
261
                      " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) ")
262
        cursor.execute(add_values, (name,
263
                                    str(uuid.uuid4()),
264
                                    energy_category_id,
265
                                    is_counted,
266
                                    hourly_low_limit,
267
                                    hourly_high_limit,
268
                                    cost_center_id,
269
                                    energy_item_id,
270
                                    description))
271
        new_id = cursor.lastrowid
272
        cnx.commit()
273
        cursor.close()
274
        cnx.close()
275
276
        resp.status = falcon.HTTP_201
277
        resp.location = '/offlinemeters/' + str(new_id)
278
279
280
class OfflineMeterItem:
281
    def __init__(self):
282
        pass
283
284
    @staticmethod
285
    def on_options(req, resp, id_):
286
        _ = req
287
        resp.status = falcon.HTTP_200
288
        _ = id_
289
290 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
291
    def on_get(req, resp, id_):
292
        if 'API-KEY' not in req.headers or \
293
                not isinstance(req.headers['API-KEY'], str) or \
294
                len(str.strip(req.headers['API-KEY'])) == 0:
295
            access_control(req)
296
        else:
297
            api_key_control(req)
298
        if not id_.isdigit() or int(id_) <= 0:
299
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
300
                                   description='API.INVALID_OFFLINE_METER_ID')
301
302
        cnx = mysql.connector.connect(**config.myems_system_db)
303
        cursor = cnx.cursor()
304
305
        query = (" SELECT id, name, uuid "
306
                 " FROM tbl_energy_categories ")
307
        cursor.execute(query)
308
        rows_energy_categories = cursor.fetchall()
309
310
        energy_category_dict = dict()
311
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
312
            for row in rows_energy_categories:
313
                energy_category_dict[row[0]] = {"id": row[0],
314
                                                "name": row[1],
315
                                                "uuid": row[2]}
316
317
        query = (" SELECT id, name, uuid "
318
                 " FROM tbl_energy_items ")
319
        cursor.execute(query)
320
        rows_energy_items = cursor.fetchall()
321
322
        energy_item_dict = dict()
323
        if rows_energy_items is not None and len(rows_energy_items) > 0:
324
            for row in rows_energy_items:
325
                energy_item_dict[row[0]] = {"id": row[0],
326
                                            "name": row[1],
327
                                            "uuid": row[2]}
328
329
        query = (" SELECT id, name, uuid "
330
                 " FROM tbl_cost_centers ")
331
        cursor.execute(query)
332
        rows_cost_centers = cursor.fetchall()
333
334
        cost_center_dict = dict()
335
        if rows_cost_centers is not None and len(rows_cost_centers) > 0:
336
            for row in rows_cost_centers:
337
                cost_center_dict[row[0]] = {"id": row[0],
338
                                            "name": row[1],
339
                                            "uuid": row[2]}
340
341
        query = (" SELECT id, name, uuid, energy_category_id, "
342
                 "        is_counted, hourly_low_limit, hourly_high_limit, "
343
                 "        energy_item_id, cost_center_id, description "
344
                 " FROM tbl_offline_meters "
345
                 " WHERE id = %s ")
346
        cursor.execute(query, (id_,))
347
        row = cursor.fetchone()
348
        cursor.close()
349
        cnx.close()
350
351
        if row is None:
352
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
353
                                   description='API.OFFLINE_METER_NOT_FOUND')
354
        else:
355
            meta_result = {"id": row[0],
356
                           "name": row[1],
357
                           "uuid": row[2],
358
                           "energy_category": energy_category_dict.get(row[3], None),
359
                           "is_counted": True if row[4] else False,
360
                           "hourly_low_limit": row[5],
361
                           "hourly_high_limit": row[6],
362
                           "energy_item": energy_item_dict.get(row[7], None),
363
                           "cost_center": cost_center_dict.get(row[8], None),
364
                           "description": row[9]}
365
366
        resp.text = json.dumps(meta_result)
367
368
    @staticmethod
369
    @user_logger
370
    def on_delete(req, resp, id_):
371
        admin_control(req)
372
        if not id_.isdigit() or int(id_) <= 0:
373
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
374
                                   description='API.INVALID_OFFLINE_METER_ID')
375
376
        cnx = mysql.connector.connect(**config.myems_system_db)
377
        cursor = cnx.cursor()
378
379
        cursor.execute(" SELECT uuid "
380
                       " FROM tbl_offline_meters "
381
                       " WHERE id = %s ", (id_,))
382
        row = cursor.fetchone()
383
        if row is None:
384
            cursor.close()
385
            cnx.close()
386
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
387
                                   description='API.OFFLINE_METER_NOT_FOUND')
388
        else:
389
            offline_meter_uuid = row[0]
390
391
        # check if this offline meter is being used by virtual meters
392
        cursor.execute(" SELECT vm.name "
393
                       " FROM tbl_variables va, tbl_virtual_meters vm "
394
                       " WHERE va.meter_id = %s AND va.meter_type = 'offline_meter' AND va.virtual_meter_id = vm.id ",
395
                       (id_,))
396
        row_virtual_meter = cursor.fetchone()
397
        if row_virtual_meter is not None:
398
            cursor.close()
399
            cnx.close()
400
            raise falcon.HTTPError(status=falcon.HTTP_400,
401
                                   title='API.BAD_REQUEST',
402
                                   description='API.THIS_OFFLINE_METER_IS_BEING_USED_BY_A_VIRTUAL_METER')
403
404
        # check relation with spaces
405
        cursor.execute(" SELECT id "
406
                       " FROM tbl_spaces_offline_meters "
407
                       " WHERE offline_meter_id = %s ", (id_,))
408
        rows_companies = cursor.fetchall()
409
        if rows_companies is not None and len(rows_companies) > 0:
410
            cursor.close()
411
            cnx.close()
412
            raise falcon.HTTPError(status=falcon.HTTP_400,
413
                                   title='API.BAD_REQUEST',
414
                                   description='API.THERE_IS_RELATION_WITH_SPACES')
415
416
        # check relation with combined equipments
417
        cursor.execute(" SELECT combined_equipment_id "
418
                       " FROM tbl_combined_equipments_offline_meters "
419
                       " WHERE offline_meter_id = %s ",
420
                       (id_,))
421
        rows_combined_equipments = cursor.fetchall()
422
        if rows_combined_equipments is not None and len(rows_combined_equipments) > 0:
423
            cursor.close()
424
            cnx.close()
425
            raise falcon.HTTPError(status=falcon.HTTP_400,
426
                                   title='API.BAD_REQUEST',
427
                                   description='API.THERE_IS_RELATION_WITH_COMBINED_EQUIPMENTS')
428
429
        # check relation with combined equipment parameters
430
        cursor.execute(" SELECT combined_equipment_id "
431
                       " FROM tbl_combined_equipments_parameters "
432
                       " WHERE numerator_meter_uuid = %s OR denominator_meter_uuid = %s",
433
                       (offline_meter_uuid, offline_meter_uuid,))
434
        rows_combined_equipments = cursor.fetchall()
435
        if rows_combined_equipments is not None and len(rows_combined_equipments) > 0:
436
            cursor.close()
437
            cnx.close()
438
            raise falcon.HTTPError(status=falcon.HTTP_400,
439
                                   title='API.BAD_REQUEST',
440
                                   description='API.THERE_IS_RELATION_WITH_COMBINED_EQUIPMENT_PARAMETERS')
441
442
        # check relations with tenants
443
        cursor.execute(" SELECT tenant_id "
444
                       " FROM tbl_tenants_offline_meters "
445
                       " WHERE offline_meter_id = %s ", (id_,))
446
        rows_tenants = cursor.fetchall()
447
        if rows_tenants is not None and len(rows_tenants) > 0:
448
            cursor.close()
449
            cnx.close()
450
            raise falcon.HTTPError(status=falcon.HTTP_400,
451
                                   title='API.BAD_REQUEST',
452
                                   description='API.THERE_IS_RELATION_WITH_TENANTS')
453
454
        # check relations with stores
455
        cursor.execute(" SELECT store_id "
456
                       " FROM tbl_stores_offline_meters "
457
                       " WHERE offline_meter_id = %s ", (id_,))
458
        rows_stores = cursor.fetchall()
459
        if rows_stores is not None and len(rows_stores) > 0:
460
            cursor.close()
461
            cnx.close()
462
            raise falcon.HTTPError(status=falcon.HTTP_400,
463
                                   title='API.BAD_REQUEST',
464
                                   description='API.THERE_IS_RELATION_WITH_STORES')
465
466
        # check relations with shopfloors
467
        cursor.execute(" SELECT shopfloor_id "
468
                       " FROM tbl_shopfloors_offline_meters "
469
                       " WHERE offline_meter_id = %s ", (id_,))
470
        rows_shopfloors = cursor.fetchall()
471
        if rows_shopfloors is not None and len(rows_shopfloors) > 0:
472
            cursor.close()
473
            cnx.close()
474
            raise falcon.HTTPError(status=falcon.HTTP_400,
475
                                   title='API.BAD_REQUEST',
476
                                   description='API.THERE_IS_RELATION_WITH_SHOPFLOORS')
477
478
        # check relations with equipments
479
        cursor.execute(" SELECT equipment_id "
480
                       " FROM tbl_equipments_offline_meters "
481
                       " WHERE offline_meter_id = %s ", (id_,))
482
        rows_equipments = cursor.fetchall()
483
        if rows_equipments is not None and len(rows_equipments) > 0:
484
            cursor.close()
485
            cnx.close()
486
            raise falcon.HTTPError(status=falcon.HTTP_400,
487
                                   title='API.BAD_REQUEST',
488
                                   description='API.THERE_IS_RELATION_WITH_EQUIPMENTS')
489
490
        # check relation with equipment parameters
491
        cursor.execute(" SELECT equipment_id "
492
                       " FROM tbl_equipments_parameters "
493
                       " WHERE numerator_meter_uuid = %s OR denominator_meter_uuid = %s",
494
                       (offline_meter_uuid, offline_meter_uuid,))
495
        rows_equipments = cursor.fetchall()
496
        if rows_equipments is not None and len(rows_equipments) > 0:
497
            cursor.close()
498
            cnx.close()
499
            raise falcon.HTTPError(status=falcon.HTTP_400,
500
                                   title='API.BAD_REQUEST',
501
                                   description='API.THERE_IS_RELATION_WITH_EQUIPMENT_PARAMETERS')
502
503
        # check relation with energy flow diagram links
504
        cursor.execute(" SELECT id "
505
                       " FROM tbl_energy_flow_diagrams_links "
506
                       " WHERE meter_uuid = %s ", (offline_meter_uuid,))
507
        rows_links = cursor.fetchall()
508
        if rows_links is not None and len(rows_links) > 0:
509
            cursor.close()
510
            cnx.close()
511
            raise falcon.HTTPError(status=falcon.HTTP_400,
512
                                   title='API.BAD_REQUEST',
513
                                   description='API.THERE_IS_RELATION_WITH_ENERGY_FLOW_DIAGRAM_LINKS')
514
515
        cursor.execute(" DELETE FROM tbl_offline_meters WHERE id = %s ", (id_,))
516
        cnx.commit()
517
518
        cursor.close()
519
        cnx.close()
520
521
        resp.status = falcon.HTTP_204
522
523
    @staticmethod
524
    @user_logger
525
    def on_put(req, resp, id_):
526
        """Handles PUT requests"""
527
        admin_control(req)
528
        try:
529
            raw_json = req.stream.read().decode('utf-8')
530
        except Exception as ex:
531
            print(str(ex))
532
            raise falcon.HTTPError(status=falcon.HTTP_400,
533
                                   title='API.BAD_REQUEST',
534
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
535
536
        if not id_.isdigit() or int(id_) <= 0:
537
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
538
                                   description='API.INVALID_OFFLINE_METER_ID')
539
540
        new_values = json.loads(raw_json)
541
542
        if 'name' not in new_values['data'].keys() or \
543
                not isinstance(new_values['data']['name'], str) or \
544
                len(str.strip(new_values['data']['name'])) == 0:
545
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
546
                                   description='API.INVALID_OFFLINE_METER_NAME')
547
        name = str.strip(new_values['data']['name'])
548
549
        if 'energy_category_id' not in new_values['data'].keys() or \
550
                not isinstance(new_values['data']['energy_category_id'], int) or \
551
                new_values['data']['energy_category_id'] <= 0:
552
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
553
                                   description='API.INVALID_ENERGY_CATEGORY_ID')
554
        energy_category_id = new_values['data']['energy_category_id']
555
556
        if 'is_counted' not in new_values['data'].keys() or \
557
                not isinstance(new_values['data']['is_counted'], bool):
558
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
559
                                   description='API.INVALID_IS_COUNTED_VALUE')
560
        is_counted = new_values['data']['is_counted']
561
562
        if 'hourly_low_limit' not in new_values['data'].keys() or \
563
                not (isinstance(new_values['data']['hourly_low_limit'], float) or
564
                     isinstance(new_values['data']['hourly_low_limit'], int)):
565
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
566
                                   description='API.INVALID_HOURLY_LOW_LIMIT_VALUE')
567
        hourly_low_limit = new_values['data']['hourly_low_limit']
568
569
        if 'hourly_high_limit' not in new_values['data'].keys() or \
570
                not (isinstance(new_values['data']['hourly_high_limit'], float) or
571
                     isinstance(new_values['data']['hourly_high_limit'], int)):
572
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
573
                                   description='API.INVALID_HOURLY_HIGH_LIMIT_VALUE')
574
        hourly_high_limit = new_values['data']['hourly_high_limit']
575
576
        if 'cost_center_id' not in new_values['data'].keys() or \
577
                not isinstance(new_values['data']['cost_center_id'], int) or \
578
                new_values['data']['cost_center_id'] <= 0:
579
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
580
                                   description='API.INVALID_COST_CENTER_ID')
581
582
        cost_center_id = new_values['data']['cost_center_id']
583
584
        if 'energy_item_id' in new_values['data'].keys() and \
585
                new_values['data']['energy_item_id'] is not None:
586
            if not isinstance(new_values['data']['energy_item_id'], int) or \
587
                    new_values['data']['energy_item_id'] <= 0:
588
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
589
                                       description='API.INVALID_ENERGY_ITEM_ID')
590
            energy_item_id = new_values['data']['energy_item_id']
591
        else:
592
            energy_item_id = None
593
594
        if 'description' in new_values['data'].keys() and \
595
                new_values['data']['description'] is not None and \
596
                len(str(new_values['data']['description'])) > 0:
597
            description = str.strip(new_values['data']['description'])
598
        else:
599
            description = None
600
601
        cnx = mysql.connector.connect(**config.myems_system_db)
602
        cursor = cnx.cursor()
603
604
        cursor.execute(" SELECT name "
605
                       " FROM tbl_offline_meters "
606
                       " WHERE id = %s ", (id_,))
607
        if cursor.fetchone() is None:
608
            cursor.close()
609
            cnx.close()
610
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
611
                                   description='API.OFFLINE_METER_NOT_FOUND')
612
613
        cursor.execute(" SELECT name "
614
                       " FROM tbl_offline_meters "
615
                       " WHERE name = %s AND id != %s ", (name, id_))
616
        if cursor.fetchone() is not None:
617
            cursor.close()
618
            cnx.close()
619
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
620
                                   description='API.OFFLINE_METER_NAME_IS_ALREADY_IN_USE')
621
622
        cursor.execute(" SELECT name "
623
                       " FROM tbl_energy_categories "
624
                       " WHERE id = %s ",
625
                       (new_values['data']['energy_category_id'],))
626
        if cursor.fetchone() is None:
627
            cursor.close()
628
            cnx.close()
629
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
630
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
631
632
        cursor.execute(" SELECT name "
633
                       " FROM tbl_cost_centers "
634
                       " WHERE id = %s ",
635
                       (new_values['data']['cost_center_id'],))
636
        row = cursor.fetchone()
637
        if row is None:
638
            cursor.close()
639
            cnx.close()
640
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
641
                                   description='API.COST_CENTER_NOT_FOUND')
642
643 View Code Duplication
        if energy_item_id is not None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
644
            cursor.execute(" SELECT name, energy_category_id "
645
                           " FROM tbl_energy_items "
646
                           " WHERE id = %s ",
647
                           (new_values['data']['energy_item_id'],))
648
            row = cursor.fetchone()
649
            if row is None:
650
                cursor.close()
651
                cnx.close()
652
                raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
653
                                       description='API.ENERGY_ITEM_NOT_FOUND')
654
            else:
655
                if row[1] != energy_category_id:
656
                    cursor.close()
657
                    cnx.close()
658
                    raise falcon.HTTPError(status=falcon.HTTP_404, title='API.BAD_REQUEST',
659
                                           description='API.ENERGY_ITEM_IS_NOT_BELONG_TO_ENERGY_CATEGORY')
660
661
        update_row = (" UPDATE tbl_offline_meters "
662
                      " SET name = %s, energy_category_id = %s,"
663
                      "     is_counted = %s, hourly_low_limit = %s, hourly_high_limit = %s, "
664
                      "     cost_center_id = %s, energy_item_id = %s, description = %s "
665
                      " WHERE id = %s ")
666
        cursor.execute(update_row, (name,
667
                                    energy_category_id,
668
                                    is_counted,
669
                                    hourly_low_limit,
670
                                    hourly_high_limit,
671
                                    cost_center_id,
672
                                    energy_item_id,
673
                                    description,
674
                                    id_,))
675
        cnx.commit()
676
677
        cursor.close()
678
        cnx.close()
679
680
        resp.status = falcon.HTTP_200
681
682
683
class OfflineMeterExport:
684
    def __init__(self):
685
        pass
686
687
    @staticmethod
688
    def on_options(req, resp, id_):
689
        _ = req
690
        resp.status = falcon.HTTP_200
691
        _ = id_
692
693 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
694
    def on_get(req, resp, id_):
695
        if 'API-KEY' not in req.headers or \
696
                not isinstance(req.headers['API-KEY'], str) or \
697
                len(str.strip(req.headers['API-KEY'])) == 0:
698
            access_control(req)
699
        else:
700
            api_key_control(req)
701
        if not id_.isdigit() or int(id_) <= 0:
702
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
703
                                   description='API.INVALID_OFFLINE_METER_ID')
704
705
        cnx = mysql.connector.connect(**config.myems_system_db)
706
        cursor = cnx.cursor()
707
708
        query = (" SELECT id, name, uuid "
709
                 " FROM tbl_energy_categories ")
710
        cursor.execute(query)
711
        rows_energy_categories = cursor.fetchall()
712
713
        energy_category_dict = dict()
714
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
715
            for row in rows_energy_categories:
716
                energy_category_dict[row[0]] = {"id": row[0],
717
                                                "name": row[1],
718
                                                "uuid": row[2]}
719
720
        query = (" SELECT id, name, uuid "
721
                 " FROM tbl_energy_items ")
722
        cursor.execute(query)
723
        rows_energy_items = cursor.fetchall()
724
725
        energy_item_dict = dict()
726
        if rows_energy_items is not None and len(rows_energy_items) > 0:
727
            for row in rows_energy_items:
728
                energy_item_dict[row[0]] = {"id": row[0],
729
                                            "name": row[1],
730
                                            "uuid": row[2]}
731
732
        query = (" SELECT id, name, uuid "
733
                 " FROM tbl_cost_centers ")
734
        cursor.execute(query)
735
        rows_cost_centers = cursor.fetchall()
736
737
        cost_center_dict = dict()
738
        if rows_cost_centers is not None and len(rows_cost_centers) > 0:
739
            for row in rows_cost_centers:
740
                cost_center_dict[row[0]] = {"id": row[0],
741
                                            "name": row[1],
742
                                            "uuid": row[2]}
743
744
        query = (" SELECT id, name, uuid, energy_category_id, "
745
                 "        is_counted, hourly_low_limit, hourly_high_limit, "
746
                 "        energy_item_id, cost_center_id, description "
747
                 " FROM tbl_offline_meters "
748
                 " WHERE id = %s ")
749
        cursor.execute(query, (id_,))
750
        row = cursor.fetchone()
751
        cursor.close()
752
        cnx.close()
753
754
        if row is None:
755
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
756
                                   description='API.OFFLINE_METER_NOT_FOUND')
757
        else:
758
            meta_result = {"id": row[0],
759
                           "name": row[1],
760
                           "uuid": row[2],
761
                           "energy_category": energy_category_dict.get(row[3], None),
762
                           "is_counted": True if row[4] else False,
763
                           "hourly_low_limit": row[5],
764
                           "hourly_high_limit": row[6],
765
                           "energy_item": energy_item_dict.get(row[7], None),
766
                           "cost_center": cost_center_dict.get(row[8], None),
767
                           "description": row[9]}
768
769
        resp.text = json.dumps(meta_result)
770
771
772
class OfflineMeterImport:
773
    def __init__(self):
774
        pass
775
776
    @staticmethod
777
    def on_options(req, resp):
778
        _ = req
779
        resp.status = falcon.HTTP_200
780
781
    @staticmethod
782
    @user_logger
783
    def on_post(req, resp):
784
        """Handles POST requests"""
785
        admin_control(req)
786
        try:
787
            raw_json = req.stream.read().decode('utf-8')
788
        except Exception as ex:
789
            print(str(ex))
790
            raise falcon.HTTPError(status=falcon.HTTP_400,
791
                                   title='API.BAD_REQUEST',
792
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
793
794
        new_values = json.loads(raw_json)
795
796
        if 'name' not in new_values.keys() or \
797
                not isinstance(new_values['name'], str) or \
798
                len(str.strip(new_values['name'])) == 0:
799
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
800
                                   description='API.INVALID_OFFLINE_METER_NAME')
801
        name = str.strip(new_values['name'])
802
803
        if 'energy_category' not in new_values.keys() or \
804
            'id' not in new_values['energy_category'].keys() or \
805
            not isinstance(new_values['energy_category']['id'], int) or \
806
                new_values['energy_category']['id'] <= 0:
807
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
808
                                   description='API.INVALID_ENERGY_CATEGORY_ID')
809
        energy_category_id = new_values['energy_category']['id']
810
811
        if 'is_counted' not in new_values.keys() or \
812
                not isinstance(new_values['is_counted'], bool):
813
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
814
                                   description='API.INVALID_IS_COUNTED_VALUE')
815
        is_counted = new_values['is_counted']
816
817
        if 'hourly_low_limit' not in new_values.keys() or \
818
                not (isinstance(new_values['hourly_low_limit'], float) or
819
                     isinstance(new_values['hourly_low_limit'], int)):
820
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
821
                                   description='API.INVALID_HOURLY_LOW_LIMIT_VALUE')
822
        hourly_low_limit = new_values['hourly_low_limit']
823
824
        if 'hourly_high_limit' not in new_values.keys() or \
825
                not (isinstance(new_values['hourly_high_limit'], float) or
826
                     isinstance(new_values['hourly_high_limit'], int)):
827
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
828
                                   description='API.INVALID_HOURLY_HIGH_LIMIT_VALUE')
829
        hourly_high_limit = new_values['hourly_high_limit']
830
831
        if 'cost_center' not in new_values.keys() or \
832
            new_values['cost_center'] is None or \
833
            'id' not in new_values['cost_center'].keys() or \
834
                not isinstance(new_values['cost_center']['id'], int) or \
835
                new_values['cost_center']['id'] <= 0:
836
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
837
                                   description='API.INVALID_COST_CENTER_ID')
838
839
        cost_center_id = new_values['cost_center']['id']
840
841 View Code Duplication
        if 'energy_item' in new_values.keys() and \
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
842
            new_values['energy_item'] is not None and \
843
                'id' in new_values['energy_item'].keys() and \
844
                new_values['energy_item']['id'] is not None:
845
            if not isinstance(new_values['energy_item']['id'], int) or \
846
                    new_values['energy_item']['id'] <= 0:
847
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
848
                                       description='API.INVALID_ENERGY_ITEM_ID')
849
            energy_item_id = new_values['energy_item']['id']
850
        else:
851
            energy_item_id = None
852
853
        if 'description' in new_values.keys() and \
854
                new_values['description'] is not None and \
855
                len(str(new_values['description'])) > 0:
856
            description = str.strip(new_values['description'])
857
        else:
858
            description = None
859
860
        cnx = mysql.connector.connect(**config.myems_system_db)
861
        cursor = cnx.cursor()
862
863
        cursor.execute(" SELECT name "
864
                       " FROM tbl_offline_meters "
865
                       " WHERE name = %s ", (name,))
866
        if cursor.fetchone() is not None:
867
            cursor.close()
868
            cnx.close()
869
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
870
                                   description='API.OFFLINE_METER_NAME_IS_ALREADY_IN_USE')
871
872
        cursor.execute(" SELECT name "
873
                       " FROM tbl_energy_categories "
874
                       " WHERE id = %s ",
875
                       (new_values['energy_category']['id'],))
876
        if cursor.fetchone() is None:
877
            cursor.close()
878
            cnx.close()
879
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
880
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
881 View Code Duplication
        if energy_item_id is not None:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
882
            cursor.execute(" SELECT name, energy_category_id "
883
                           " FROM tbl_energy_items "
884
                           " WHERE id = %s ",
885
                           (new_values['energy_item']['id'],))
886
            row = cursor.fetchone()
887
            if row is None:
888
                cursor.close()
889
                cnx.close()
890
                raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
891
                                       description='API.ENERGY_ITEM_NOT_FOUND')
892
            else:
893
                if row[1] != energy_category_id:
894
                    cursor.close()
895
                    cnx.close()
896
                    raise falcon.HTTPError(status=falcon.HTTP_404, title='API.BAD_REQUEST',
897
                                           description='API.ENERGY_ITEM_IS_NOT_BELONG_TO_ENERGY_CATEGORY')
898
899
        cursor.execute(" SELECT name "
900
                       " FROM tbl_cost_centers "
901
                       " WHERE id = %s ",
902
                       (new_values['cost_center']['id'],))
903
        row = cursor.fetchone()
904
        if row is None:
905
            cursor.close()
906
            cnx.close()
907
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
908
                                   description='API.COST_CENTER_NOT_FOUND')
909
910
        add_values = (" INSERT INTO tbl_offline_meters "
911
                      "    (name, uuid, energy_category_id, "
912
                      "     is_counted, hourly_low_limit, hourly_high_limit, "
913
                      "     cost_center_id, energy_item_id, description) "
914
                      " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) ")
915
        cursor.execute(add_values, (name,
916
                                    str(uuid.uuid4()),
917
                                    energy_category_id,
918
                                    is_counted,
919
                                    hourly_low_limit,
920
                                    hourly_high_limit,
921
                                    cost_center_id,
922
                                    energy_item_id,
923
                                    description))
924
        new_id = cursor.lastrowid
925
        cnx.commit()
926
        cursor.close()
927
        cnx.close()
928
929
        resp.status = falcon.HTTP_201
930
        resp.location = '/offlinemeters/' + str(new_id)
931
932
933
class OfflineMeterClone:
934
    def __init__(self):
935
        pass
936
937
    @staticmethod
938
    def on_options(req, resp, id_):
939
        _ = req
940
        resp.status = falcon.HTTP_200
941
        _ = id_
942
943
    @staticmethod
944
    @user_logger
945
    def on_post(req, resp, id_):
946
        admin_control(req)
947
        if not id_.isdigit() or int(id_) <= 0:
948
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
949
                                   description='API.INVALID_OFFLINE_METER_ID')
950
951
        cnx = mysql.connector.connect(**config.myems_system_db)
952
        cursor = cnx.cursor()
953
954
        query = (" SELECT id, name, uuid "
955
                 " FROM tbl_energy_categories ")
956
        cursor.execute(query)
957
        rows_energy_categories = cursor.fetchall()
958
959
        energy_category_dict = dict()
960
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
961
            for row in rows_energy_categories:
962
                energy_category_dict[row[0]] = {"id": row[0],
963
                                                "name": row[1],
964
                                                "uuid": row[2]}
965
966
        query = (" SELECT id, name, uuid "
967
                 " FROM tbl_energy_items ")
968
        cursor.execute(query)
969
        rows_energy_items = cursor.fetchall()
970
971
        energy_item_dict = dict()
972
        if rows_energy_items is not None and len(rows_energy_items) > 0:
973
            for row in rows_energy_items:
974
                energy_item_dict[row[0]] = {"id": row[0],
975
                                            "name": row[1],
976
                                            "uuid": row[2]}
977
978
        query = (" SELECT id, name, uuid "
979
                 " FROM tbl_cost_centers ")
980
        cursor.execute(query)
981
        rows_cost_centers = cursor.fetchall()
982
983
        cost_center_dict = dict()
984
        if rows_cost_centers is not None and len(rows_cost_centers) > 0:
985
            for row in rows_cost_centers:
986
                cost_center_dict[row[0]] = {"id": row[0],
987
                                            "name": row[1],
988
                                            "uuid": row[2]}
989
990
        query = (" SELECT id, name, uuid, energy_category_id, "
991
                 "        is_counted, hourly_low_limit, hourly_high_limit, "
992
                 "        energy_item_id, cost_center_id, description "
993
                 " FROM tbl_offline_meters "
994
                 " WHERE id = %s ")
995
        cursor.execute(query, (id_,))
996
        row = cursor.fetchone()
997
998
        if row is None:
999
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
1000
                                   description='API.OFFLINE_METER_NOT_FOUND')
1001
        else:
1002
            meta_result = {"id": row[0],
1003
                           "name": row[1],
1004
                           "uuid": row[2],
1005
                           "energy_category": energy_category_dict.get(row[3], None),
1006
                           "is_counted": True if row[4] else False,
1007
                           "hourly_low_limit": row[5],
1008
                           "hourly_high_limit": row[6],
1009
                           "energy_item": energy_item_dict.get(row[7], None),
1010
                           "cost_center": cost_center_dict.get(row[8], None),
1011
                           "description": row[9]}
1012
1013
            timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
1014
            if config.utc_offset[0] == '-':
1015
                timezone_offset = -timezone_offset
1016
            new_name = (str.strip(meta_result['name']) +
1017
                        (datetime.utcnow() + timedelta(minutes=timezone_offset)).isoformat(sep='-', timespec='seconds'))
1018
            energy_item_id = meta_result['energy_item']['id'] if meta_result['energy_item'] is not None else None
1019
            add_values = (" INSERT INTO tbl_offline_meters "
1020
                          "    (name, uuid, energy_category_id, "
1021
                          "     is_counted, hourly_low_limit, hourly_high_limit, "
1022
                          "     cost_center_id, energy_item_id, description) "
1023
                          " VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s) ")
1024
            cursor.execute(add_values, (new_name,
1025
                                        str(uuid.uuid4()),
1026
                                        meta_result['energy_category']['id'],
1027
                                        meta_result['is_counted'],
1028
                                        meta_result['hourly_low_limit'],
1029
                                        meta_result['hourly_high_limit'],
1030
                                        meta_result['cost_center']['id'],
1031
                                        energy_item_id,
1032
                                        meta_result['description']))
1033
            new_id = cursor.lastrowid
1034
            cnx.commit()
1035
            cursor.close()
1036
            cnx.close()
1037
1038
            resp.status = falcon.HTTP_201
1039
            resp.location = '/offlinemeters/' + str(new_id)
1040