from array import array from msilib.schema import Class from re import I import threading from tkinter.ttk import Separator from typing import Type from xmlrpc.client import boolean from flask import session,Flask,request, jsonify from flask_restful import Resource, Api import flask_restful from itsdangerous import json from sqlalchemy import delete 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 from werkzeug.security import check_password_hash import anytree import View.view_privilege as privileges from datetime import timedelta from flask_session import Session import View.view_error_management as view_error_management logger = logging.getLogger(logger_name + ".VIEW") __app__ = Flask("OpenIsp") __app__.secret_key = "aseqzdwxc" __app__.permanent_session_lifetime = timedelta(minutes=2) __app__.config["SESSION_PERMANENT"] = False __app__.config["SESSION_TYPE"] = "filesystem" __resource_array__ : array __id_counter__ : int = 1 from werkzeug.serving import make_server class ServerThread(threading.Thread): def __init__(self, app,ip,port): threading.Thread.__init__(self) self.server = make_server(ip, port, app) self.ctx = app.app_context() self.ctx.push() def run(self): logger.info('starting server') self.server.serve_forever() def shutdown(self): self.server.shutdown() __server_process__ : ServerThread def get_roles_ids() : return session["roles_ids"] def init() : @__app__.before_request def before_request_func(): print(request.headers.__dict__) global __id_counter__ logger.debug("before_request is running!") 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"]) from flask.logging import default_handler __app__.logger.removeHandler(default_handler) privileges.init() view_error_management.define_error_management(__app__) @__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["account_data"] = model_manager.ModelObjectToJsonString(Item) session["roles_ids"] = [privileges.inventory_read_only_role.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 = ['POST']) def logout(): logger.info("account " + session["username"] + " logged OUT with id : " + session["client_id"]) session.clear() return jsonify('logout') @__app__.route('/routes',methods = ['GET']) @privileges.manager.require_authorization(required_role=privileges.inventory_admin_role,ids_getter=get_roles_ids) def routes(): routes = [] for route in __app__.url_map.iter_rules(): routes.append('%s' % route) return jsonify(routes) def run() : global __server_process__ __server_process__ = ServerThread(__app__,"0.0.0.0",8000) __server_process__.start() logger.info('View server started') def stop() : global __server_process__ __server_process__.shutdown() logger.info('View server stopped') class ResourceNode(anytree.NodeMixin) : def __init__(self, url_key : str, resource = None, parent=None, children=None): super(ResourceNode, self).__init__() self.url_key = url_key self.parent = parent if children: self.children = children if resource : self.resource = resource # we check if the resource class has an http API method get = getattr(self, "get", None) post = getattr(self, "post", None) delete = getattr(self, "delete", None) update = getattr(self, "update", None) patch = getattr(self, "patch", None) if not callable(get) and not callable(post) \ and not callable(delete) and not callable(update) \ and not callable(patch) : raise BaseException("class does have an api class") url_slice = None resource = None def add_resource_tree(node : ResourceNode) : if not node.is_root() : raise BaseException("node is not a root node") logger.debug("adding resource tree for API") logger.debug(anytree.RenderTree(node, style=anytree.AsciiStyle()).by_attr("url_slice")) for node in anytree.PreOrderIter(node) : logger.debug("iterating though node " + node.url_key) if node.resource is not None : logger.debug("resource found") url = "" parent : ResourceNode for parent in node.ancestors : url = url + node.separator + parent.url_key print("url built for the node : " + url) __api__.add_resource(node.resource, url) __resource_array__.append(node) #node.ancestors ( all parent ) def delete_resource_tree(node : ResourceNode, cascade : boolean = True) : if not cascade and not node.is_leaf() : raise BaseException("cannot delete only a node when it's not a leaf !") raise BaseException("Not implemented yet") #TODO