added Offline Cost File actions to API

pull/53/head
13621160019@163.com 2021-07-16 20:10:49 +08:00
parent 00a17b0d71
commit 9443eca6f0
4 changed files with 362 additions and 6 deletions

View File

@ -3322,6 +3322,102 @@
}
]
},
{
"name": "Offline Cost File",
"item": [
{
"name": "GET All Offline Cost Files",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/offlinecostfiles",
"host": [
"{{base_url}}"
],
"path": [
"offlinecostfiles"
]
}
},
"response": []
},
{
"name": "GET a Offline Cost File by ID",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{base_url}}/offlinecostfiles/1",
"host": [
"{{base_url}}"
],
"path": [
"offlinecostfiles",
"1"
]
}
},
"response": []
},
{
"name": "POST Upload a Offline Cost File",
"request": {
"method": "POST",
"header": [
{
"key": "User_UUID",
"value": "dcdb67d1-6116-4987-916f-6fc6cf2bc0e4",
"type": "text"
},
{
"key": "Token",
"value": "6b0622f8974b2e6f2d7a7470baf073b78bddffd4",
"type": "text"
}
],
"body": {
"mode": "formdata",
"formdata": [
{
"key": "file",
"type": "file",
"src": "/zh/myems/myems-doc/offlinemeters.xlsx"
}
]
},
"url": {
"raw": "{{base_url}}/offlinecostfiles",
"host": [
"{{base_url}}"
],
"path": [
"offlinecostfiles"
]
}
},
"response": []
},
{
"name": "DELETE a Offline Cost File by ID",
"request": {
"method": "DELETE",
"header": [],
"url": {
"raw": "{{base_url}}/offlinecostfiles/1",
"host": [
"{{base_url}}"
],
"path": [
"offlinecostfiles",
"1"
]
}
},
"response": []
}
]
},
{
"name": "Point",
"item": [

View File

@ -159,7 +159,7 @@ View in Postman: import the file MyEMS.postman_collection.json with Postman
[Data Source](#Data-Source) | [Point](#Point)
[Tariff](#Tariff) | [Cost Center](#Cost-Center)
[Tariff](#Tariff) | [Cost Center](#Cost-Center) | [Offline Cost File](#Offline-Cost-File)
[Meter](#Meter) | [Virtual Meter](#Virtual-Meter) | [Offline Meter](#Offline-Meter) | [Offline Meter File](#Offline-Meter-File)
@ -250,6 +250,37 @@ $ curl -i -H "Content-Type: application/json" -X POST -d '{"data":{"tariff_id":"
$ curl -i -X DELETE {{base_url}}/costcenters/{id}/tariffs/{tid}
```
### Offline Cost File
* GET an Offline Cost File by ID
```bash
$ curl -i -X GET {{base_url}}/offlinecostfiles/{id}
```
Result
| Name | Data Type | Description |
|---------------|-----------|-------------------------------------------|
| id | integer | Offline Cost File ID |
| file_name | string | Offline Cost File name |
| uuid | string | Offline Cost File UUID |
| upload_datetime | float | the number of milliseconds since January 1, 1970, 00:00:00, universal time |
| status | string | Offline Cost File processing status (new, done, error) |
| file_object | BLOB | Offline Cost File Object |
* GET All Offline Cost Files
```bash
$ curl -i -X GET {{base_url}}/offlinecostfiles
```
* DELETE an Offline Cost File by ID
```bash
$ curl -i -X DELETE {{base_url}}/offlinecostfiles/{id}
```
* POST Upload an Offline Cost File
(user must login first to get cookie)
```bash
$ curl -i -H "Content-Type: application/TBD" -X POST -d 'file: (binary)' {{base_url}}/offlinecostfiles
```
### Data Source
* GET Data Source by ID
@ -1076,7 +1107,7 @@ $ curl -i -X DELETE {{base_url}}/offlinemeterfiles/{id}
* POST Upload an Offline Meter File
(user must login first to get cookie)
```bash
$ curl -i -H "Content-Type: application/TBD" -X POST -d 'file: (binary)' {{base_url}}/offlinemeters
$ curl -i -H "Content-Type: application/TBD" -X POST -d 'file: (binary)' {{base_url}}/offlinemeterfiles
```
### Point

View File

@ -3,12 +3,13 @@ from falcon_cors import CORS
from falcon_multipart.middleware import MultipartMiddleware
from core import energyflowdiagram, privilege, textmessage, distributioncircuit, virtualmeter, \
costcenter, point, knowledgefile, meter, gsmmodem, tariff, user, storetype, timezone, \
offlinemeterfile, version, contact, emailserver, combinedequipment, datasource, equipment, tenant, shopfloor, \
offlinecostfile, offlinemeterfile, version, contact, emailserver, combinedequipment, datasource, equipment, tenant, shopfloor, \
webmessage, distributionsystem, store, emailmessage, tenanttype, wechatmessage, space, gateway, offlinemeter, \
rule, energycategory, sensor, energyitem, notification
from reports import advancedreport
from reports import distributionsystem as distributionsystemreport
from reports import energyflowdiagram as energyflowdiagramreport
from reports import combinedequipmentbatch
from reports import combinedequipmentcost
from reports import combinedequipmentefficiency
from reports import combinedequipmentenergycategory
@ -18,8 +19,8 @@ from reports import combinedequipmentload
from reports import combinedequipmentoutput
from reports import combinedequipmentsaving
from reports import combinedequipmentstatistics
from reports import combinedequipmentbatch
from reports import dashboard
from reports import equipmentbatch
from reports import equipmentcost
from reports import equipmentefficiency
from reports import equipmentenergycategory
@ -139,6 +140,11 @@ api.add_route('/costcenters/{id_}/tariffs',
api.add_route('/costcenters/{id_}/tariffs/{tid}',
costcenter.CostCenterTariffItem())
api.add_route('/offlinecostfiles',
offlinecostfile.OfflineCostFileCollection())
api.add_route('/offlinecostfiles/{id_}',
offlinecostfile.OfflineCostFileItem())
api.add_route('/datasources',
datasource.DataSourceCollection())
api.add_route('/datasources/{id_}',
@ -483,6 +489,8 @@ api.add_route('/reports/distributionsystem',
distributionsystemreport.Reporting())
api.add_route('/reports/energyflowdiagram',
energyflowdiagramreport.Reporting())
api.add_route('/reports/combinedequipmentbatch',
combinedequipmentbatch.Reporting())
api.add_route('/reports/combinedequipmentcost',
combinedequipmentcost.Reporting())
api.add_route('/reports/combinedequipmentefficiency',
@ -501,10 +509,10 @@ api.add_route('/reports/combinedequipmentsaving',
combinedequipmentsaving.Reporting())
api.add_route('/reports/combinedequipmentstatistics',
combinedequipmentstatistics.Reporting())
api.add_route('/reports/combinedequipmentbatch',
combinedequipmentbatch.Reporting())
api.add_route('/reports/dashboard',
dashboard.Reporting())
api.add_route('/reports/equipmentbatch',
equipmentbatch.Reporting())
api.add_route('/reports/equipmentcost',
equipmentcost.Reporting())
api.add_route('/reports/equipmentefficiency',

View File

@ -0,0 +1,221 @@
import falcon
import json
import mysql.connector
import config
import uuid
from datetime import datetime, timezone
import os
class OfflineCostFileCollection:
@staticmethod
def __init__():
pass
@staticmethod
def on_options(req, resp):
resp.status = falcon.HTTP_200
@staticmethod
def on_get(req, resp):
cnx = mysql.connector.connect(**config.myems_historical_db)
cursor = cnx.cursor()
query = (" SELECT id, file_name, uuid, upload_datetime_utc, status "
" FROM tbl_offline_cost_files "
" ORDER BY upload_datetime_utc desc ")
cursor.execute(query)
rows = cursor.fetchall()
cursor.close()
cnx.disconnect()
result = list()
if rows is not None and len(rows) > 0:
for row in rows:
upload_datetime = row[3]
upload_datetime = upload_datetime.replace(tzinfo=timezone.utc)
meta_result = {"id": row[0],
"file_name": row[1],
"uuid": row[2],
"upload_datetime": upload_datetime.timestamp() * 1000,
"status": row[4]}
result.append(meta_result)
resp.body = json.dumps(result)
@staticmethod
def on_post(req, resp):
"""Handles POST requests"""
try:
upload = req.get_param('file')
# Read upload file as binary
raw_blob = upload.file.read()
# Retrieve filename
filename = upload.filename
file_uuid = str(uuid.uuid4())
# Define file_path
file_path = os.path.join(config.upload_path, file_uuid)
# Write to a temporary file to prevent incomplete files from
# being used.
temp_file_path = file_path + '~'
open(temp_file_path, 'wb').write(raw_blob)
# Now that we know the file has been fully saved to disk
# move it into place.
os.rename(temp_file_path, file_path)
except Exception as ex:
raise falcon.HTTPError(falcon.HTTP_400, title='API.ERROR',
description='API.FAILED_TO_UPLOAD_OFFLINE_COST_FILE')
# Verify User Session
token = req.headers.get('TOKEN')
user_uuid = req.headers.get('USER-UUID')
if token is None:
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.TOKEN_NOT_FOUND_IN_HEADERS_PLEASE_LOGIN')
if user_uuid is None:
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.USER_UUID_NOT_FOUND_IN_HEADERS_PLEASE_LOGIN')
cnx = mysql.connector.connect(**config.myems_user_db)
cursor = cnx.cursor()
query = (" SELECT utc_expires "
" FROM tbl_sessions "
" WHERE user_uuid = %s AND token = %s")
cursor.execute(query, (user_uuid, token,))
row = cursor.fetchone()
if row is None:
if cursor:
cursor.close()
if cnx:
cnx.disconnect()
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.INVALID_SESSION_PLEASE_RE_LOGIN')
else:
utc_expires = row[0]
if datetime.utcnow() > utc_expires:
if cursor:
cursor.close()
if cnx:
cnx.disconnect()
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.USER_SESSION_TIMEOUT')
cursor.execute(" SELECT id "
" FROM tbl_users "
" WHERE uuid = %s ",
(user_uuid,))
row = cursor.fetchone()
if row is None:
if cursor:
cursor.close()
if cnx:
cnx.disconnect()
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.INVALID_USER_PLEASE_RE_LOGIN')
else:
user_id = row[0]
cnx = mysql.connector.connect(**config.myems_historical_db)
cursor = cnx.cursor()
add_values = (" INSERT INTO tbl_offline_cost_files "
" (file_name, uuid, upload_datetime_utc, status, file_object ) "
" VALUES (%s, %s, %s, %s, %s) ")
cursor.execute(add_values, (filename,
file_uuid,
datetime.utcnow(),
'new',
raw_blob))
new_id = cursor.lastrowid
cnx.commit()
cursor.close()
cnx.disconnect()
resp.status = falcon.HTTP_201
resp.location = '/offlinecostfiles/' + str(new_id)
class OfflineCostFileItem:
@staticmethod
def __init__():
pass
@staticmethod
def on_options(req, resp, id_):
resp.status = falcon.HTTP_200
@staticmethod
def on_get(req, resp, id_):
if not id_.isdigit() or int(id_) <= 0:
raise falcon.HTTPError(falcon.HTTP_400,
title='API.BAD_REQUEST',
description='API.INVALID_OFFLINE_COST_FILE_ID')
cnx = mysql.connector.connect(**config.myems_historical_db)
cursor = cnx.cursor()
query = (" SELECT id, file_name, uuid, upload_datetime_utc, status "
" FROM tbl_offline_cost_files "
" WHERE id = %s ")
cursor.execute(query, (id_,))
row = cursor.fetchone()
cursor.close()
cnx.disconnect()
if row is None:
raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
description='API.OFFLINE_COST_FILE_NOT_FOUND')
upload_datetime = row[3]
upload_datetime = upload_datetime.replace(tzinfo=timezone.utc)
result = {"id": row[0],
"file_name": row[1],
"uuid": row[2],
"upload_datetime": upload_datetime.timestamp() * 1000,
"status": row[4]}
resp.body = json.dumps(result)
@staticmethod
def on_delete(req, resp, id_):
if not id_.isdigit() or int(id_) <= 0:
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.INVALID_OFFLINE_COST_FILE_ID')
cnx = mysql.connector.connect(**config.myems_historical_db)
cursor = cnx.cursor()
cursor.execute(" SELECT uuid "
" FROM tbl_offline_cost_files "
" WHERE id = %s ", (id_,))
row = cursor.fetchone()
if row is None:
cursor.close()
cnx.disconnect()
raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
description='API.OFFLINE_COST_FILE_NOT_FOUND')
try:
file_uuid = row[0]
# Define file_path
file_path = os.path.join(config.upload_path, file_uuid)
# remove the file from disk
os.remove(file_path)
except Exception as ex:
# ignore exception and don't return API.OFFLINE_COST_FILE_NOT_FOUND error
pass
# Note: the energy data imported from the deleted file will not be deleted
cursor.execute(" DELETE FROM tbl_offline_cost_files WHERE id = %s ", (id_,))
cnx.commit()
cursor.close()
cnx.disconnect()
resp.status = falcon.HTTP_204