def _prepare_app(): """ Setup the initial APP values and initialize various flask plugins. :returns: flask app instance """ # init JSGLUE. this is needed to query URLs in javascript _js_glue = JSGlue(APP) cfg_rdr = ConfigReader() APP.config['SECRET_KEY'] = cfg_rdr.get_attr('db_secret_key') APP.config['SQLALCHEMY_DATABASE_URI'] = cfg_rdr.get_attr('db_address') # needed because this functionality is already depricated APP.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # the salt is a workaround for a bug, as flask-security salts passwords # automatically but somehow it requires and uses this config value which # breaks the login if the salt is individually unique (as a salt should be) APP.config['SECURITY_PASSWORD_SALT'] = 'fake_salt' APP.config['SECURITY_TRACKABLE'] = True APP.config['SECURITY_REGISTERABLE'] = True APP.config['SECURITY_CONFIRMABLE'] = False APP.config['UPLOAD_FOLDER'] = 'config' # max upload size is 50 KB APP.config['MAX_CONTENT_LENGTH'] = 50 * 1024 path = os.path.join('.', os.path.dirname(__file__), 'static/js/sijax/') APP.config['SIJAX_STATIC_PATH'] = path APP.config['SIJAX_JSON_URI'] = '/static/js/sijax/json2.js' flask_sijax.Sijax(APP) APP.config['JWT_ALGORITHM'] = 'RS256' with open(cfg_rdr.get_attr('private_key_file_location'), 'rb') as file: APP.config['JWT_PRIVATE_KEY'] = file.read() JWT = JWTManager(APP) with APP.app_context(): DB.init_app(APP) user_datastore = SQLAlchemyUserDatastore(DB, User, Role) _security = Security(APP, user_datastore) setup(user_datastore) rs256_token = create_access_token(str(current_user), expires_delta=False) APP.config['access_headers'] = {'Authorization': 'Bearer {}' .format(rs256_token)} JSONService.init(APP.config['access_headers']) return APP
def _populate_db(user_datastore): """ Reads the initial credentials from the configuration file. """ DB.create_all() cfg_rdr = ConfigReader() user_datastore.create_role( name='admin', description='Admins are able to manage users and configure the \ controller.') user_datastore.create_user(email=cfg_rdr.get_attr('username'), password=encrypt_password( cfg_rdr.get_attr('password')), roles=['admin']) DB.session.commit()
states = [] for miner in range(self._length): state = int(_read("?miner {}".format(miner))) states.append(GET_ACTIONS[state]) return states def get_all(self): resp = _read("?miners") miner_list = [] for miner in resp.split(', '): miner_list.append(GET_ACTIONS[int(miner)]) return miner_list CFG_RDR = ConfigReader(path='config/config.ini') SERIAL = serial.Serial(CFG_RDR.get_attr('serial_port'), CFG_RDR.get_attr('baudrate')) def _read(cmd): """ Read whole serial interface buffer. :returns: stripped str """ _write(cmd) while not SERIAL.in_waiting: time.sleep(.1) return SERIAL.read(SERIAL.in_waiting).decode('utf-8').strip()
""" Small collection of classes that map JSON resources. The name of each class method corresponds to the HTTP request method name. To define the names of the endpoints one simply has to add the resource in the `prepare_app` function """ from flask import Flask from flask_restful import Resource, Api, reqparse from flask_jwt_extended import JWTManager, jwt_required, create_access_token from src.mc_wrapper import Microcontroller from src.config_reader import ConfigReader MC = Microcontroller() APP = Flask(__name__) APP.config['JWT_ALGORITHM'] = 'RS256' CFG_RDR = ConfigReader(path='config/config.ini') with open(CFG_RDR.get_attr('public_key_file_location'), 'rb') as file: APP.config['JWT_PUBLIC_KEY'] = file.read() JWT = JWTManager(APP) API = Api(APP) PARSER = reqparse.RequestParser() class Info(Resource): @jwt_required def get(self): return {'firmware_version': MC.info_fw_version} class Temperature(Resource): @jwt_required
class JSONService: """ This class encapsulates all requests made by the frontend to the backend. Most of the requests need to be done with `requests`, but some also act on local files. To use this class a jwt_token is required, otherwise the backend is not going to accept any requests. """ def __init__(self, jwt_headers=None): """ Initializing all necessary attributes. :param jwt_headers: jwt_token to be passed in the header of future\ requests """ self.jwt_headers = jwt_headers self.cfg_rdr = ConfigReader() self.connection = self.cfg_rdr.get_attr('backend_address') self.session = requests.Session() self.adapter = requests.adapters.HTTPAdapter(max_retries=10) self.session.mount('http://', self.adapter) def init(self, jwt_headers): """ Useful for injecting the jwt_headers at a later time. """ self.jwt_headers = jwt_headers def get(self, resource): """ Returns the data from the specified resource. :param resource: JSON resource URI :returns: json data """ return self.session.get(self.connection + resource, headers=self.jwt_headers).json() def put(self, resource, data, exclude=[]): """ Puts the data to the specified resource. :param resource: JSON resource URI :param data: data to be posted. has to be an `ImmutableMultiDict` which\ are requests caught by flask. :param exclude: list of json keys which should be excluded :returns: raises an exception in case the request went wrong """ copy = data.copy().to_dict() for item in exclude: copy.pop(item, None) resp = self.session.put(self.connection + resource, data=copy, headers=self.jwt_headers) return resp.raise_for_status() def patch(self, resource, data, exclude=[]): """ Patches the data to the specified resource. :param resource: JSON resource URI :param data: data to be posted. has to be an `ImmutableMultiDict` which\ are requests caught by flask. :param exclude: list of json keys which should be excluded :returns: raises an exception in case the request went wrong """ copy = data.copy().to_dict() for item in exclude: copy.pop(item, None) resp = self.session.patch(self.connection + resource, data=copy, headers=self.jwt_headers) return resp.raise_for_status() def write_json(self, data, filename='config/layout.json'): """ Writes the data to a local json file. :param data: by default an `ImmutableMultiDict`, can also be a `dict` """ if isinstance(data, ImmutableMultiDict): layout = data.copy().to_dict() else: layout = data with open(filename, 'w') as file: json.dump(layout, file) def read_json(self, filename, catch_exception=True): """ Reads a local json file. If desired the exception that occurs in case the file does not exist may be caught internally and an `None` object may be returned. :param filename: JSON resource URI :param catch_exception: header containing JWT token for auth :returns: `dict` of json data :raises FileNotFoundError: if `catch_exception` is `false` """ try: with open(filename) as file: data = json.load(file) except FileNotFoundError: if catch_exception: data = None else: raise FileNotFoundError return data def patch_str(self, resource, data): """ Patches the raw string data to the specified resource. :param resource: JSON resource URI :param data: data to be posted. has to be an `ImmutableMultiDict` which\ are requests caught by flask. :param exclude: list of json keys which should be excluded :returns: raises an exception in case the request went wrong """ json_data = json.load(data) resp = self.session.patch(self.connection + resource, data=json_data, headers=self.jwt_headers) return resp.raise_for_status() @staticmethod def resp_to_dict(resp): """ Transforms an `ImmutableMultiDict` into a regular `dict`. :param resp: `ImmutableMultiDict` :returns: boring, old `dict` """ return resp.copy().to_dict()