Browse Source

"json response normalization"

ash 2 năm trước cách đây
mục cha
commit
00edd97922

+ 44 - 25
Backend/Sources/Modules/Inventory/inventory_view.py

@@ -72,36 +72,35 @@ def declare_route() :
         for item in inventory.get_all_inventory_items() :
             ret.append(item)
 
-        return json.dumps(ret, cls=model_manager.ComplexEncoder)
+        return view.JsonStringToResponse(json.dumps(ret, cls=model_manager.ComplexEncoder))
 
     @inventory_blueprint.route('/item/<int:itemID>',methods =  ['GET'])
     @view_privilege.manager.require_authorization(required_role=inventory_read_only_role,get_privilege_func=view.get_user_privilege)
     def get_item(itemID : int) :
-        return model_manager.ModelObjectToJsonString(inventory.get_inventory_item(itemID))
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.get_inventory_item(itemID)))
 
 
     @inventory_blueprint.route('/item/<int:itemID>',methods =  ['UPDATE','DELETE'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def update_or_delete_item(itemID : int) :
         if flask.request.method == 'UPDATE':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_item_update(itemID,json.dumps(flask.request.json)))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_item_update(itemID,json.dumps(flask.request.json))))
 
         if flask.request.method == 'DELETE':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_item_delete(itemID))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_item_delete(itemID)))
 
 
     @inventory_blueprint.route('/item',methods = ['POST'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def create_item() :
 
-        return model_manager.ModelObjectToJsonString(inventory.inventory_item_create(json.dumps(flask.request.json)))
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_item_create(json.dumps(flask.request.json))))
 
 
     @inventory_blueprint.route('/item/template',methods = ['GET'])
     @view_privilege.manager.require_authorization(required_role=inventory_read_only_role,get_privilege_func=view.get_user_privilege)
     def get_item_template() :
-
-        return model_manager.ModelObjectToJsonString(inventory.inventory_item())
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_item()))
 
 
 
@@ -121,28 +120,27 @@ def declare_route() :
     @inventory_blueprint.route('/site/<int:siteID>',methods =  ['GET'])
     @view_privilege.manager.require_authorization(required_role=inventory_read_only_role,get_privilege_func=view.get_user_privilege)
     def get_site(siteID : int) :
-        return model_manager.ModelObjectToJsonString(inventory.get_inventory_site(siteID))
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.get_inventory_site(siteID)))
 
 
     @inventory_blueprint.route('/site/<int:siteID>',methods =  ['UPDATE','DELETE'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def update_or_delete_site(siteID : int) :
         if flask.request.method == 'UPDATE':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_site_update(siteID,json.dumps(flask.request.json)))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_site_update(siteID,json.dumps(flask.request.json))))
 
         if flask.request.method == 'DELETE':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_site_delete(siteID))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_site_delete(siteID)))
 
     @inventory_blueprint.route('/site',methods = ['POST'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def create_site() :
-        return model_manager.ModelObjectToJsonString(inventory.inventory_site_create(json.dumps(flask.request.json)))
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_site_create(json.dumps(flask.request.json))))
 
     @inventory_blueprint.route('/site/template',methods = ['GET'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def get_site_template() :
-
-        return model_manager.ModelObjectToJsonString(inventory.inventory_site())
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_site()))
 
 #############################################
 ########           contacts          ########
@@ -161,29 +159,29 @@ def declare_route() :
     @inventory_blueprint.route('/contact/<int:contactID>',methods = ['GET'])
     @view_privilege.manager.require_authorization(required_role=inventory_read_only_role,get_privilege_func=view.get_user_privilege)
     def get_contact(contactID : int) :
-        return model_manager.ModelObjectToJsonString(inventory.get_inventory_contact(contactID))
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.get_inventory_contact(contactID)))
 
     @inventory_blueprint.route('/contact/<int:contactID>',methods = ['UPDATE','DELETE'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def update_or_delete_contact(contactID : int) :
         if flask.request.method == 'UPDATE':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_contact_update(contactID,json.dumps(flask.request.json)))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_contact_update(contactID,json.dumps(flask.request.json))))
 
         if flask.request.method == 'DELETE':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_contact_delete(contactID))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_contact_delete(contactID)))
 
 
     @inventory_blueprint.route('/contact',methods = ['POST'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def create_contact() :
-        return model_manager.ModelObjectToJsonString(inventory.inventory_contact_create(json.dumps(flask.request.json)))
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_contact_create(json.dumps(flask.request.json))))
 
 
     @inventory_blueprint.route('/contact/template',methods = ['GET'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def get_contact_template() :
 
-        return model_manager.ModelObjectToJsonString(inventory.inventory_contact())
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_contact()))
 
 #############################################
 ########           groups            ########
@@ -201,39 +199,60 @@ def declare_route() :
     @inventory_blueprint.route('/group/<int:groupID>',methods = ['GET'])
     @view_privilege.manager.require_authorization(required_role=inventory_read_only_role,get_privilege_func=view.get_user_privilege)
     def get_group(groupID : int) :
-        return model_manager.ModelObjectToJsonString(inventory.get_inventory_group(groupID))
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.get_inventory_group(groupID)))
 
     @inventory_blueprint.route('/group/<int:groupID>',methods = ['UPDATE','DELETE'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def update_or_delete_group(groupID : int) :
         if flask.request.method == 'UPDATE':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_group_update(groupID,json.dumps(flask.request.json)))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_group_update(groupID,json.dumps(flask.request.json))))
 
         if flask.request.method == 'DELETE':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_group_delete(groupID))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_group_delete(groupID)))
 
     @inventory_blueprint.route('/group',methods = ['POST'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def create_group() :
-        return model_manager.ModelObjectToJsonString(inventory.inventory_group_create(json.dumps(flask.request.json)))
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_group_create(json.dumps(flask.request.json))))
 
 
     @inventory_blueprint.route('/group/<int:groupID>/item/<int:itemID>',methods = ['POST','DELETE'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def manage_group_members(groupID : int,itemID : int) :
         if flask.request.method == 'POST':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_group_add_item(groupID,itemID))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_group_add_item(groupID,itemID)))
         if flask.request.method == 'DELETE':
-            return model_manager.ModelObjectToJsonString(inventory.inventory_group_delete_item(groupID,itemID))
+            return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_group_delete_item(groupID,itemID)))
 
 
     @inventory_blueprint.route('/group/template',methods = ['GET'])
     @view_privilege.manager.require_authorization(required_role=inventory_admin_role,get_privilege_func=view.get_user_privilege)
     def get_group_template() :
 
-        return model_manager.ModelObjectToJsonString(inventory.inventory_group())
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.inventory_group()))
+
+
 
 
 
+#############################################
+########         aggregation         ########
+#############################################
+
+
+    @inventory_blueprint.route('/group/<int:groupID>/items',methods = ['GET'])
+    @view_privilege.manager.require_authorization(required_role=inventory_read_only_role,get_privilege_func=view.get_user_privilege)
+    def get_group_items(groupID : int) :
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.get_inventory_group_items(groupID)))
+
+    @inventory_blueprint.route('/contact/<int:contactID>/items',methods = ['GET'])
+    @view_privilege.manager.require_authorization(required_role=inventory_read_only_role,get_privilege_func=view.get_user_privilege)
+    def get_contact_items(contactID : int) :
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.get_inventory_contact_items(contactID)))
+
+    @inventory_blueprint.route('/site/<int:siteID>/items',methods = ['GET'])
+    @view_privilege.manager.require_authorization(required_role=inventory_read_only_role,get_privilege_func=view.get_user_privilege)
+    def get_site_items(siteID : int) :
+        return view.JsonStringToResponse(model_manager.ModelObjectToJsonString(inventory.get_inventory_site_items(siteID)))
 
 

+ 119 - 0
Backend/Sources/View/view_basics_api.py

@@ -0,0 +1,119 @@
+import Model.isp_model as isp_model
+from flask import session,request,jsonify
+import Model.model_manager as model_manager
+from werkzeug.security import check_password_hash,generate_password_hash
+import persistence
+import json
+import View.view_privilege as privileges
+import logging
+from utility.app_logging import logger_name
+logger = logging.getLogger(logger_name + ".VIEW")
+
+__api_login_url__ = "/api/login"
+__id_counter__ : int = 1
+
+def define_basic_api(app) :
+
+
+    @app.before_request
+    def before_request_func():
+
+        global __id_counter__
+        logger.debug("before_request processing")
+        logger.debug("request from " + request.remote_addr)
+        logger.debug("request header" + str(request.headers.__dict__))
+
+        if request.json :
+            logger.debug("request json body : " + str(request.json))
+
+
+        if not "client_id" in session :
+            session["client_id"] = str(__id_counter__)
+        logger.debug("client_id is " + session["client_id"])
+        __id_counter__ = __id_counter__ + 1
+
+
+        if not request.path == __api_login_url__ and not "username" in session :
+            logger.warning("Unauthorized client with id " + session["client_id"] + " try to access application")
+            resp = jsonify({'message' : 'Unauthorized access, request is not from and authentificated user.'})
+            resp.status_code = 401
+            return resp
+
+        if "username" in session :
+            logger.debug("request from  " + session["username"])
+
+
+    @app.route(__api_login_url__,methods = ['POST'])
+    def login():
+        _json = request.json
+        _username = _json['username']
+        _password = _json['password']
+
+
+        with persistence.get_Session_Instance() as sess :
+
+            Item = sess.query(isp_model.user_account).filter(isp_model.user_account.nickname == _username).first()
+            if not isinstance(Item,isp_model.user_account) :
+                logger.warning("user tried to login with unknown account name : " + _username)
+                resp = jsonify({'message' : 'Bad Request - user account not found'})
+                resp.status_code = 400
+                return resp
+
+            if not check_password_hash(Item.password,_password) :
+                logger.warning("user with account name '" + _username + "' tried to login with invalid password")
+                resp = jsonify({'message' : 'Bad Request - invalid password for this account'})
+                resp.status_code = 400
+                return resp
+
+
+
+            session["username"] = _username
+            session["user_account_id"] = Item.id
+            logger.info("account " + _username + " logged IN successfully with id : " + session["client_id"])
+            resp = jsonify({'message' : 'login successful'})
+            resp.status_code = 200
+            return resp
+
+
+
+
+    @app.route('/api/logout',methods = ['DELETE'])
+    def logout():
+        logger.info("account " + session["username"] + " logged OUT with id : " + session["client_id"])
+        session.clear()
+        return jsonify('logout')
+
+    @app.route('/api/me',methods = ['GET'])
+    def user_description():
+        with persistence.get_Session_Instance() as sess :
+            item : isp_model.user_account = sess.query(isp_model.user_account).filter(isp_model.user_account.id == session["client_id"]).first()
+            json_string = model_manager.ModelObjectToJsonString(item)
+            json_dict : dict = json.loads(json_string)
+            json_dict.pop("password") # removing the password item for security
+            json_string = json.dumps(json_dict)
+            return jsonify(json_dict)
+
+    @app.route('/api/password',methods = ['POST'])
+    def change_password():
+        _json = request.json
+        _old_password = _json['old_password']
+        _password     = _json['new_password']
+        with persistence.get_Session_Instance() as sess :
+            Item : isp_model.user_account = sess.query(isp_model.user_account).filter(isp_model.user_account.id == session["user_account_id"]).first()
+
+
+            if not check_password_hash(Item.password,_password) :
+                raise Exception("old password is incorrect")
+
+            Item.password = generate_password_hash(_password)
+            sess.commit()
+
+        return jsonify('password changed')
+
+
+    @app.route('/routes',methods = ['GET'])
+    def routes():
+        routes = []
+        for route in app.url_map.iter_rules():
+            routes.append('%s' % route)
+        return jsonify(routes)

+ 2 - 1
Backend/Sources/View/view_error_management.py

@@ -27,7 +27,8 @@ def define_error_management(app) :
     def handle_generic_error(err) :
         exc_type,exc_obj,exc_tb = sys.exc_info()
         """Return JSON instead of HTML for any other server error"""
-        logger.error(f"Exception: {str(err)}")
+
+        logger.error(f"Exception: {str(err) + traceback.format_exc()}")
         response = {"error": str(err) }
         return jsonify(response), 500
 

+ 17 - 109
Backend/Sources/View/view_manager.py

@@ -2,8 +2,8 @@ from array import array
 import threading
 from flask import session,Flask,request, jsonify
 import flask
-from utility.app_logging import logger_name
-import logging
+
+
 import persistence
 import Model.isp_model as isp_model
 import Model.model_manager as model_manager
@@ -14,25 +14,25 @@ from datetime import timedelta
 import View.view_error_management as view_error_management
 from flask_limiter import Limiter
 from flask_limiter.util import get_remote_address
+import json
+import View.view_basics_api as view_basic_api
 
 
+import logging
+from utility.app_logging import logger_name
 logger = logging.getLogger(logger_name + ".VIEW")
 
 __app__ = Flask("OpenIsp")
 __app__.secret_key = "aseqzdwxc"
 __app__.permanent_session_lifetime = timedelta(minutes=2)
 __app__.logger = logger
-#CORS(__app__)
+__app__.config['JSONIFY_PRETTYPRINT_REGULAR'] = True
 
-__resource_array__ : array
-__id_counter__ : int = 1
 
 
-limiter = Limiter(__app__,key_func=get_remote_address,default_limits=["500 per minute"])
+limiter = Limiter(__app__,key_func=get_remote_address,default_limits=["100 per minute"])
 limiter.logger = logger
 
-
-
 from werkzeug.serving import make_server
 class ServerThread(threading.Thread):
 
@@ -58,38 +58,11 @@ def get_user_privilege() :
 def init() :
     privileges.init()
     view_error_management.define_error_management(__app__)
+    view_basic_api.define_basic_api(__app__)
 
 
-
-@__app__.before_request
-def before_request_func():
-
-    global __id_counter__
-    logger.debug("before_request processing")
-    logger.debug("request from " + request.remote_addr)
-    logger.debug("request header" + str(request.headers.__dict__))
-
-    if request.json :
-        logger.debug("request json body : " + str(request.json))
-
-
-    if not "client_id" in session :
-        session["client_id"] = str(__id_counter__)
-    logger.debug("client_id is " + session["client_id"])
-    __id_counter__ = __id_counter__ + 1
-
-
-    if not request.path == "/api/login" and not "username" in session :
-        logger.warning("Unauthorized client with id " + session["client_id"] + " try to access application")
-        resp = jsonify({'message' : 'Unauthorized'})
-        resp.status_code = 401
-        return resp
-
-    if "username" in session :
-        logger.debug("request from  " + session["username"])
-
 @__app__.after_request
-def after_request(response):
+def after_request(response : flask.Response):
     header = response.headers
 
     # adding this to the header to allow cross origin
@@ -98,77 +71,14 @@ def after_request(response):
     header['Access-Control-Allow-Origin'] = '*'
     header['Access-Control-Allow-Methods'] = 'GET,DELETE,UPDATE,HEAD,OPTIONS,POST,PUT'
     header['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept, Authorization'
-    return response
-
-
-
-@__app__.route('/api/login',methods = ['POST'])
-def login():
-    _json = request.json
-    _username = _json['username']
-    _password = _json['password']
-
-
-    with persistence.get_Session_Instance() as sess :
-
-        Item = sess.query(isp_model.user_account).filter(isp_model.user_account.nickname == _username).first()
-        if not isinstance(Item,isp_model.user_account) :
-            logger.warning("user tried to login with unknown account name : " + _username)
-            resp = jsonify({'message' : 'Bad Request - user account not found'})
-            resp.status_code = 400
-            return resp
-
-        if not check_password_hash(Item.password,_password) :
-            logger.warning("user with account name '" + _username + "' tried to login with invalid password")
-            resp = jsonify({'message' : 'Bad Request - invalid password for this account'})
-            resp.status_code = 400
-            return resp
-
-
-
-        session["username"] = _username
-        session["user_account_id"] = Item.id
-        logger.info("account " + _username + " logged IN successfully with id : " + session["client_id"])
-        resp = jsonify({'message' : 'login successful'})
-        resp.status_code = 200
-        return resp
-
-@__app__.route('/api/logout',methods = ['DELETE'])
-def logout():
-    logger.info("account " + session["username"] + " logged OUT with id : " + session["client_id"])
-    session.clear()
-    return jsonify('logout')
-
-
-@__app__.route('/api/password',methods = ['POST'])
-def change_password():
-    _json = request.json
-    _old_password = _json['old_password']
-    _password     = _json['new_password']
-    with persistence.get_Session_Instance() as sess :
-        Item : isp_model.user_account = sess.query(isp_model.user_account).filter(isp_model.user_account.id == session["user_account_id"]).first()
-
-
-        if not check_password_hash(Item.password,_password) :
-            raise Exception("old password is incorrect")
-
-        Item.password = generate_password_hash(_password)
-        sess.commit()
-
-    return jsonify('password changed')
-
-
-@__app__.route('/routes',methods = ['GET'])
-@privileges.manager.require_authorization(required_role=inventory_view.inventory_admin_role,get_privilege_func=get_user_privilege)
-def routes():
-    routes = []
-    for route in __app__.url_map.iter_rules():
-        routes.append('%s' % route)
-    return jsonify(routes)
 
+    logger.debug(response.__dict__)
 
+    return response
 
 
+def JsonStringToResponse(string : str) :
+    return jsonify(json.loads(string))
 
 def run() :
     global __server_process__
@@ -177,7 +87,6 @@ def run() :
     logger.info('View server started')
 
 
-
 def stop() :
     global __server_process__
     __server_process__.shutdown()
@@ -185,12 +94,11 @@ def stop() :
 
 
 def register_blueprint(blueprint : flask.Blueprint) :
+    assert isinstance(blueprint,flask.Blueprint)
     logger.info("registering view (blueprint) : '" + blueprint.name + "' with prefix '" + blueprint.url_prefix +"'")
     __app__.register_blueprint(blueprint)
 
-@privileges.manager.require_authorization(required_role=inventory_view.inventory_read_only_role,get_privilege_func=get_user_privilege)
-def tab():
-    return jsonify([2,5,7])
 
 
-__app__.add_url_rule("/tab","/tab",tab)
+
+

+ 0 - 2
Backend/Sources/View/view_privilege.py

@@ -12,8 +12,6 @@ def init() :
     load_privilege_data()
 
 
-
-
 def save_privilege_data() :
     None
 

+ 0 - 0
requirement.txt