core.virtualmeter.VirtualMeterItem.on_put()   F
last analyzed

Complexity

Conditions 54

Size

Total Lines 227
Code Lines 180

Duplication

Lines 30
Ratio 13.22 %

Importance

Changes 0
Metric Value
eloc 180
dl 30
loc 227
rs 0
c 0
b 0
f 0
cc 54
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.virtualmeter.VirtualMeterItem.on_put() 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 VirtualMeterCollection:
11
    def __init__(self):
12
        """"Initializes VirtualMeterCollection"""
13
        pass
14
15
    @staticmethod
16
    def on_options(req, resp):
17
        resp.status = falcon.HTTP_200
18
19
    @staticmethod
20
    def on_get(req, resp):
21
        if 'API-KEY' not in req.headers or \
22
                not isinstance(req.headers['API-KEY'], str) or \
23
                len(str.strip(req.headers['API-KEY'])) == 0:
24
            access_control(req)
25
        else:
26
            api_key_control(req)
27
        cnx = mysql.connector.connect(**config.myems_system_db)
28
        cursor = cnx.cursor()
29
30
        query = (" SELECT id, name, uuid "
31
                 " FROM tbl_energy_categories ")
32
        cursor.execute(query)
33
        rows_energy_categories = cursor.fetchall()
34
35
        energy_category_dict = dict()
36
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
37
            for row in rows_energy_categories:
38
                energy_category_dict[row[0]] = {"id": row[0],
39
                                                "name": row[1],
40
                                                "uuid": row[2]}
41
42
        query = (" SELECT id, name, uuid "
43
                 " FROM tbl_energy_items ")
44
        cursor.execute(query)
45
        rows_energy_items = cursor.fetchall()
46
47
        energy_item_dict = dict()
48
        if rows_energy_items is not None and len(rows_energy_items) > 0:
49
            for row in rows_energy_items:
50
                energy_item_dict[row[0]] = {"id": row[0],
51
                                            "name": row[1],
52
                                            "uuid": row[2]}
53
54
        query = (" SELECT id, name, uuid "
55
                 " FROM tbl_cost_centers ")
56
        cursor.execute(query)
57
        rows_cost_centers = cursor.fetchall()
58
59
        cost_center_dict = dict()
60
        if rows_cost_centers is not None and len(rows_cost_centers) > 0:
61
            for row in rows_cost_centers:
62
                cost_center_dict[row[0]] = {"id": row[0],
63
                                            "name": row[1],
64
                                            "uuid": row[2]}
65
66
        query = (" SELECT id, name, uuid, equation, energy_category_id, is_counted, cost_center_id, "
67
                 "        energy_item_id, description "
68
                 " FROM tbl_virtual_meters "
69
                 " ORDER BY id ")
70
        cursor.execute(query)
71
        rows_virtual_meters = cursor.fetchall()
72
73
        result = list()
74
        if rows_virtual_meters is not None and len(rows_virtual_meters) > 0:
75
            for row in rows_virtual_meters:
76
                meta_result = {"id": row[0],
77
                               "name": row[1],
78
                               "uuid": row[2],
79
                               "equation": row[3],
80
                               "energy_category": energy_category_dict.get(row[4], None),
81
                               "is_counted": True if row[5] else False,
82
                               "cost_center": cost_center_dict.get(row[6], None),
83
                               "energy_item": energy_item_dict.get(row[7], None),
84
                               "description": row[8],
85
                               "expression": {}}
86
87
                expression = dict()
88
89
                if meta_result["equation"] is not None:
90
                    expression = {'equation': meta_result["equation"], 'variables': []}
91
92
                    query_variables = (" SELECT v.id, v.name, v.meter_type, v.meter_id "
93
                                       " FROM tbl_virtual_meters vm, tbl_variables v "
94
                                       " WHERE vm.id = %s AND v.virtual_meter_id = vm.id "
95
                                       " ORDER BY SUBSTRING(v.name, 2, 10) + 0 ")
96
                    cursor.execute(query_variables, (meta_result['id'],))
97
                    rows_variables = cursor.fetchall()
98
                    if rows_variables is not None:
99
                        for row_variable in rows_variables:
100
                            if row_variable[2].lower() == 'meter':
101
                                query_meter = (" SELECT m.name "
102
                                               " FROM tbl_meters m "
103
                                               " WHERE m.id = %s ")
104
                                cursor.execute(query_meter, (row_variable[3],))
105
                                row_meter = cursor.fetchone()
106
                                if row_meter is not None:
107
                                    expression['variables'].append({'id': row_variable[0],
108
                                                                    'name': row_variable[1],
109
                                                                    'meter_type': row_variable[2],
110
                                                                    'meter_id': row_variable[3],
111
                                                                    'meter_name': row_meter[0]})
112
                            elif row_variable[2].lower() == 'offline_meter':
113
                                query_meter = (" SELECT m.name "
114
                                               " FROM tbl_offline_meters m "
115
                                               " WHERE m.id = %s ")
116
                                cursor.execute(query_meter, (row_variable[3],))
117
                                row_meter = cursor.fetchone()
118
                                if row_meter is not None:
119
                                    expression['variables'].append({'id': row_variable[0],
120
                                                                    'name': row_variable[1],
121
                                                                    'meter_type': row_variable[2],
122
                                                                    'meter_id': row_variable[3],
123
                                                                    'meter_name': row_meter[0]})
124
                            elif row_variable[2].lower() == 'virtual_meter':
125
                                query_meter = (" SELECT m.name "
126
                                               " FROM tbl_virtual_meters m "
127
                                               " WHERE m.id = %s ")
128
                                cursor.execute(query_meter, (row_variable[3],))
129
                                row_meter = cursor.fetchone()
130
                                if row_meter is not None:
131
                                    expression['variables'].append({'id': row_variable[0],
132
                                                                    'name': row_variable[1],
133
                                                                    'meter_type': row_variable[2],
134
                                                                    'meter_id': row_variable[3],
135
                                                                    'meter_name': row_meter[0]})
136
137
                meta_result['expression'] = expression
138
                result.append(meta_result)
139
140
        cursor.close()
141
        cnx.close()
142
        resp.text = json.dumps(result)
143
144
    @staticmethod
145
    @user_logger
146
    def on_post(req, resp):
147
        """Handles POST requests"""
148
        admin_control(req)
149
        try:
150
            raw_json = req.stream.read().decode('utf-8')
151
        except Exception as ex:
152
            raise falcon.HTTPError(status=falcon.HTTP_400,
153
                                   title='API.BAD_REQUEST',
154
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
155
156
        new_values = json.loads(raw_json)
157
158
        if 'name' not in new_values['data'].keys() or \
159
                not isinstance(new_values['data']['name'], str) or \
160
                len(str.strip(new_values['data']['name'])) == 0:
161
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
162
                                   description='API.INVALID_VIRTUAL_METER_NAME')
163
        name = str.strip(new_values['data']['name'])
164
165
        if 'energy_category_id' not in new_values['data'].keys() or new_values['data']['energy_category_id'] <= 0:
166
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
167
                                   description='API.INVALID_ENERGY_CATEGORY_ID')
168
        energy_category_id = new_values['data']['energy_category_id']
169
170
        if 'is_counted' not in new_values['data'].keys() or not isinstance(new_values['data']['is_counted'], bool):
171
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
172
                                   description='API.INVALID_IS_COUNTED_VALUE')
173
        is_counted = new_values['data']['is_counted']
174
175
        if 'cost_center_id' not in new_values['data'].keys() or \
176
                not isinstance(new_values['data']['cost_center_id'], int) or \
177
                new_values['data']['cost_center_id'] <= 0:
178
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
179
                                   description='API.INVALID_COST_CENTER_ID')
180
181
        cost_center_id = new_values['data']['cost_center_id']
182
183
        if 'energy_item_id' in new_values['data'].keys() and \
184
                new_values['data']['energy_item_id'] is not None:
185
            if not isinstance(new_values['data']['energy_item_id'], int) or \
186
                    new_values['data']['energy_item_id'] <= 0:
187
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
188
                                       description='API.INVALID_ENERGY_ITEM_ID')
189
            energy_item_id = new_values['data']['energy_item_id']
190
        else:
191
            energy_item_id = None
192
193
        if 'description' in new_values['data'].keys() and \
194
                new_values['data']['description'] is not None and \
195
                len(str(new_values['data']['description'])) > 0:
196
            description = str.strip(new_values['data']['description'])
197
        else:
198
            description = None
199
200
        if 'expression' not in new_values['data'].keys():
201
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
202
                                   description='API.INVALID_EXPRESSION_OBJECT')
203
204
        if 'equation' not in new_values['data']['expression'].keys() \
205
                or len(new_values['data']['expression']['equation']) == 0:
206
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
207
                                   description='API.INVALID_EQUATION_IN_EXPRESSION')
208
        # todo: validate equation with more rules
209
210
        if 'variables' not in new_values['data']['expression'].keys() \
211
                or len(new_values['data']['expression']['variables']) == 0:
212
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
213
                                   description='API.EMPTY_VARIABLES_ARRAY')
214
215
        for variable in new_values['data']['expression']['variables']:
216
            if 'name' not in variable.keys() or \
217
                    len(variable['name']) == 0:
218
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
219
                                       description='API.INVALID_VARIABLE_NAME')
220
            if 'meter_type' not in variable.keys() or \
221
                    len(variable['meter_type']) == 0 or \
222
                    variable['meter_type'].lower() not in ['meter', 'offline_meter', 'virtual_meter']:
223
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
224
                                       description='API.INVALID_VARIABLE_METER_TYPE')
225
            if 'meter_id' not in variable.keys() or \
226
                    variable['meter_id'] <= 0:
227
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
228
                                       description='API.INVALID_VARIABLE_METER_ID')
229
230
        cnx = mysql.connector.connect(**config.myems_system_db)
231
        cursor = cnx.cursor()
232
233
        cursor.execute(" SELECT name "
234
                       " FROM tbl_virtual_meters "
235
                       " WHERE name = %s ", (name,))
236
        if cursor.fetchone() is not None:
237
            cursor.close()
238
            cnx.close()
239
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.NOT_FOUND',
240
                                   description='API.VIRTUAL_METER_NAME_IS_ALREADY_IN_USE')
241
242
        cursor.execute(" SELECT name "
243
                       " FROM tbl_energy_categories "
244
                       " WHERE id = %s ",
245
                       (energy_category_id,))
246
        if cursor.fetchone() is None:
247
            cursor.close()
248
            cnx.close()
249
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
250
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
251
252
        cursor.execute(" SELECT name "
253
                       " FROM tbl_cost_centers "
254
                       " WHERE id = %s ",
255
                       (new_values['data']['cost_center_id'],))
256
        row = cursor.fetchone()
257
        if row is None:
258
            cursor.close()
259
            cnx.close()
260
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
261
                                   description='API.COST_CENTER_NOT_FOUND')
262
263 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...
264
            cursor.execute(" SELECT name, energy_category_id "
265
                           " FROM tbl_energy_items "
266
                           " WHERE id = %s ",
267
                           (new_values['data']['energy_item_id'],))
268
            row = cursor.fetchone()
269
            if row is None:
270
                cursor.close()
271
                cnx.close()
272
                raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
273
                                       description='API.ENERGY_ITEM_NOT_FOUND')
274
            else:
275
                if row[1] != energy_category_id:
276
                    cursor.close()
277
                    cnx.close()
278
                    raise falcon.HTTPError(status=falcon.HTTP_404, title='API.BAD_REQUEST',
279
                                           description='API.ENERGY_ITEM_IS_NOT_BELONG_TO_ENERGY_CATEGORY')
280
281
        for variable in new_values['data']['expression']['variables']:
282 View Code Duplication
            if variable['meter_type'].lower() == 'meter':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
283
                cursor.execute(" SELECT name "
284
                               " FROM tbl_meters "
285
                               " WHERE id = %s ", (variable['meter_id'],))
286
                if cursor.fetchone() is None:
287
                    cursor.close()
288
                    cnx.close()
289
                    raise falcon.HTTPError(status=falcon.HTTP_404,
290
                                           title='API.NOT_FOUND',
291
                                           description='API.METER_OF_VARIABLE_NOT_FOUND')
292
            elif variable['meter_type'].lower() == 'offline_meter':
293
                cursor.execute(" SELECT name "
294
                               " FROM tbl_offline_meters "
295
                               " WHERE id = %s ", (variable['meter_id'],))
296
                if cursor.fetchone() is None:
297
                    cursor.close()
298
                    cnx.close()
299
                    raise falcon.HTTPError(status=falcon.HTTP_404,
300
                                           title='API.NOT_FOUND',
301
                                           description='API.OFFLINE_METER_OF_VARIABLE_NOT_FOUND')
302
            elif variable['meter_type'].lower() == 'virtual_meter':
303
                cursor.execute(" SELECT name "
304
                               " FROM tbl_virtual_meters "
305
                               " WHERE id = %s ", (variable['meter_id'],))
306
                if cursor.fetchone() is None:
307
                    cursor.close()
308
                    cnx.close()
309
                    raise falcon.HTTPError(status=falcon.HTTP_404,
310
                                           title='API.NOT_FOUND',
311
                                           description='API.VIRTUAL_METER_OF_VARIABLE_NOT_FOUND')
312
313
        add_values = (" INSERT INTO tbl_virtual_meters "
314
                      "     (name, uuid, equation, energy_category_id, is_counted, "
315
                      "      cost_center_id, energy_item_id, description) "
316
                      " VALUES (%s, %s, %s, %s, %s, %s, %s, %s) ")
317
        cursor.execute(add_values, (name,
318
                                    str(uuid.uuid4()),
319
                                    new_values['data']['expression']['equation'].lower(),
320
                                    energy_category_id,
321
                                    is_counted,
322
                                    cost_center_id,
323
                                    energy_item_id,
324
                                    description))
325
        new_id = cursor.lastrowid
326
        cnx.commit()
327
328
        # add variables
329
        for variable in new_values['data']['expression']['variables']:
330
            add_values = (" INSERT INTO tbl_variables (name, virtual_meter_id, meter_type, meter_id) "
331
                          " VALUES (%s, %s, %s, %s) ")
332
            cursor.execute(add_values, (variable['name'].lower(),
333
                                        new_id,
334
                                        variable['meter_type'],
335
                                        variable['meter_id'],))
336
            cnx.commit()
337
338
        cursor.close()
339
        cnx.close()
340
341
        resp.status = falcon.HTTP_201
342
        resp.location = '/virtualmeters/' + str(new_id)
343
344
345
class VirtualMeterItem:
346
    def __init__(self):
347
        """"Initializes VirtualMeterItem"""
348
        pass
349
350
    @staticmethod
351
    def on_options(req, resp, id_):
352
        resp.status = falcon.HTTP_200
353
354 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
355
    def on_get(req, resp, id_):
356
        if 'API-KEY' not in req.headers or \
357
                not isinstance(req.headers['API-KEY'], str) or \
358
                len(str.strip(req.headers['API-KEY'])) == 0:
359
            access_control(req)
360
        else:
361
            api_key_control(req)
362
        if not id_.isdigit() or int(id_) <= 0:
363
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
364
                                   description='API.INVALID_VIRTUAL_METER_ID')
365
366
        cnx = mysql.connector.connect(**config.myems_system_db)
367
        cursor = cnx.cursor()
368
369
        query = (" SELECT id, name, uuid "
370
                 " FROM tbl_energy_categories ")
371
        cursor.execute(query)
372
        rows_energy_categories = cursor.fetchall()
373
374
        energy_category_dict = dict()
375
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
376
            for row in rows_energy_categories:
377
                energy_category_dict[row[0]] = {"id": row[0],
378
                                                "name": row[1],
379
                                                "uuid": row[2]}
380
381
        query = (" SELECT id, name, uuid, energy_category_id "
382
                 " FROM tbl_energy_items ")
383
        cursor.execute(query)
384
        rows_energy_items = cursor.fetchall()
385
386
        energy_item_dict = dict()
387
        if rows_energy_items is not None and len(rows_energy_items) > 0:
388
            for row in rows_energy_items:
389
                energy_item_dict[row[0]] = {"id": row[0],
390
                                            "name": row[1],
391
                                            "uuid": row[2]}
392
393
        query = (" SELECT id, name, uuid "
394
                 " FROM tbl_cost_centers ")
395
        cursor.execute(query)
396
        rows_cost_centers = cursor.fetchall()
397
398
        cost_center_dict = dict()
399
        if rows_cost_centers is not None and len(rows_cost_centers) > 0:
400
            for row in rows_cost_centers:
401
                cost_center_dict[row[0]] = {"id": row[0],
402
                                            "name": row[1],
403
                                            "uuid": row[2]}
404
405
        query = (" SELECT id, name, uuid, equation, energy_category_id, is_counted, cost_center_id, "
406
                 "        energy_item_id, description "
407
                 " FROM tbl_virtual_meters "
408
                 " WHERE id = %s ")
409
        cursor.execute(query, (id_,))
410
        row = cursor.fetchone()
411
        if row is None:
412
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
413
                                   description='API.VIRTUAL_METER_NOT_FOUND')
414
        else:
415
            meta_result = {"id": row[0],
416
                           "name": row[1],
417
                           "uuid": row[2],
418
                           "equation": row[3],
419
                           "energy_category": energy_category_dict.get(row[4], None),
420
                           "is_counted": True if row[5] else False,
421
                           "cost_center": cost_center_dict.get(row[6], None),
422
                           "energy_item": energy_item_dict.get(row[7], None),
423
                           "description": row[8],
424
                           "expression": {}}
425
426
        expression = dict()
427
428
        if meta_result["equation"] is not None:
429
            expression = {'equation': meta_result["equation"], 'variables': []}
430
431
            query_variables = (" SELECT v.id, v.name, v.meter_type, v.meter_id "
432
                               " FROM tbl_virtual_meters  vm, tbl_variables v "
433
                               " WHERE vm.id = %s AND v.virtual_meter_id = vm.id "
434
                               " ORDER BY v.name ")
435
            cursor.execute(query_variables, (meta_result["id"],))
436
            rows_variables = cursor.fetchall()
437
            if rows_variables is not None:
438
                for row_variable in rows_variables:
439
                    if row_variable[2].lower() == 'meter':
440
                        query_meter = (" SELECT m.name "
441
                                       " FROM tbl_meters m "
442
                                       " WHERE m.id = %s ")
443
                        cursor.execute(query_meter, (row_variable[3],))
444
                        row_meter = cursor.fetchone()
445
                        if row_meter is not None:
446
                            expression['variables'].append({'id': row_variable[0],
447
                                                            'name': row_variable[1],
448
                                                            'meter_type': row_variable[2],
449
                                                            'meter_id': row_variable[3],
450
                                                            'meter_name': row_meter[0]})
451
                    elif row_variable[2].lower() == 'offline_meter':
452
                        query_meter = (" SELECT m.name "
453
                                       " FROM tbl_offline_meters m "
454
                                       " WHERE m.id = %s ")
455
                        cursor.execute(query_meter, (row_variable[3],))
456
                        row_meter = cursor.fetchone()
457
                        if row_meter is not None:
458
                            expression['variables'].append({'id': row_variable[0],
459
                                                            'name': row_variable[1],
460
                                                            'meter_type': row_variable[2],
461
                                                            'meter_id': row_variable[3],
462
                                                            'meter_name': row_meter[0]})
463
                    elif row_variable[2].lower() == 'virtual_meter':
464
                        query_meter = (" SELECT m.name "
465
                                       " FROM tbl_virtual_meters m "
466
                                       " WHERE m.id = %s ")
467
                        cursor.execute(query_meter, (row_variable[3],))
468
                        row_meter = cursor.fetchone()
469
                        if row_meter is not None:
470
                            expression['variables'].append({'id': row_variable[0],
471
                                                            'name': row_variable[1],
472
                                                            'meter_type': row_variable[2],
473
                                                            'meter_id': row_variable[3],
474
                                                            'meter_name': row_meter[0]})
475
476
        meta_result['expression'] = expression
477
478
        cursor.close()
479
        cnx.close()
480
        resp.text = json.dumps(meta_result)
481
482
    @staticmethod
483
    @user_logger
484
    def on_delete(req, resp, id_):
485
        admin_control(req)
486
        if not id_.isdigit() or int(id_) <= 0:
487
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
488
                                   description='API.INVALID_VIRTUAL_METER_ID')
489
490
        cnx = mysql.connector.connect(**config.myems_system_db)
491
        cursor = cnx.cursor()
492
493
        cursor.execute(" SELECT uuid "
494
                       " FROM tbl_virtual_meters "
495
                       " WHERE id = %s ", (id_,))
496
        row = cursor.fetchone()
497
        if row is None:
498
            cursor.close()
499
            cnx.close()
500
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
501
                                   description='API.VIRTUAL_METER_NOT_FOUND')
502
        else:
503
            virtual_meter_uuid = row[0]
504
505
        # check relations with other virtual meters
506
        cursor.execute(" SELECT vm.name "
507
                       " FROM tbl_variables va, tbl_virtual_meters vm "
508
                       " WHERE va.meter_id = %s AND va.meter_type = 'virtual_meter' AND va.virtual_meter_id = vm.id ",
509
                       (id_,))
510
        row_virtual_meter = cursor.fetchone()
511
        if row_virtual_meter is not None:
512
            cursor.close()
513
            cnx.close()
514
            raise falcon.HTTPError(status=falcon.HTTP_400,
515
                                   title='API.BAD_REQUEST',
516
                                   description='API.THERE_IS_RELATION_WITH_OTHER_VIRTUAL_METERS')
517
518
        # check relation with spaces
519
        cursor.execute(" SELECT id "
520
                       " FROM tbl_spaces_virtual_meters "
521
                       " WHERE virtual_meter_id = %s ", (id_,))
522
        rows_spaces = cursor.fetchall()
523
        if rows_spaces is not None and len(rows_spaces) > 0:
524
            cursor.close()
525
            cnx.close()
526
            raise falcon.HTTPError(status=falcon.HTTP_400,
527
                                   title='API.BAD_REQUEST',
528
                                   description='API.THERE_IS_RELATION_WITH_SPACES')
529
530
        # check relation with combined equipments
531
        cursor.execute(" SELECT combined_equipment_id "
532
                       " FROM tbl_combined_equipments_virtual_meters "
533
                       " WHERE virtual_meter_id = %s ",
534
                       (id_,))
535
        rows_combined_equipments = cursor.fetchall()
536
        if rows_combined_equipments is not None and len(rows_combined_equipments) > 0:
537
            cursor.close()
538
            cnx.close()
539
            raise falcon.HTTPError(status=falcon.HTTP_400,
540
                                   title='API.BAD_REQUEST',
541
                                   description='API.THERE_IS_RELATION_WITH_COMBINED_EQUIPMENTS')
542
543
        # check relation with combined equipment parameters
544
        cursor.execute(" SELECT combined_equipment_id "
545
                       " FROM tbl_combined_equipments_parameters "
546
                       " WHERE numerator_meter_uuid = %s OR denominator_meter_uuid = %s",
547
                       (virtual_meter_uuid, virtual_meter_uuid,))
548
        rows_combined_equipments = cursor.fetchall()
549
        if rows_combined_equipments is not None and len(rows_combined_equipments) > 0:
550
            cursor.close()
551
            cnx.close()
552
            raise falcon.HTTPError(status=falcon.HTTP_400,
553
                                   title='API.BAD_REQUEST',
554
                                   description='API.THERE_IS_RELATION_WITH_COMBINED_EQUIPMENT_PARAMETERS')
555
556
        # check relation with equipments
557
        cursor.execute(" SELECT equipment_id "
558
                       " FROM tbl_equipments_virtual_meters "
559
                       " WHERE virtual_meter_id = %s ", (id_,))
560
        rows_equipments = cursor.fetchall()
561
        if rows_equipments is not None and len(rows_equipments) > 0:
562
            cursor.close()
563
            cnx.close()
564
            raise falcon.HTTPError(status=falcon.HTTP_400,
565
                                   title='API.BAD_REQUEST',
566
                                   description='API.THERE_IS_RELATION_WITH_EQUIPMENTS')
567
568
        # check relation with equipment parameters
569
        cursor.execute(" SELECT equipment_id "
570
                       " FROM tbl_equipments_parameters "
571
                       " WHERE numerator_meter_uuid = %s OR denominator_meter_uuid = %s",
572
                       (virtual_meter_uuid, virtual_meter_uuid,))
573
        rows_equipments = cursor.fetchall()
574
        if rows_equipments is not None and len(rows_equipments) > 0:
575
            cursor.close()
576
            cnx.close()
577
            raise falcon.HTTPError(status=falcon.HTTP_400,
578
                                   title='API.BAD_REQUEST',
579
                                   description='API.THERE_IS_RELATION_WITH_EQUIPMENT_PARAMETERS')
580
581
        # check relations with tenants
582
        cursor.execute(" SELECT tenant_id "
583
                       " FROM tbl_tenants_virtual_meters "
584
                       " WHERE virtual_meter_id = %s ", (id_,))
585
        rows_tenants = cursor.fetchall()
586
        if rows_tenants is not None and len(rows_tenants) > 0:
587
            cursor.close()
588
            cnx.close()
589
            raise falcon.HTTPError(status=falcon.HTTP_400,
590
                                   title='API.BAD_REQUEST',
591
                                   description='API.THERE_IS_RELATION_WITH_TENANTS')
592
593
        # check relations with stores
594
        cursor.execute(" SELECT store_id "
595
                       " FROM tbl_stores_virtual_meters "
596
                       " WHERE virtual_meter_id = %s ", (id_,))
597
        rows_stores = cursor.fetchall()
598
        if rows_stores is not None and len(rows_stores) > 0:
599
            cursor.close()
600
            cnx.close()
601
            raise falcon.HTTPError(status=falcon.HTTP_400,
602
                                   title='API.BAD_REQUEST',
603
                                   description='API.THERE_IS_RELATION_WITH_STORES')
604
605
        # check relations with shopfloors
606
        cursor.execute(" SELECT shopfloor_id "
607
                       " FROM tbl_shopfloors_virtual_meters "
608
                       " WHERE virtual_meter_id = %s ", (id_,))
609
        rows_shopfloors = cursor.fetchall()
610
        if rows_shopfloors is not None and len(rows_shopfloors) > 0:
611
            cursor.close()
612
            cnx.close()
613
            raise falcon.HTTPError(status=falcon.HTTP_400,
614
                                   title='API.BAD_REQUEST',
615
                                   description='API.THERE_IS_RELATION_WITH_SHOPFLOORS')
616
617
        # check relation with energy flow diagram links
618
        cursor.execute(" SELECT id "
619
                       " FROM tbl_energy_flow_diagrams_links "
620
                       " WHERE meter_uuid = %s ", (virtual_meter_uuid,))
621
        rows_links = cursor.fetchall()
622
        if rows_links is not None and len(rows_links) > 0:
623
            cursor.close()
624
            cnx.close()
625
            raise falcon.HTTPError(status=falcon.HTTP_400,
626
                                   title='API.BAD_REQUEST',
627
                                   description='API.THERE_IS_RELATION_WITH_ENERGY_FLOW_DIAGRAM_LINKS')
628
629
        cursor.execute(" SELECT id "
630
                       " FROM tbl_variables "
631
                       " WHERE virtual_meter_id = %s ", (id_,))
632
        row_variables = cursor.fetchall()
633
        if row_variables is not None and len(row_variables) > 0:
634
            # delete variables
635
            cursor.execute(" DELETE FROM tbl_variables WHERE virtual_meter_id = %s ", (id_,))
636
            cnx.commit()
637
638
        cursor.execute(" DELETE FROM tbl_virtual_meters WHERE id = %s ", (id_,))
639
        cnx.commit()
640
641
        cursor.close()
642
        cnx.close()
643
644
        resp.status = falcon.HTTP_204
645
646
    @staticmethod
647
    @user_logger
648
    def on_put(req, resp, id_):
649
        """Handles PUT requests"""
650
        admin_control(req)
651
        try:
652
            raw_json = req.stream.read().decode('utf-8')
653
        except Exception as ex:
654
            raise falcon.HTTPError(status=falcon.HTTP_400,
655
                                   title='API.BAD_REQUEST',
656
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
657
658
        if not id_.isdigit() or int(id_) <= 0:
659
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
660
                                   description='API.INVALID_VIRTUAL_METER_ID')
661
662
        new_values = json.loads(raw_json)
663
664
        if 'name' not in new_values['data'].keys() or \
665
                not isinstance(new_values['data']['name'], str) or \
666
                len(str.strip(new_values['data']['name'])) == 0:
667
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
668
                                   description='API.INVALID_VIRTUAL_METER_NAME')
669
        name = str.strip(new_values['data']['name'])
670
671
        if 'energy_category_id' not in new_values['data'].keys() or new_values['data']['energy_category_id'] <= 0:
672
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
673
                                   description='API.INVALID_ENERGY_CATEGORY_ID')
674
        energy_category_id = new_values['data']['energy_category_id']
675
676
        if 'is_counted' not in new_values['data'].keys() or not isinstance(new_values['data']['is_counted'], bool):
677
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
678
                                   description='API.INVALID_IS_COUNTED_VALUE')
679
        is_counted = new_values['data']['is_counted']
680
681
        if 'cost_center_id' not in new_values['data'].keys() or \
682
                not isinstance(new_values['data']['cost_center_id'], int) or \
683
                new_values['data']['cost_center_id'] <= 0:
684
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
685
                                   description='API.INVALID_COST_CENTER_ID')
686
687
        cost_center_id = new_values['data']['cost_center_id']
688
689
        if 'energy_item_id' in new_values['data'].keys() and \
690
                new_values['data']['energy_item_id'] is not None:
691
            if not isinstance(new_values['data']['energy_item_id'], int) or \
692
                    new_values['data']['energy_item_id'] <= 0:
693
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
694
                                       description='API.INVALID_ENERGY_ITEM_ID')
695
            energy_item_id = new_values['data']['energy_item_id']
696
        else:
697
            energy_item_id = None
698
699
        if 'description' in new_values['data'].keys() and \
700
                new_values['data']['description'] is not None and \
701
                len(str(new_values['data']['description'])) > 0:
702
            description = str.strip(new_values['data']['description'])
703
        else:
704
            description = None
705
706
        if 'expression' not in new_values['data'].keys():
707
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
708
                                   description='API.INVALID_EXPRESSION_OBJECT')
709
710
        if 'equation' not in new_values['data']['expression'].keys() \
711
                or len(new_values['data']['expression']['equation']) == 0:
712
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
713
                                   description='API.INVALID_EQUATION_IN_EXPRESSION')
714
        # todo: validate equation with more rules
715
716
        if 'variables' not in new_values['data']['expression'].keys() \
717
                or len(new_values['data']['expression']['variables']) == 0:
718
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
719
                                   description='API.EMPTY_VARIABLES_ARRAY')
720
721
        for variable in new_values['data']['expression']['variables']:
722
            if 'name' not in variable.keys() or \
723
                    len(variable['name']) == 0:
724
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
725
                                       description='API.INVALID_VARIABLE_NAME')
726
            if 'meter_type' not in variable.keys() or \
727
                len(variable['meter_type']) == 0 or \
728
                    variable['meter_type'].lower() not in ['meter', 'offline_meter', 'virtual_meter']:
729
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
730
                                       description='API.INVALID_VARIABLE_METER_TYPE')
731
            if 'meter_id' not in variable.keys() or \
732
                    variable['meter_id'] <= 0:
733
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
734
                                       description='API.INVALID_VARIABLE_METER_ID')
735
736
        cnx = mysql.connector.connect(**config.myems_system_db)
737
        cursor = cnx.cursor()
738
739
        cursor.execute(" SELECT name "
740
                       " FROM tbl_virtual_meters "
741
                       " WHERE id = %s ", (id_,))
742
        if cursor.fetchone() is None:
743
            cursor.close()
744
            cnx.close()
745
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
746
                                   description='API.VIRTUAL_METER_NOT_FOUND')
747
748
        cursor.execute(" SELECT name "
749
                       " FROM tbl_virtual_meters "
750
                       " WHERE name = %s AND id != %s ", (name, id_))
751
        if cursor.fetchone() is not None:
752
            cursor.close()
753
            cnx.close()
754
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
755
                                   description='API.VIRTUAL_METER_NAME_IS_ALREADY_IN_USE')
756
757
        cursor.execute(" SELECT name "
758
                       " FROM tbl_energy_categories "
759
                       " WHERE id = %s ",
760
                       (energy_category_id,))
761
        if cursor.fetchone() is None:
762
            cursor.close()
763
            cnx.close()
764
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
765
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
766
767
        cursor.execute(" SELECT name "
768
                       " FROM tbl_cost_centers "
769
                       " WHERE id = %s ",
770
                       (new_values['data']['cost_center_id'],))
771
        row = cursor.fetchone()
772
        if row is None:
773
            cursor.close()
774
            cnx.close()
775
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
776
                                   description='API.COST_CENTER_NOT_FOUND')
777
778
        if energy_item_id is not None:
779
            cursor.execute(" SELECT name, energy_category_id "
780
                           " FROM tbl_energy_items "
781
                           " WHERE id = %s ",
782
                           (new_values['data']['energy_item_id'],))
783
            row = cursor.fetchone()
784
            if row is None:
785
                cursor.close()
786
                cnx.close()
787
                raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
788
                                       description='API.ENERGY_ITEM_NOT_FOUND')
789
            else:
790
                if row[1] != energy_category_id:
791
                    cursor.close()
792
                    cnx.close()
793
                    raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
794
                                           description='API.ENERGY_ITEM_IS_NOT_BELONG_TO_ENERGY_CATEGORY')
795
796
        for variable in new_values['data']['expression']['variables']:
797 View Code Duplication
            if variable['meter_type'].lower() == 'meter':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
798
                cursor.execute(" SELECT name "
799
                               " FROM tbl_meters "
800
                               " WHERE id = %s ", (variable['meter_id'],))
801
                if cursor.fetchone() is None:
802
                    cursor.close()
803
                    cnx.close()
804
                    raise falcon.HTTPError(status=falcon.HTTP_404,
805
                                           title='API.NOT_FOUND',
806
                                           description='API.METER_OF_VARIABLE_NOT_FOUND')
807
            elif variable['meter_type'].lower() == 'offline_meter':
808
                cursor.execute(" SELECT name "
809
                               " FROM tbl_offline_meters "
810
                               " WHERE id = %s ", (variable['meter_id'],))
811
                if cursor.fetchone() is None:
812
                    cursor.close()
813
                    cnx.close()
814
                    raise falcon.HTTPError(status=falcon.HTTP_404,
815
                                           title='API.NOT_FOUND',
816
                                           description='API.OFFLINE_METER_OF_VARIABLE_NOT_FOUND')
817
            elif variable['meter_type'].lower() == 'virtual_meter':
818
                cursor.execute(" SELECT name "
819
                               " FROM tbl_virtual_meters "
820
                               " WHERE id = %s ", (variable['meter_id'],))
821
                if cursor.fetchone() is None:
822
                    cursor.close()
823
                    cnx.close()
824
                    raise falcon.HTTPError(status=falcon.HTTP_404,
825
                                           title='API.NOT_FOUND',
826
                                           description='API.VIRTUAL_METER_OF_VARIABLE_NOT_FOUND')
827
        try:
828
            update_row = (" UPDATE tbl_virtual_meters "
829
                          " SET name = %s, equation = %s, energy_category_id = %s, is_counted = %s, "
830
                          "     cost_center_id = %s, energy_item_id = %s, description = %s "
831
                          " WHERE id = %s ")
832
            cursor.execute(update_row, (name,
833
                                        new_values['data']['expression']['equation'].lower(),
834
                                        energy_category_id,
835
                                        is_counted,
836
                                        cost_center_id,
837
                                        energy_item_id,
838
                                        description,
839
                                        id_,))
840
            cnx.commit()
841
        except Exception as ex:
842
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.ERROR', description=str(ex))
843
844
        try:
845
            cursor.execute(" SELECT id "
846
                           " FROM tbl_variables "
847
                           " WHERE virtual_meter_id = %s ", (id_,))
848
            row_variables = cursor.fetchall()
849
            if row_variables is not None and len(row_variables) > 0:
850
                # delete variables
851
                cursor.execute(" DELETE FROM tbl_variables WHERE virtual_meter_id = %s ", (id_,))
852
                cnx.commit()
853
        except Exception as ex:
854
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.ERROR', description=str(ex))
855
856
        # add variables
857
        for variable in new_values['data']['expression']['variables']:
858
            try:
859
                add_values = (" INSERT INTO tbl_variables (name, virtual_meter_id, meter_type, meter_id) "
860
                              " VALUES (%s, %s, %s, %s) ")
861
                cursor.execute(add_values, (variable['name'].lower(),
862
                                            id_,
863
                                            variable['meter_type'],
864
                                            variable['meter_id'],))
865
                cnx.commit()
866
            except Exception as ex:
867
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.ERROR', description=str(ex))
868
869
        cursor.close()
870
        cnx.close()
871
872
        resp.status = falcon.HTTP_200
873
874
875
class VirtualMeterExport:
876
    def __init__(self):
877
        """"Initializes VirtualMeterItem"""
878
        pass
879
880
    @staticmethod
881
    def on_options(req, resp, id_):
882
        resp.status = falcon.HTTP_200
883
884 View Code Duplication
    @staticmethod
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
885
    def on_get(req, resp, id_):
886
        if 'API-KEY' not in req.headers or \
887
                not isinstance(req.headers['API-KEY'], str) or \
888
                len(str.strip(req.headers['API-KEY'])) == 0:
889
            access_control(req)
890
        else:
891
            api_key_control(req)
892
        if not id_.isdigit() or int(id_) <= 0:
893
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
894
                                   description='API.INVALID_VIRTUAL_METER_ID')
895
896
        cnx = mysql.connector.connect(**config.myems_system_db)
897
        cursor = cnx.cursor()
898
899
        query = (" SELECT id, name, uuid "
900
                 " FROM tbl_energy_categories ")
901
        cursor.execute(query)
902
        rows_energy_categories = cursor.fetchall()
903
904
        energy_category_dict = dict()
905
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
906
            for row in rows_energy_categories:
907
                energy_category_dict[row[0]] = {"id": row[0],
908
                                                "name": row[1],
909
                                                "uuid": row[2]}
910
911
        query = (" SELECT id, name, uuid, energy_category_id "
912
                 " FROM tbl_energy_items ")
913
        cursor.execute(query)
914
        rows_energy_items = cursor.fetchall()
915
916
        energy_item_dict = dict()
917
        if rows_energy_items is not None and len(rows_energy_items) > 0:
918
            for row in rows_energy_items:
919
                energy_item_dict[row[0]] = {"id": row[0],
920
                                            "name": row[1],
921
                                            "uuid": row[2]}
922
923
        query = (" SELECT id, name, uuid "
924
                 " FROM tbl_cost_centers ")
925
        cursor.execute(query)
926
        rows_cost_centers = cursor.fetchall()
927
928
        cost_center_dict = dict()
929
        if rows_cost_centers is not None and len(rows_cost_centers) > 0:
930
            for row in rows_cost_centers:
931
                cost_center_dict[row[0]] = {"id": row[0],
932
                                            "name": row[1],
933
                                            "uuid": row[2]}
934
935
        query = (" SELECT id, name, uuid, equation, energy_category_id, is_counted, cost_center_id, "
936
                 "        energy_item_id, description "
937
                 " FROM tbl_virtual_meters "
938
                 " WHERE id = %s ")
939
        cursor.execute(query, (id_,))
940
        row = cursor.fetchone()
941
        if row is None:
942
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
943
                                   description='API.VIRTUAL_METER_NOT_FOUND')
944
        else:
945
            meta_result = {"id": row[0],
946
                           "name": row[1],
947
                           "uuid": row[2],
948
                           "equation": row[3],
949
                           "energy_category": energy_category_dict.get(row[4], None),
950
                           "is_counted": True if row[5] else False,
951
                           "cost_center": cost_center_dict.get(row[6], None),
952
                           "energy_item": energy_item_dict.get(row[7], None),
953
                           "description": row[8],
954
                           "expression": {}}
955
956
        expression = dict()
957
958
        if meta_result["equation"] is not None:
959
            expression = {'equation': meta_result["equation"], 'variables': []}
960
961
            query_variables = (" SELECT v.id, v.name, v.meter_type, v.meter_id "
962
                               " FROM tbl_virtual_meters  vm, tbl_variables v "
963
                               " WHERE vm.id = %s AND v.virtual_meter_id = vm.id "
964
                               " ORDER BY v.name ")
965
            cursor.execute(query_variables, (meta_result["id"],))
966
            rows_variables = cursor.fetchall()
967
            if rows_variables is not None:
968
                for row_variable in rows_variables:
969
                    if row_variable[2].lower() == 'meter':
970
                        query_meter = (" SELECT m.name "
971
                                       " FROM tbl_meters m "
972
                                       " WHERE m.id = %s ")
973
                        cursor.execute(query_meter, (row_variable[3],))
974
                        row_meter = cursor.fetchone()
975
                        if row_meter is not None:
976
                            expression['variables'].append({'id': row_variable[0],
977
                                                            'name': row_variable[1],
978
                                                            'meter_type': row_variable[2],
979
                                                            'meter_id': row_variable[3],
980
                                                            'meter_name': row_meter[0]})
981
                    elif row_variable[2].lower() == 'offline_meter':
982
                        query_meter = (" SELECT m.name "
983
                                       " FROM tbl_offline_meters m "
984
                                       " WHERE m.id = %s ")
985
                        cursor.execute(query_meter, (row_variable[3],))
986
                        row_meter = cursor.fetchone()
987
                        if row_meter is not None:
988
                            expression['variables'].append({'id': row_variable[0],
989
                                                            'name': row_variable[1],
990
                                                            'meter_type': row_variable[2],
991
                                                            'meter_id': row_variable[3],
992
                                                            'meter_name': row_meter[0]})
993
                    elif row_variable[2].lower() == 'virtual_meter':
994
                        query_meter = (" SELECT m.name "
995
                                       " FROM tbl_virtual_meters m "
996
                                       " WHERE m.id = %s ")
997
                        cursor.execute(query_meter, (row_variable[3],))
998
                        row_meter = cursor.fetchone()
999
                        if row_meter is not None:
1000
                            expression['variables'].append({'id': row_variable[0],
1001
                                                            'name': row_variable[1],
1002
                                                            'meter_type': row_variable[2],
1003
                                                            'meter_id': row_variable[3],
1004
                                                            'meter_name': row_meter[0]})
1005
1006
        meta_result['expression'] = expression
1007
1008
        cursor.close()
1009
        cnx.close()
1010
        resp.text = json.dumps(meta_result)
1011
1012
1013
class VirtualMeterImport:
1014
    def __init__(self):
1015
        """"Initializes VirtualMeterImport"""
1016
        pass
1017
1018
    @staticmethod
1019
    def on_options(req, resp):
1020
        resp.status = falcon.HTTP_200
1021
1022
    @staticmethod
1023
    @user_logger
1024
    def on_post(req, resp):
1025
        """Handles POST requests"""
1026
        admin_control(req)
1027
        try:
1028
            raw_json = req.stream.read().decode('utf-8')
1029
        except Exception as ex:
1030
            raise falcon.HTTPError(status=falcon.HTTP_400,
1031
                                   title='API.BAD_REQUEST',
1032
                                   description='API.FAILED_TO_READ_REQUEST_STREAM')
1033
1034
        new_values = json.loads(raw_json)
1035
1036
        if 'name' not in new_values.keys() or \
1037
                not isinstance(new_values['name'], str) or \
1038
                len(str.strip(new_values['name'])) == 0:
1039
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1040
                                   description='API.INVALID_VIRTUAL_METER_NAME')
1041
        name = str.strip(new_values['name'])
1042
1043
        if 'id' not in new_values['energy_category'].keys() or new_values['energy_category']['id'] <= 0:
1044
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1045
                                   description='API.INVALID_ENERGY_CATEGORY_ID')
1046
        energy_category_id = new_values['energy_category']['id']
1047
1048
        if 'is_counted' not in new_values.keys() or not isinstance(new_values['is_counted'], bool):
1049
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1050
                                   description='API.INVALID_IS_COUNTED_VALUE')
1051
        is_counted = new_values['is_counted']
1052
1053
        if 'id' not in new_values['cost_center'].keys() or \
1054
                not isinstance(new_values['cost_center']['id'], int) or \
1055
                new_values['cost_center']['id'] <= 0:
1056
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1057
                                   description='API.INVALID_COST_CENTER_ID')
1058
1059
        cost_center_id = new_values['cost_center']['id']
1060
1061
        if 'id' in new_values['energy_item'].keys() and \
1062
                new_values['energy_item']['id'] is not None:
1063
            if not isinstance(new_values['energy_item']['id'], int) or \
1064
                    new_values['energy_item']['id'] <= 0:
1065
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1066
                                       description='API.INVALID_ENERGY_ITEM_ID')
1067
            energy_item_id = new_values['energy_item']['id']
1068
        else:
1069
            energy_item_id = None
1070
1071
        if 'description' in new_values.keys() and \
1072
                new_values['description'] is not None and \
1073
                len(str(new_values['description'])) > 0:
1074
            description = str.strip(new_values['description'])
1075
        else:
1076
            description = None
1077
1078
        if 'expression' not in new_values.keys():
1079
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1080
                                   description='API.INVALID_EXPRESSION_OBJECT')
1081
1082
        if 'equation' not in new_values['expression'].keys() \
1083
                or len(new_values['expression']['equation']) == 0:
1084
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1085
                                   description='API.INVALID_EQUATION_IN_EXPRESSION')
1086
        # todo: validate equation with more rules
1087
1088
        if 'variables' not in new_values['expression'].keys() \
1089
                or len(new_values['expression']['variables']) == 0:
1090
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1091
                                   description='API.EMPTY_VARIABLES_ARRAY')
1092
1093
        for variable in new_values['expression']['variables']:
1094
            if 'name' not in variable.keys() or \
1095
                    len(variable['name']) == 0:
1096
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1097
                                       description='API.INVALID_VARIABLE_NAME')
1098
            if 'meter_type' not in variable.keys() or \
1099
                    len(variable['meter_type']) == 0 or \
1100
                    variable['meter_type'].lower() not in ['meter', 'offline_meter', 'virtual_meter']:
1101
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1102
                                       description='API.INVALID_VARIABLE_METER_TYPE')
1103
            if 'meter_id' not in variable.keys() or \
1104
                    variable['meter_id'] <= 0:
1105
                raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1106
                                       description='API.INVALID_VARIABLE_METER_ID')
1107
1108
        cnx = mysql.connector.connect(**config.myems_system_db)
1109
        cursor = cnx.cursor()
1110
1111
        cursor.execute(" SELECT name "
1112
                       " FROM tbl_virtual_meters "
1113
                       " WHERE name = %s ", (name,))
1114
        if cursor.fetchone() is not None:
1115
            cursor.close()
1116
            cnx.close()
1117
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.NOT_FOUND',
1118
                                   description='API.VIRTUAL_METER_NAME_IS_ALREADY_IN_USE')
1119
1120
        cursor.execute(" SELECT name "
1121
                       " FROM tbl_energy_categories "
1122
                       " WHERE id = %s ",
1123
                       (energy_category_id,))
1124
        if cursor.fetchone() is None:
1125
            cursor.close()
1126
            cnx.close()
1127
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
1128
                                   description='API.ENERGY_CATEGORY_NOT_FOUND')
1129
1130
        cursor.execute(" SELECT name "
1131
                       " FROM tbl_cost_centers "
1132
                       " WHERE id = %s ",
1133
                       (new_values['cost_center']['id'],))
1134
        row = cursor.fetchone()
1135
        if row is None:
1136
            cursor.close()
1137
            cnx.close()
1138
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
1139
                                   description='API.COST_CENTER_NOT_FOUND')
1140
1141 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...
1142
            cursor.execute(" SELECT name, energy_category_id "
1143
                           " FROM tbl_energy_items "
1144
                           " WHERE id = %s ",
1145
                           (new_values['energy_item']['id'],))
1146
            row = cursor.fetchone()
1147
            if row is None:
1148
                cursor.close()
1149
                cnx.close()
1150
                raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
1151
                                       description='API.ENERGY_ITEM_NOT_FOUND')
1152
            else:
1153
                if row[1] != energy_category_id:
1154
                    cursor.close()
1155
                    cnx.close()
1156
                    raise falcon.HTTPError(status=falcon.HTTP_404, title='API.BAD_REQUEST',
1157
                                           description='API.ENERGY_ITEM_IS_NOT_BELONG_TO_ENERGY_CATEGORY')
1158
1159
        for variable in new_values['expression']['variables']:
1160 View Code Duplication
            if variable['meter_type'].lower() == 'meter':
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1161
                cursor.execute(" SELECT name "
1162
                               " FROM tbl_meters "
1163
                               " WHERE id = %s ", (variable['meter_id'],))
1164
                if cursor.fetchone() is None:
1165
                    cursor.close()
1166
                    cnx.close()
1167
                    raise falcon.HTTPError(status=falcon.HTTP_404,
1168
                                           title='API.NOT_FOUND',
1169
                                           description='API.METER_OF_VARIABLE_NOT_FOUND')
1170
            elif variable['meter_type'].lower() == 'offline_meter':
1171
                cursor.execute(" SELECT name "
1172
                               " FROM tbl_offline_meters "
1173
                               " WHERE id = %s ", (variable['meter_id'],))
1174
                if cursor.fetchone() is None:
1175
                    cursor.close()
1176
                    cnx.close()
1177
                    raise falcon.HTTPError(status=falcon.HTTP_404,
1178
                                           title='API.NOT_FOUND',
1179
                                           description='API.OFFLINE_METER_OF_VARIABLE_NOT_FOUND')
1180
            elif variable['meter_type'].lower() == 'virtual_meter':
1181
                cursor.execute(" SELECT name "
1182
                               " FROM tbl_virtual_meters "
1183
                               " WHERE id = %s ", (variable['meter_id'],))
1184
                if cursor.fetchone() is None:
1185
                    cursor.close()
1186
                    cnx.close()
1187
                    raise falcon.HTTPError(status=falcon.HTTP_404,
1188
                                           title='API.NOT_FOUND',
1189
                                           description='API.VIRTUAL_METER_OF_VARIABLE_NOT_FOUND')
1190
1191
        add_values = (" INSERT INTO tbl_virtual_meters "
1192
                      "     (name, uuid, equation, energy_category_id, is_counted, "
1193
                      "      cost_center_id, energy_item_id, description) "
1194
                      " VALUES (%s, %s, %s, %s, %s, %s, %s, %s) ")
1195
        cursor.execute(add_values, (name,
1196
                                    str(uuid.uuid4()),
1197
                                    new_values['expression']['equation'].lower(),
1198
                                    energy_category_id,
1199
                                    is_counted,
1200
                                    cost_center_id,
1201
                                    energy_item_id,
1202
                                    description))
1203
        new_id = cursor.lastrowid
1204
        cnx.commit()
1205
1206
        # add variables
1207
        for variable in new_values['expression']['variables']:
1208
            add_values = (" INSERT INTO tbl_variables (name, virtual_meter_id, meter_type, meter_id) "
1209
                          " VALUES (%s, %s, %s, %s) ")
1210
            cursor.execute(add_values, (variable['name'].lower(),
1211
                                        new_id,
1212
                                        variable['meter_type'],
1213
                                        variable['meter_id'],))
1214
            cnx.commit()
1215
1216
        cursor.close()
1217
        cnx.close()
1218
1219
        resp.status = falcon.HTTP_201
1220
        resp.location = '/virtualmeters/' + str(new_id)
1221
1222
1223
class VirtualMeterClone:
1224
    def __init__(self):
1225
        """"Initializes VirtualMeterClone"""
1226
        pass
1227
1228
    @staticmethod
1229
    def on_options(req, resp, id_):
1230
        resp.status = falcon.HTTP_200
1231
1232
    @staticmethod
1233
    @user_logger
1234
    def on_post(req, resp, id_):
1235
        if 'API-KEY' not in req.headers or \
1236
                not isinstance(req.headers['API-KEY'], str) or \
1237
                len(str.strip(req.headers['API-KEY'])) == 0:
1238
            access_control(req)
1239
        else:
1240
            api_key_control(req)
1241
        if not id_.isdigit() or int(id_) <= 0:
1242
            raise falcon.HTTPError(status=falcon.HTTP_400, title='API.BAD_REQUEST',
1243
                                   description='API.INVALID_VIRTUAL_METER_ID')
1244
1245
        cnx = mysql.connector.connect(**config.myems_system_db)
1246
        cursor = cnx.cursor()
1247
1248
        query = (" SELECT id, name, uuid "
1249
                 " FROM tbl_energy_categories ")
1250
        cursor.execute(query)
1251
        rows_energy_categories = cursor.fetchall()
1252
1253
        energy_category_dict = dict()
1254
        if rows_energy_categories is not None and len(rows_energy_categories) > 0:
1255
            for row in rows_energy_categories:
1256
                energy_category_dict[row[0]] = {"id": row[0],
1257
                                                "name": row[1],
1258
                                                "uuid": row[2]}
1259
1260
        query = (" SELECT id, name, uuid, energy_category_id "
1261
                 " FROM tbl_energy_items ")
1262
        cursor.execute(query)
1263
        rows_energy_items = cursor.fetchall()
1264
1265
        energy_item_dict = dict()
1266
        if rows_energy_items is not None and len(rows_energy_items) > 0:
1267
            for row in rows_energy_items:
1268
                energy_item_dict[row[0]] = {"id": row[0],
1269
                                            "name": row[1],
1270
                                            "uuid": row[2]}
1271
1272
        query = (" SELECT id, name, uuid "
1273
                 " FROM tbl_cost_centers ")
1274
        cursor.execute(query)
1275
        rows_cost_centers = cursor.fetchall()
1276
1277
        cost_center_dict = dict()
1278
        if rows_cost_centers is not None and len(rows_cost_centers) > 0:
1279
            for row in rows_cost_centers:
1280
                cost_center_dict[row[0]] = {"id": row[0],
1281
                                            "name": row[1],
1282
                                            "uuid": row[2]}
1283
1284
        query = (" SELECT id, name, uuid, equation, energy_category_id, is_counted, cost_center_id, "
1285
                 "        energy_item_id, description "
1286
                 " FROM tbl_virtual_meters "
1287
                 " WHERE id = %s ")
1288
        cursor.execute(query, (id_,))
1289
        row = cursor.fetchone()
1290
        if row is None:
1291
            raise falcon.HTTPError(status=falcon.HTTP_404, title='API.NOT_FOUND',
1292
                                   description='API.VIRTUAL_METER_NOT_FOUND')
1293
        else:
1294
            meta_result = {"id": row[0],
1295
                           "name": row[1],
1296
                           "uuid": row[2],
1297
                           "equation": row[3],
1298
                           "energy_category": energy_category_dict.get(row[4], None),
1299
                           "is_counted": True if row[5] else False,
1300
                           "cost_center": cost_center_dict.get(row[6], None),
1301
                           "energy_item": energy_item_dict.get(row[7], None),
1302
                           "description": row[8],
1303
                           "expression": {}}
1304
1305
        expression = dict()
1306
1307
        if meta_result["equation"] is not None:
1308
            expression = {'equation': meta_result["equation"], 'variables': []}
1309
1310
            query_variables = (" SELECT v.id, v.name, v.meter_type, v.meter_id "
1311
                               " FROM tbl_virtual_meters  vm, tbl_variables v "
1312
                               " WHERE vm.id = %s AND v.virtual_meter_id = vm.id "
1313
                               " ORDER BY v.name ")
1314
            cursor.execute(query_variables, (meta_result["id"],))
1315
            rows_variables = cursor.fetchall()
1316
            if rows_variables is not None:
1317
                for row_variable in rows_variables:
1318
                    if row_variable[2].lower() == 'meter':
1319
                        query_meter = (" SELECT m.name "
1320
                                       " FROM tbl_meters m "
1321
                                       " WHERE m.id = %s ")
1322
                        cursor.execute(query_meter, (row_variable[3],))
1323
                        row_meter = cursor.fetchone()
1324
                        if row_meter is not None:
1325
                            expression['variables'].append({'id': row_variable[0],
1326
                                                            'name': row_variable[1],
1327
                                                            'meter_type': row_variable[2],
1328
                                                            'meter_id': row_variable[3],
1329
                                                            'meter_name': row_meter[0]})
1330
                    elif row_variable[2].lower() == 'offline_meter':
1331
                        query_meter = (" SELECT m.name "
1332
                                       " FROM tbl_offline_meters m "
1333
                                       " WHERE m.id = %s ")
1334
                        cursor.execute(query_meter, (row_variable[3],))
1335
                        row_meter = cursor.fetchone()
1336
                        if row_meter is not None:
1337
                            expression['variables'].append({'id': row_variable[0],
1338
                                                            'name': row_variable[1],
1339
                                                            'meter_type': row_variable[2],
1340
                                                            'meter_id': row_variable[3],
1341
                                                            'meter_name': row_meter[0]})
1342
                    elif row_variable[2].lower() == 'virtual_meter':
1343
                        query_meter = (" SELECT m.name "
1344
                                       " FROM tbl_virtual_meters m "
1345
                                       " WHERE m.id = %s ")
1346
                        cursor.execute(query_meter, (row_variable[3],))
1347
                        row_meter = cursor.fetchone()
1348
                        if row_meter is not None:
1349
                            expression['variables'].append({'id': row_variable[0],
1350
                                                            'name': row_variable[1],
1351
                                                            'meter_type': row_variable[2],
1352
                                                            'meter_id': row_variable[3],
1353
                                                            'meter_name': row_meter[0]})
1354
1355
        meta_result['expression'] = expression
1356
        timezone_offset = int(config.utc_offset[1:3]) * 60 + int(config.utc_offset[4:6])
1357
        if config.utc_offset[0] == '-':
1358
            timezone_offset = -timezone_offset
1359
        new_name = (str.strip(meta_result['name']) +
1360
                    (datetime.utcnow() + timedelta(minutes=timezone_offset)).isoformat(sep='-', timespec='seconds'))
1361
        add_values = (" INSERT INTO tbl_virtual_meters "
1362
                      "     (name, uuid, equation, energy_category_id, is_counted, "
1363
                      "      cost_center_id, energy_item_id, description) "
1364
                      " VALUES (%s, %s, %s, %s, %s, %s, %s, %s) ")
1365
        cursor.execute(add_values, (new_name,
1366
                                    str(uuid.uuid4()),
1367
                                    meta_result['expression']['equation'].lower(),
1368
                                    meta_result['energy_category']['id'],
1369
                                    meta_result['is_counted'],
1370
                                    meta_result['cost_center']['id'],
1371
                                    meta_result['energy_item']['id'],
1372
                                    meta_result['description']))
1373
        new_id = cursor.lastrowid
1374
        cnx.commit()
1375
1376
        # add variables
1377
        for variable in meta_result['expression']['variables']:
1378
            add_values = (" INSERT INTO tbl_variables (name, virtual_meter_id, meter_type, meter_id) "
1379
                          " VALUES (%s, %s, %s, %s) ")
1380
            cursor.execute(add_values, (variable['name'].lower(),
1381
                                        new_id,
1382
                                        variable['meter_type'],
1383
                                        variable['meter_id'],))
1384
            cnx.commit()
1385
1386
        cursor.close()
1387
        cnx.close()
1388
1389
        resp.status = falcon.HTTP_201
1390
        resp.location = '/virtualmeters/' + str(new_id)
1391
1392