Passed
Push — master ( c6068e...54bd3b )
by Guangyu
02:21 queued 10s
created

datasource.py (1 issue)

1
import falcon
2
import simplejson as json
3
import mysql.connector
4
import config
5
import uuid
6
from datetime import datetime
7
8
9
class DataSourceCollection:
10
    @staticmethod
11
    def __init__():
12
        pass
13
14
    @staticmethod
15
    def on_options(req, resp):
16
        resp.status = falcon.HTTP_200
17
18
    @staticmethod
19
    def on_get(req, resp):
20
        cnx = mysql.connector.connect(**config.myems_system_db)
21
        cursor = cnx.cursor()
22
23
        query = (" SELECT id, name, uuid "
24
                 " FROM tbl_gateways ")
25
        cursor.execute(query)
26
        rows_gateways = cursor.fetchall()
27
        gateway_dict = dict()
28
        if rows_gateways is not None and len(rows_gateways) > 0:
29
            for row in rows_gateways:
30
                gateway_dict[row[0]] = {"id": row[0],
31
                                        "name": row[1],
32
                                        "uuid": row[2]}
33
34
        query = (" SELECT id, name, uuid, gateway_id, protocol, connection, last_seen_datetime_utc "
35
                 " FROM tbl_data_sources "
36
                 " ORDER BY id ")
37
        cursor.execute(query)
38
        rows = cursor.fetchall()
39
        cursor.close()
40
        cnx.disconnect()
41
42
        result = list()
43
        now = datetime.utcnow().replace(second=0, microsecond=0, tzinfo=None)
44
        if rows is not None and len(rows) > 0:
45
            for row in rows:
46
                last_seen_time = row[6]
47
                if last_seen_time is not None and (now - last_seen_time).total_seconds() > 5 * 60:
48
                    status = "online"
49
                else:
50
                    status = "offline"
51
                meta_result = {"id": row[0], "name": row[1], "uuid": row[2],
52
                               "gateway": gateway_dict.get(row[3]),
53
                               "protocol": row[4],
54
                               "connection": row[5],
55
                               "last_seen_datetime": row[4].timestamp() * 1000 if isinstance(row[4],
56
                                                                                             datetime) else None,
57
                               "status": status
58
                               }
59
60
                result.append(meta_result)
61
62
        resp.body = json.dumps(result)
63
64
    @staticmethod
65
    def on_post(req, resp):
66
        """Handles POST requests"""
67
        try:
68
            raw_json = req.stream.read().decode('utf-8')
69
        except Exception as ex:
70
            raise falcon.HTTPError(falcon.HTTP_400, title='API.ERROR', description=ex)
71
72
        new_values = json.loads(raw_json, encoding='utf-8')
73
74
        if 'name' not in new_values['data'].keys() or \
75
                not isinstance(new_values['data']['name'], str) or \
76
                len(str.strip(new_values['data']['name'])) == 0:
77
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
78
                                   description='API.INVALID_DATA_SOURCE_NAME')
79
        name = str.strip(new_values['data']['name'])
80
81
        if 'gateway_id' not in new_values['data'].keys() or \
82
                not isinstance(new_values['data']['gateway_id'], int) or \
83
                new_values['data']['gateway_id'] <= 0:
84
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
85
                                   description='API.INVALID_GATEWAY_ID')
86
        gateway_id = new_values['data']['gateway_id']
87
88
        if 'protocol' not in new_values['data'].keys() \
89
                or new_values['data']['protocol'] not in \
90
                ('modbus-tcp', 'modbus-rtu', 'bacnet-ip', 's7', 'profibus', 'profinet', 'opc-ua', 'lora', 'simulation',
91
                 'controllogix', 'weather'):
92
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
93
                                   description='API.INVALID_DATA_SOURCE_PROTOCOL.')
94
        protocol = new_values['data']['protocol']
95
96
        if 'connection' not in new_values['data'].keys() or \
97
                not isinstance(new_values['data']['connection'], str) or \
98
                len(str.strip(new_values['data']['connection'])) == 0:
99
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
100
                                   description='API.INVALID_CONNECTION')
101
        connection = str.strip(new_values['data']['connection'])
102
103
        cnx = mysql.connector.connect(**config.myems_system_db)
104
        cursor = cnx.cursor()
105
106
        cursor.execute(" SELECT name "
107
                       " FROM tbl_data_sources "
108
                       " WHERE name = %s ", (name,))
109
        if cursor.fetchone() is not None:
110
            cursor.close()
111
            cnx.disconnect()
112
            raise falcon.HTTPError(falcon.HTTP_404, title='API.BAD_REQUEST',
113
                                   description='API.DATA_SOURCE_NAME_IS_ALREADY_IN_USE')
114
115
        cursor.execute(" SELECT name "
116
                       " FROM tbl_gateways "
117
                       " WHERE id = %s ", (gateway_id,))
118
        if cursor.fetchone() is None:
119
            cursor.close()
120
            cnx.disconnect()
121
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
122
                                   description='API.INVALID_GATEWAY_ID')
123
124
        add_values = (" INSERT INTO tbl_data_sources (name, uuid, gateway_id, protocol, connection) "
125
                      " VALUES (%s, %s, %s, %s, %s) ")
126
        cursor.execute(add_values, (name,
127
                                    str(uuid.uuid4()),
128
                                    gateway_id,
129
                                    protocol,
130
                                    connection))
131
        new_id = cursor.lastrowid
132
        cnx.commit()
133
        cursor.close()
134
        cnx.disconnect()
135
136
        resp.status = falcon.HTTP_201
137
        resp.location = '/datasources/' + str(new_id)
138
139
140
class DataSourceItem:
141
    @staticmethod
142
    def __init__():
143
        pass
144
145
    @staticmethod
146
    def on_options(req, resp, id_):
147
        resp.status = falcon.HTTP_200
148
149
    @staticmethod
150
    def on_get(req, resp, id_):
151
        if not id_.isdigit() or int(id_) <= 0:
152
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
153
                                   description='API.INVALID_DATA_SOURCE_ID')
154
155
        cnx = mysql.connector.connect(**config.myems_system_db)
156
        cursor = cnx.cursor()
157
158
        query = (" SELECT id, name, uuid "
159
                 " FROM tbl_gateways ")
160
        cursor.execute(query)
161
        rows_gateways = cursor.fetchall()
162
        gateway_dict = dict()
163
        if rows_gateways is not None and len(rows_gateways) > 0:
164
            for row in rows_gateways:
165
                gateway_dict[row[0]] = {"id": row[0],
166
                                        "name": row[1],
167
                                        "uuid": row[2]}
168
169
        query = (" SELECT id, name, uuid, gateway_id, protocol, connection, last_seen_datetime_utc "
170
                 " FROM tbl_data_sources "
171
                 " WHERE id = %s ")
172
        cursor.execute(query, (id_,))
173
        row = cursor.fetchone()
174
        cursor.close()
175
        cnx.disconnect()
176
        if row is None:
177
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
178
                                   description='API.DATA_SOURCE_NOT_FOUND')
179
180
        last_seen_time = row[6]
181
        now = datetime.utcnow().replace(second=0, microsecond=0, tzinfo=None)
182
183
        if last_seen_time is not None and (now - last_seen_time).total_seconds() > 5 * 60:
184
            status = "online"
185
        else:
186
            status = "offline"
187
188
        result = {"id": row[0], "name": row[1], "uuid": row[2],
189
                  "gateway": gateway_dict.get(row[3]),
190
                  "protocol": row[4],
191
                  "connection": row[5],
192
                  "last_seen_datetime": row[4].timestamp() * 1000 if isinstance(row[4], datetime) else None,
193
                  "status": status
194
                  }
195
196
        resp.body = json.dumps(result)
197
198
    @staticmethod
199
    def on_delete(req, resp, id_):
200
        if not id_.isdigit() or int(id_) <= 0:
201
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
202
                                   description='API.INVALID_DATA_SOURCE_ID')
203
204
        cnx = mysql.connector.connect(**config.myems_system_db)
205
        cursor = cnx.cursor()
206
207
        cursor.execute(" SELECT name "
208
                       " FROM tbl_data_sources "
209
                       " WHERE id = %s ", (id_,))
210
        if cursor.fetchone() is None:
211
            cursor.close()
212
            cnx.disconnect()
213
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
214
                                   description='API.DATA_SOURCE_NOT_FOUND')
215
216
        # check if this data source is being used by any meters
217
        cursor.execute(" SELECT DISTINCT(m.name) "
218
                       " FROM tbl_meters m, tbl_meters_points mp, tbl_points p, tbl_data_sources ds "
219
                       " WHERE m.id = mp.meter_id AND mp.point_id = p.id AND p.data_source_id = ds.id "
220
                       "       AND ds.id = %s "
221
                       " LIMIT 1 ",
222
                       (id_,))
223
        row_meter = cursor.fetchone()
224
        if row_meter is not None:
225
            cursor.close()
226
            cnx.disconnect()
227
            raise falcon.HTTPError(falcon.HTTP_400,
228
                                   title='API.BAD_REQUEST',
229
                                   description='API.THIS_DATA_SOURCE_IS_BEING_USED_BY_A_METER' + row_meter[0])
230
231
        cursor.execute(" DELETE FROM tbl_points WHERE data_source_id = %s ", (id_,))
232
        cursor.execute(" DELETE FROM tbl_data_sources WHERE id = %s ", (id_,))
233
        cnx.commit()
234
235
        cursor.close()
236
        cnx.disconnect()
237
        resp.status = falcon.HTTP_204
238
239
    @staticmethod
240
    def on_put(req, resp, id_):
241
        """Handles PUT requests"""
242
        try:
243
            raw_json = req.stream.read().decode('utf-8')
244
        except Exception as ex:
245
            raise falcon.HTTPError(falcon.HTTP_400, 'API.ERROR', ex)
246
247
        if not id_.isdigit() or int(id_) <= 0:
248
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
249
                                   description='API.INVALID_DATA_SOURCE_ID')
250
251
        new_values = json.loads(raw_json, encoding='utf-8')
252
253
        if 'name' not in new_values['data'].keys() or \
254
                not isinstance(new_values['data']['name'], str) or \
255
                len(str.strip(new_values['data']['name'])) == 0:
256
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
257
                                   description='API.INVALID_DATA_SOURCE_NAME')
258
        name = str.strip(new_values['data']['name'])
259
260
        if 'gateway_id' not in new_values['data'].keys() or \
261
                not isinstance(new_values['data']['gateway_id'], int) or \
262
                new_values['data']['gateway_id'] <= 0:
263
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
264
                                   description='API.INVALID_GATEWAY_ID')
265
        gateway_id = new_values['data']['gateway_id']
266
267
        if 'protocol' not in new_values['data'].keys() \
268
                or new_values['data']['protocol'] not in \
269
                ('modbus-tcp', 'modbus-rtu', 'bacnet-ip', 's7', 'profibus', 'profinet', 'opc-ua', 'lora', 'simulation',
270
                 'controllogix', 'weather'):
271
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
272
                                   description='API.INVALID_DATA_SOURCE_PROTOCOL.')
273
        protocol = new_values['data']['protocol']
274
275
        if 'connection' not in new_values['data'].keys() or \
276
                not isinstance(new_values['data']['connection'], str) or \
277
                len(str.strip(new_values['data']['connection'])) == 0:
278
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
279
                                   description='API.INVALID_CONNECTION')
280
        connection = str.strip(new_values['data']['connection'])
281
282
        cnx = mysql.connector.connect(**config.myems_system_db)
283
        cursor = cnx.cursor()
284
285
        cursor.execute(" SELECT name "
286
                       " FROM tbl_data_sources "
287
                       " WHERE id = %s ", (id_,))
288
        if cursor.fetchone() is None:
289
            cursor.close()
290
            cnx.disconnect()
291
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
292
                                   description='API.DATA_SOURCE_NOT_FOUND')
293
294
        cursor.execute(" SELECT name "
295
                       " FROM tbl_gateways "
296
                       " WHERE id = %s ", (gateway_id,))
297
        if cursor.fetchone() is None:
298
            cursor.close()
299
            cnx.disconnect()
300
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
301
                                   description='API.INVALID_GATEWAY_ID')
302
303
        update_row = (" UPDATE tbl_data_sources "
304
                      " SET name = %s, gateway_id = %s, protocol = %s, connection = %s "
305
                      " WHERE id = %s ")
306
        cursor.execute(update_row, (name,
307
                                    gateway_id,
308
                                    protocol,
309
                                    connection,
310
                                    id_,))
311
        cnx.commit()
312
313
        cursor.close()
314
        cnx.disconnect()
315
316
        resp.status = falcon.HTTP_200
317
318
319 View Code Duplication
class DataSourcePointCollection:
0 ignored issues
show
This code seems to be duplicated in your project.
Loading history...
320
    @staticmethod
321
    def __init__():
322
        pass
323
324
    @staticmethod
325
    def on_options(req, resp):
326
        resp.status = falcon.HTTP_200
327
328
    @staticmethod
329
    def on_get(req, resp, id_):
330
        if not id_.isdigit() or int(id_) <= 0:
331
            raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
332
                                   description='API.INVALID_DATA_SOURCE_ID')
333
334
        cnx = mysql.connector.connect(**config.myems_system_db)
335
        cursor = cnx.cursor()
336
337
        cursor.execute(" SELECT name "
338
                       " FROM tbl_data_sources "
339
                       " WHERE id = %s ", (id_,))
340
        if cursor.fetchone() is None:
341
            cursor.close()
342
            cnx.disconnect()
343
            raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
344
                                   description='API.DATA_SOURCE_NOT_FOUND')
345
346
        result = list()
347
        # Get points of the data source
348
        # NOTE: there is no uuid in tbl_points
349
        query_point = (" SELECT id, name, object_type, "
350
                       "        units, high_limit, low_limit, ratio, is_trend, address, description "
351
                       " FROM tbl_points "
352
                       " WHERE data_source_id = %s "
353
                       " ORDER BY name ")
354
        cursor.execute(query_point, (id_,))
355
        rows_point = cursor.fetchall()
356
357
        if rows_point is not None and len(rows_point) > 0:
358
            for row in rows_point:
359
                meta_result = {"id": row[0],
360
                               "name": row[1],
361
                               "object_type": row[2],
362
                               "units": row[3],
363
                               "high_limit": row[4],
364
                               "low_limit": row[5],
365
                               "ratio": float(row[6]),
366
                               "is_trend": True if row[7] else False,
367
                               "address": row[8],
368
                               "description": row[9]}
369
                result.append(meta_result)
370
371
        cursor.close()
372
        cnx.disconnect()
373
        resp.body = json.dumps(result)
374