# -*- coding: UTF-8 -* # pylint: disable=invalid-name from app.scodoc.sco_exceptions import ScoValueError import os import sys import logging from logging.handlers import SMTPHandler, RotatingFileHandler from flask import request from flask import Flask from flask import current_app from flask import g from flask import render_template from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_login import LoginManager from flask_mail import Mail from flask_bootstrap import Bootstrap from flask_moment import Moment from flask_caching import Cache from config import DevConfig from app.scodoc import notesdb as ndb from app.scodoc import sco_cache db = SQLAlchemy() migrate = Migrate() login = LoginManager() login.login_view = "auth.login" login.login_message = "Please log in to access this page." mail = Mail() bootstrap = Bootstrap() moment = Moment() cache = Cache( # XXX TODO: configuration file config={ # "CACHE_TYPE": "MemcachedCache" "CACHE_TYPE": "RedisCache" } ) def handle_sco_value_error(exc): return render_template("sco_value_error.html", exc=exc), 404 def create_app(config_class=DevConfig): app = Flask(__name__, static_url_path="/ScoDoc/static", static_folder="static") app.logger.setLevel(logging.DEBUG) app.config.from_object(config_class) app.logger.info(f"create_app({config_class.__name__})") db.init_app(app) migrate.init_app(app, db) login.init_app(app) mail.init_app(app) bootstrap.init_app(app) moment.init_app(app) cache.init_app(app) sco_cache.CACHE = cache app.register_error_handler(ScoValueError, handle_sco_value_error) from app.auth import bp as auth_bp app.register_blueprint(auth_bp, url_prefix="/auth") from app.views import essais_bp app.register_blueprint(essais_bp, url_prefix="/Essais") from app.main import bp as main_bp from app.views import scodoc_bp from app.views import scolar_bp from app.views import notes_bp from app.views import users_bp from app.views import absences_bp app.register_blueprint(main_bp) # XXX à enlever en production #sco8 # https://scodoc.fr/ScoDoc app.register_blueprint(scodoc_bp) # https://scodoc.fr/ScoDoc/RT/Scolarite/... app.register_blueprint(scolar_bp, url_prefix="/ScoDoc//Scolarite") # https://scodoc.fr/ScoDoc/RT/Scolarite/Notes/... app.register_blueprint(notes_bp, url_prefix="/ScoDoc//Scolarite/Notes") # https://scodoc.fr/ScoDoc/RT/Scolarite/Users/... app.register_blueprint(users_bp, url_prefix="/ScoDoc//Scolarite/Users") # https://scodoc.fr/ScoDoc/RT/Scolarite/Absences/... app.register_blueprint( absences_bp, url_prefix="/ScoDoc//Scolarite/Absences" ) if not app.debug and not app.testing: if app.config["MAIL_SERVER"]: auth = None if app.config["MAIL_USERNAME"] or app.config["MAIL_PASSWORD"]: auth = (app.config["MAIL_USERNAME"], app.config["MAIL_PASSWORD"]) secure = None if app.config["MAIL_USE_TLS"]: secure = () mail_handler = SMTPHandler( mailhost=(app.config["MAIL_SERVER"], app.config["MAIL_PORT"]), fromaddr="no-reply@" + app.config["MAIL_SERVER"], toaddrs=[app.config["ADMINS"]], subject="ScoDoc8 Failure", credentials=auth, secure=secure, ) mail_handler.setLevel(logging.ERROR) app.logger.addHandler(mail_handler) if not os.path.exists("logs"): os.mkdir("logs") file_handler = RotatingFileHandler( "logs/scodoc.log", maxBytes=10240, backupCount=10 ) file_handler.setFormatter( logging.Formatter( "%(asctime)s %(levelname)s: %(message)s " "[in %(pathname)s:%(lineno)d]" ) ) file_handler.setLevel(logging.INFO) app.logger.addHandler(file_handler) app.logger.setLevel(logging.INFO) app.logger.info("ScoDoc8 startup") return app def user_db_init(): """Initialize the users database.""" from app.auth.models import User, Role current_app.logger.info("Init User's db") # Create roles: Role.insert_roles() current_app.logger.info("created initial roles") # Ensure that admin exists admin_mail = current_app.config.get("SCODOC_ADMIN_MAIL") if admin_mail: admin_user_name = current_app.config["SCODOC_ADMIN_LOGIN"] user = User.query.filter_by(user_name=admin_user_name).first() if not user: user = User(user_name=admin_user_name, email=admin_mail) try: db.session.add(user) db.session.commit() except: db.session.rollback() raise current_app.logger.info( "created initial admin user, login: {u.user_name}, email: {u.email}".format( u=user ) ) def sco_db_init(): """Initialize Sco database""" from app import models current_app.logger.info("Init Sco db") # Modalités: models.NotesFormModalite.insert_modalites() def initialize_scodoc_database(erase=False): """Initialize the database. Starts from an existing database and create all necessary SQL tables and functions. If erase is True, _erase_ all database content. """ from app import models # - our specific functions and sequences, not generated by SQLAlchemy models.create_database_functions() # - ERASE (the truncation sql function has been defined above) if erase: truncate_database() # - Create all tables db.create_all() # - Insert initial roles and create super-admin user user_db_init() # - Insert some constant values (modalites, ...) sco_db_init() def truncate_database(): """Erase content of all tables (including users !) from the current database. """ # use a stored SQL function, see createtables.sql try: db.session.execute("SELECT truncate_tables('scodoc');") db.session.commit() except: db.session.rollback() raise # admin_role = Role.query.filter_by(name="SuperAdmin").first() # if admin_role: # admin = ( # User.query.join(UserRole) # .filter((UserRole.user_id == User.id) & (UserRole.role_id == admin_role.id)) # .first() # ) # else: # click.echo( # "Warning: user database not initialized !\n (use: flask user-db-init)" # ) # admin = None