Merge branch 'develop'

pull/80/head
13621160019@163.com 2021-11-10 18:12:38 +08:00
commit b4637d15ad
41 changed files with 167 additions and 108 deletions

View File

@ -46,7 +46,8 @@ app.controller('UserController', function ($scope,
}
});
modalInstance.result.then(function (user) {
UserService.addUser(user, function (response) {
let headers = { "User-UUID": $scope.cur_user.uuid, "Token": $scope.cur_user.token };
UserService.addUser(user, headers, function (response) {
if (angular.isDefined(response.status) && response.status === 201) {
toaster.pop({
type: "success",
@ -85,7 +86,8 @@ app.controller('UserController', function ($scope,
});
modalInstance.result.then(function (modifiedUser) {
UserService.editUser(modifiedUser, function (response) {
let headers = { "User-UUID": $scope.cur_user.uuid, "Token": $scope.cur_user.token };
UserService.editUser(modifiedUser, headers, function (response) {
if (angular.isDefined(response.status) && response.status === 200) {
toaster.pop({
type: "success",
@ -123,12 +125,8 @@ app.controller('UserController', function ($scope,
});
modalInstance.result.then(function (modifiedUser) {
let data = {
name: modifiedUser.name,
password: modifiedUser.password };
let data = {name: modifiedUser.name, password: modifiedUser.password };
let headers = { "User-UUID": $scope.cur_user.uuid, "Token": $scope.cur_user.token };
UserService.resetPassword(data, headers, function (response) {
if (angular.isDefined(response.status) && response.status === 200) {
toaster.pop({
@ -166,7 +164,8 @@ app.controller('UserController', function ($scope,
},
function (isConfirm) {
if (isConfirm) {
UserService.deleteUser(user, function (response) {
let headers = { "User-UUID": $scope.cur_user.uuid, "Token": $scope.cur_user.token };
UserService.deleteUser(user, headers, function (response) {
if (angular.isDefined(response.status) && response.status === 204) {
toaster.pop({
type: "success",

View File

@ -17,16 +17,16 @@ app.factory('UserService', function($http) {
callback(response);
});
},
addUser: function(user, callback) {
$http.post(getAPI()+'users',{data:user})
addUser: function(user, headers, callback) {
$http.post(getAPI()+'users', {data:user}, {headers})
.then(function (response) {
callback(response);
}, function (response) {
callback(response);
});
},
editUser: function(user, callback) {
$http.put(getAPI()+'users/'+user.id,{data:user})
editUser: function(user, headers, callback) {
$http.put(getAPI()+'users/'+user.id, {data:user}, {headers})
.then(function (response) {
callback(response);
}, function (response) {
@ -49,16 +49,16 @@ app.factory('UserService', function($http) {
callback(response);
});
},
deleteUser: function(user, callback) {
$http.delete(getAPI()+'users/'+user.id)
deleteUser: function(user, headers, callback) {
$http.delete(getAPI()+'users/'+user.id, {headers})
.then(function (response) {
callback(response);
}, function (response) {
callback(response);
});
},
getUser: function(id, callback) {
$http.get(getAPI()+'users/'+id)
getUser: function(id, headers, callback) {
$http.get(getAPI()+'users/'+id, {headers})
.then(function (response) {
callback(response);
}, function (response) {

View File

@ -6518,15 +6518,26 @@
"type": "noauth"
},
"method": "GET",
"header": [],
"header": [
{
"key": "User-UUID",
"value": "dcdb67d1-6116-4987-916f-6fc6cf2bc0e4",
"type": "text"
},
{
"key": "Token",
"value": "b422ef869a947eb8dd058f5c9464b11769db7be3232b327fb8a4edac28118df876a5d7d3ab1d8175ef81169126d01fbe3b38baa6da62edf4cbf49b2bef0ed9a7",
"type": "text"
}
],
"url": {
"raw": "{{base_url}}/users/2",
"raw": "{{base_url}}/users/1",
"host": [
"{{base_url}}"
],
"path": [
"users",
"2"
"1"
]
}
},
@ -6536,7 +6547,18 @@
"name": "POST Create New User",
"request": {
"method": "POST",
"header": [],
"header": [
{
"key": "User-UUID",
"value": "dcdb67d1-6116-4987-916f-6fc6cf2bc0e4",
"type": "text"
},
{
"key": "Token",
"value": "b422ef869a947eb8dd058f5c9464b11769db7be3232b327fb8a4edac28118df876a5d7d3ab1d8175ef81169126d01fbe3b38baa6da62edf4cbf49b2bef0ed9a7",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\"data\":{\"name\":\"albert1\", \"display_name\":\"Mr. Albert\", \"email\":\"albert1@myems.io\", \"is_admin\":false, \"privilege_id\":1, \"password\":\"!MyEMS1\", \"account_expiration_datetime\":\"2100-01-01T00:00:00\",\"password_expiration_datetime\":\"2100-01-01T00:00:00\"}}"
@ -6579,7 +6601,18 @@
"name": "DELETE User",
"request": {
"method": "DELETE",
"header": [],
"header": [
{
"key": "User-UUID",
"value": "dcdb67d1-6116-4987-916f-6fc6cf2bc0e4",
"type": "text"
},
{
"key": "Token",
"value": "b422ef869a947eb8dd058f5c9464b11769db7be3232b327fb8a4edac28118df876a5d7d3ab1d8175ef81169126d01fbe3b38baa6da62edf4cbf49b2bef0ed9a7",
"type": "text"
}
],
"url": {
"raw": "{{base_url}}/users/2",
"host": [
@ -6597,7 +6630,18 @@
"name": "PUT Update User Profile",
"request": {
"method": "PUT",
"header": [],
"header": [
{
"key": "User-UUID",
"value": "dcdb67d1-6116-4987-916f-6fc6cf2bc0e4",
"type": "text"
},
{
"key": "Token",
"value": "b422ef869a947eb8dd058f5c9464b11769db7be3232b327fb8a4edac28118df876a5d7d3ab1d8175ef81169126d01fbe3b38baa6da62edf4cbf49b2bef0ed9a7",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\"data\":{\"name\":\"albert\", \"display_name\":\"Mr. Albert\", \"email\":\"albert@myems.io\", \"is_admin\":false, \"privilege_id\":1, \"password\":\"!MyEMS1\", \"account_expiration_datetime\":\"2100-01-01T00:00:00\",\"password_expiration_datetime\":\"2100-01-01T00:00:00\"}}"
@ -6637,7 +6681,7 @@
},
{
"key": "Token",
"value": "18f212f9fe64adcf34f6e618eb9f72a0e8b4c411",
"value": "b422ef869a947eb8dd058f5c9464b11769db7be3232b327fb8a4edac28118df876a5d7d3ab1d8175ef81169126d01fbe3b38baa6da62edf4cbf49b2bef0ed9a7",
"type": "text"
}
],
@ -6670,7 +6714,7 @@
},
{
"key": "Token",
"value": "b3a1b48ff5a9a3f67ec16848c5ddf9a42bf17045",
"value": "b422ef869a947eb8dd058f5c9464b11769db7be3232b327fb8a4edac28118df876a5d7d3ab1d8175ef81169126d01fbe3b38baa6da62edf4cbf49b2bef0ed9a7",
"type": "text"
}
],
@ -6703,7 +6747,7 @@
},
{
"key": "Token",
"value": "b3a1b48ff5a9a3f67ec16848c5ddf9a42bf17045",
"value": "b422ef869a947eb8dd058f5c9464b11769db7be3232b327fb8a4edac28118df876a5d7d3ab1d8175ef81169126d01fbe3b38baa6da62edf4cbf49b2bef0ed9a7",
"type": "text"
}
],

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class CombinedEquipmentCollection:

View File

@ -4,7 +4,7 @@ import mysql.connector
import config
import uuid
import re
from core.userlogger import user_logger
from core.useractivity import user_logger
class ContactCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class CostCenterCollection:

View File

@ -5,7 +5,7 @@ import config
import uuid
from datetime import datetime, timezone, timedelta
import os
from core.userlogger import user_logger
from core.useractivity import user_logger
class CostFileCollection:

View File

@ -4,7 +4,7 @@ import mysql.connector
import config
import uuid
from datetime import datetime, timezone, timedelta
from core.userlogger import user_logger
from core.useractivity import user_logger
class DataSourceCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class DistributionCircuitCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class DistributionSystemCollection:

View File

@ -3,7 +3,7 @@ import json
import mysql.connector
import config
from datetime import datetime, timedelta, timezone
from core.userlogger import user_logger
from core.useractivity import user_logger
class EmailMessageCollection:

View File

@ -4,7 +4,7 @@ import mysql.connector
import config
import base64
import re
from core.userlogger import user_logger
from core.useractivity import user_logger
class EmailServerCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class EnergyCategoryCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class EnergyFlowDiagramCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class EnergyItemCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class EquipmentCollection:

View File

@ -4,7 +4,7 @@ import mysql.connector
import config
import uuid
from datetime import datetime, timezone, timedelta
from core.userlogger import user_logger
from core.useractivity import user_logger
class GatewayCollection:

View File

@ -7,7 +7,7 @@ from datetime import datetime, timezone, timedelta
import os
import base64
import sys
from core.userlogger import user_logger
from core.useractivity import user_logger
class KnowledgeFileCollection:

View File

@ -2,7 +2,7 @@ import falcon
import simplejson as json
import mysql.connector
import config
from core.userlogger import user_logger
from core.useractivity import user_logger
class MenuCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class MeterCollection:

View File

@ -3,7 +3,7 @@ import json
import mysql.connector
import config
from datetime import datetime, timedelta, timezone
from core.userlogger import user_logger
from core.useractivity import user_logger
class NotificationCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class OfflineMeterCollection:

View File

@ -5,7 +5,7 @@ import config
import uuid
from datetime import datetime, timezone, timedelta
import os
from core.userlogger import user_logger
from core.useractivity import user_logger
class OfflineMeterFileCollection:

View File

@ -2,7 +2,7 @@ import falcon
import simplejson as json
import mysql.connector
import config
from core.userlogger import user_logger
from core.useractivity import user_logger
class PointCollection:

View File

@ -2,7 +2,7 @@ import falcon
import simplejson as json
import mysql.connector
import config
from core.userlogger import user_logger
from core.useractivity import user_logger
class PrivilegeCollection:

View File

@ -4,7 +4,7 @@ import mysql.connector
import uuid
from datetime import datetime, timezone, timedelta
import config
from core.userlogger import user_logger
from core.useractivity import user_logger
class RuleCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class SensorCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class ShopfloorCollection:

View File

@ -6,7 +6,7 @@ import uuid
from datetime import datetime
from anytree import AnyNode
from anytree.exporter import JsonExporter
from core.userlogger import user_logger
from core.useractivity import user_logger
class SpaceCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class StoreCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class StoreTypeCollection:

View File

@ -4,7 +4,7 @@ import mysql.connector
import config
import uuid
from datetime import datetime, timedelta, timezone
from core.userlogger import user_logger
from core.useractivity import user_logger
class TariffCollection:

View File

@ -4,7 +4,7 @@ import mysql.connector
import config
import uuid
from datetime import datetime, timedelta, timezone
from core.userlogger import user_logger
from core.useractivity import user_logger
class TenantCollection:

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class TenantTypeCollection:

View File

@ -3,7 +3,7 @@ import json
import mysql.connector
import config
from datetime import datetime, timedelta, timezone
from core.userlogger import user_logger
from core.useractivity import user_logger
class TextMessageCollection:

View File

@ -2,7 +2,7 @@ import falcon
import simplejson as json
import mysql.connector
import config
from core.userlogger import user_logger
from core.useractivity import user_logger
class TimezoneCollection:

View File

@ -7,7 +7,7 @@ import hashlib
import re
import os
from datetime import datetime, timedelta, timezone
from core.userlogger import user_logger, write_log
from core.useractivity import user_logger, write_log, access_control
class UserCollection:
@ -22,52 +22,9 @@ class UserCollection:
@staticmethod
def on_get(req, resp):
if 'USER-UUID' not in req.headers or \
not isinstance(req.headers['USER-UUID'], str) or \
len(str.strip(req.headers['USER-UUID'])) == 0:
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.INVALID_USER_UUID')
admin_user_uuid = str.strip(req.headers['USER-UUID'])
if 'TOKEN' not in req.headers or \
not isinstance(req.headers['TOKEN'], str) or \
len(str.strip(req.headers['TOKEN'])) == 0:
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.INVALID_TOKEN')
admin_token = str.strip(req.headers['TOKEN'])
# Check administrator privilege
access_control(req)
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, (admin_user_uuid, admin_token,))
row = cursor.fetchone()
if row is None:
cursor.close()
cnx.disconnect()
raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
description='API.ADMINISTRATOR_SESSION_NOT_FOUND')
else:
utc_expires = row[0]
if datetime.utcnow() > utc_expires:
cursor.close()
cnx.disconnect()
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.ADMINISTRATOR_SESSION_TIMEOUT')
query = (" SELECT name "
" FROM tbl_users "
" WHERE uuid = %s AND is_admin = true ")
cursor.execute(query, (admin_user_uuid,))
row = cursor.fetchone()
if row is None:
cursor.close()
cnx.disconnect()
raise falcon.HTTPError(falcon.HTTP_400, 'API.BAD_REQUEST', 'API.INVALID_PRIVILEGE')
query = (" SELECT u.id, u.name, u.display_name, u.uuid, "
" u.email, u.is_admin, p.id, p.name, "
" u.account_expiration_datetime_utc, u.password_expiration_datetime_utc "
@ -110,7 +67,7 @@ class UserCollection:
@staticmethod
def on_post(req, resp):
"""Handles POST requests"""
# todo: add access control
access_control(req)
# todo: add user log
try:
raw_json = req.stream.read().decode('utf-8')
@ -246,7 +203,7 @@ class UserItem:
@staticmethod
def on_get(req, resp, id_):
# todo: add access control
access_control(req)
if not id_.isdigit() or int(id_) <= 0:
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.INVALID_USER_ID')
@ -291,6 +248,7 @@ class UserItem:
@staticmethod
@user_logger
def on_delete(req, resp, id_):
access_control(req)
if not id_.isdigit() or int(id_) <= 0:
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.INVALID_USER_ID')
@ -320,6 +278,7 @@ class UserItem:
@user_logger
def on_put(req, resp, id_):
"""Handles PUT requests"""
access_control(req)
try:
raw_json = req.stream.read().decode('utf-8')
except Exception as ex:

View File

@ -9,6 +9,58 @@ import simplejson as json
import falcon
def access_control(req):
"""
Check administrator privilege in request headers to protect resources from invalid access
:param req: HTTP request
:return: HTTPError if invalid else None
"""
if 'USER-UUID' not in req.headers or \
not isinstance(req.headers['USER-UUID'], str) or \
len(str.strip(req.headers['USER-UUID'])) == 0:
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.INVALID_USER_UUID')
admin_user_uuid = str.strip(req.headers['USER-UUID'])
if 'TOKEN' not in req.headers or \
not isinstance(req.headers['TOKEN'], str) or \
len(str.strip(req.headers['TOKEN'])) == 0:
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.INVALID_TOKEN')
admin_token = str.strip(req.headers['TOKEN'])
# Check administrator privilege
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, (admin_user_uuid, admin_token,))
row = cursor.fetchone()
if row is None:
cursor.close()
cnx.disconnect()
raise falcon.HTTPError(falcon.HTTP_404, title='API.NOT_FOUND',
description='API.ADMINISTRATOR_SESSION_NOT_FOUND')
else:
utc_expires = row[0]
if datetime.utcnow() > utc_expires:
cursor.close()
cnx.disconnect()
raise falcon.HTTPError(falcon.HTTP_400, title='API.BAD_REQUEST',
description='API.ADMINISTRATOR_SESSION_TIMEOUT')
query = (" SELECT name "
" FROM tbl_users "
" WHERE uuid = %s AND is_admin = true ")
cursor.execute(query, (admin_user_uuid,))
row = cursor.fetchone()
cursor.close()
cnx.disconnect()
if row is None:
raise falcon.HTTPError(falcon.HTTP_400, 'API.BAD_REQUEST', 'API.INVALID_PRIVILEGE')
def write_log(user_uuid, request_method, resource_type, resource_id, request_body):
"""
:param user_uuid: user_uuid
@ -43,6 +95,11 @@ def write_log(user_uuid, request_method, resource_type, resource_id, request_bod
def user_logger(func):
"""
Decorator for logging user activities
:param func: the decorated function
:return: the decorator
"""
@wraps(func)
def logger(*args, **kwargs):
qualified_name = func.__qualname__

View File

@ -3,7 +3,7 @@ import simplejson as json
import mysql.connector
import config
import uuid
from core.userlogger import user_logger
from core.useractivity import user_logger
class VirtualMeterCollection:

View File

@ -3,7 +3,7 @@ import json
import mysql.connector
import config
from datetime import datetime, timedelta, timezone
from core.userlogger import user_logger
from core.useractivity import user_logger
class WebMessageCollection:

View File

@ -3,7 +3,7 @@ import json
import mysql.connector
import config
from datetime import datetime, timedelta, timezone
from core.userlogger import user_logger
from core.useractivity import user_logger
class WechatMessageCollection(object):