Compare commits
24 Commits
editor
...
70883db5ad
Author | SHA1 | Date | |
---|---|---|---|
70883db5ad | |||
7cefb487da | |||
2e1b01ec9b | |||
a7a5a03991 | |||
b36c6bfd18 | |||
a613b0006b | |||
d4db8692e7 | |||
37ad36da31 | |||
d140f93d25 | |||
26a6248a61 | |||
9f8ea16974 | |||
bc5ec44145 | |||
ff5b19fa0b | |||
6c50be49c6 | |||
8bfe028e2c | |||
519394a656 | |||
9e1c9caec6 | |||
ea850c9ae2 | |||
591b868920 | |||
91dc93758a | |||
5d27baee08 | |||
1254cf3698 | |||
efab086057 | |||
06db47c597 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -149,4 +149,7 @@ ref-test/testing.py
|
|||||||
database/data/
|
database/data/
|
||||||
|
|
||||||
# Ignore Encryption Keyfile
|
# Ignore Encryption Keyfile
|
||||||
.encryption.key
|
.encryption.key
|
||||||
|
|
||||||
|
# Ignore Data Dir
|
||||||
|
**/data/*
|
@ -1,5 +1,8 @@
|
|||||||
version: '3.9'
|
version: '3.9'
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
data:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
nginx:
|
nginx:
|
||||||
container_name: reftest_server
|
container_name: reftest_server
|
||||||
@ -8,6 +11,7 @@ services:
|
|||||||
- ./certbot:/etc/letsencrypt:ro
|
- ./certbot:/etc/letsencrypt:ro
|
||||||
- ./nginx:/etc/nginx
|
- ./nginx:/etc/nginx
|
||||||
- ./src/html:/usr/share/nginx/html/
|
- ./src/html:/usr/share/nginx/html/
|
||||||
|
- ./ref-test/app/editor/static:/usr/share/nginx/html/admin/editor/static
|
||||||
- ./ref-test/app/admin/static:/usr/share/nginx/html/admin/static
|
- ./ref-test/app/admin/static:/usr/share/nginx/html/admin/static
|
||||||
- ./ref-test/app/quiz/static:/usr/share/nginx/html/quiz/static
|
- ./ref-test/app/quiz/static:/usr/share/nginx/html/quiz/static
|
||||||
- ./ref-test/app/root:/usr/share/nginx/html/root
|
- ./ref-test/app/root:/usr/share/nginx/html/root
|
||||||
@ -30,7 +34,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- 5000
|
- 5000
|
||||||
volumes:
|
volumes:
|
||||||
- ./ref-test/data:/ref-test/data
|
- data:/ref-test/data
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
- frontend
|
- frontend
|
||||||
|
@ -46,8 +46,6 @@ if [ ! -e "$data_path/lets-encrypt-x3-cross-signed.pem" ]; then
|
|||||||
echo "### Downloading lets-encrypt-x3-cross-signed.pem ..."
|
echo "### Downloading lets-encrypt-x3-cross-signed.pem ..."
|
||||||
wget -O $data_path/lets-encrypt-x3-cross-signed.pem \
|
wget -O $data_path/lets-encrypt-x3-cross-signed.pem \
|
||||||
"https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem"
|
"https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem"
|
||||||
docker compose run --rm --entrypoint "\
|
|
||||||
openssl dhparam -out /etc/letsencrypt/ssl-dhparams.pem 4096" certbot
|
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -79,7 +77,7 @@ esac
|
|||||||
if [ $staging != "0" ]; then staging_arg="--staging"; fi
|
if [ $staging != "0" ]; then staging_arg="--staging"; fi
|
||||||
|
|
||||||
docker compose run --rm --entrypoint "\
|
docker compose run --rm --entrypoint "\
|
||||||
certbot certonly --webroot -w /var/www/html \
|
certbot certonly --non-interactive --webroot -w /var/www/html \
|
||||||
$staging_arg \
|
$staging_arg \
|
||||||
$email_arg \
|
$email_arg \
|
||||||
$domain_args \
|
$domain_args \
|
||||||
|
@ -29,6 +29,11 @@ server {
|
|||||||
alias /usr/share/nginx/html/admin/static/;
|
alias /usr/share/nginx/html/admin/static/;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location ^~ /admin/editor/static/ {
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
alias /usr/share/nginx/html/admin/editor/static/;
|
||||||
|
}
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
include /etc/nginx/conf.d/proxy_headers.conf;
|
include /etc/nginx/conf.d/proxy_headers.conf;
|
||||||
proxy_pass http://reftest;
|
proxy_pass http://reftest;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
FROM python:3.10-slim
|
FROM python:3.10-slim
|
||||||
|
ARG DATA=./data/
|
||||||
|
ENV DATA=$DATA
|
||||||
WORKDIR /ref-test
|
WORKDIR /ref-test
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN pip install --upgrade pip && pip install -r requirements.txt
|
RUN pip install --upgrade pip && pip install -r requirements.txt
|
||||||
|
RUN chmod +x install.py && ./install.py
|
||||||
CMD [ "gunicorn", "-b", "0.0.0.0:5000", "-w", "5", "wsgi:app" ]
|
CMD [ "gunicorn", "-b", "0.0.0.0:5000", "-w", "5", "wsgi:app" ]
|
@ -1,5 +1,4 @@
|
|||||||
from .config import Development as Config
|
from .config import Production as Config
|
||||||
from .install import install_app
|
|
||||||
from .models import User
|
from .models import User
|
||||||
from .extensions import bootstrap, csrf, db, login_manager, mail
|
from .extensions import bootstrap, csrf, db, login_manager, mail
|
||||||
|
|
||||||
@ -53,7 +52,5 @@ def create_app():
|
|||||||
app.register_blueprint(views)
|
app.register_blueprint(views)
|
||||||
app.register_blueprint(quiz)
|
app.register_blueprint(quiz)
|
||||||
app.register_blueprint(editor, url_prefix='/admin/editor')
|
app.register_blueprint(editor, url_prefix='/admin/editor')
|
||||||
|
|
||||||
install_app(app)
|
|
||||||
|
|
||||||
return app
|
return app
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="form-container">
|
<div class="form-container">
|
||||||
<form name="form-update-password" class="form-display form-post" action="{{ url_for(request.endpoint, **request.view_args) }}" data-rel-success="{{ url_for('admin._login') }}">
|
<form name="form-update-password" class="form-display form-post" action="{{ url_for('admin._update_password', **request.view_args) }}" data-rel-success="{{ url_for('admin._login') }}">
|
||||||
{% include "admin/components/server-alerts.html" %}
|
{% include "admin/components/server-alerts.html" %}
|
||||||
<h2 class="form-heading">Update Password</h2>
|
<h2 class="form-heading">Update Password</h2>
|
||||||
{{ form.hidden_tag() }}
|
{{ form.hidden_tag() }}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{ entry.get_email() }}
|
{{ entry.get_email() }}
|
||||||
</li>
|
</li>
|
||||||
{% if entry.club %}
|
{% if entry.get_club() %}
|
||||||
<li class="list-group-item list-group-item-action">
|
<li class="list-group-item list-group-item-action">
|
||||||
<div class="d-flex w-100 justify-content-between">
|
<div class="d-flex w-100 justify-content-between">
|
||||||
<h5 class="mb-1">Club</h5>
|
<h5 class="mb-1">Club</h5>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{ entry.get_email() }}
|
{{ entry.get_email() }}
|
||||||
</li>
|
</li>
|
||||||
{% if entry.club %}
|
{% if entry.get_club() %}
|
||||||
<li class="list-group-item list-group-item-action">
|
<li class="list-group-item list-group-item-action">
|
||||||
<div class="d-flex w-100 justify-content-between">
|
<div class="d-flex w-100 justify-content-between">
|
||||||
<h5 class="mb-1">Club</h5>
|
<h5 class="mb-1">Club</h5>
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
{{ entry.get_surname() }}, {{ entry.get_first_name() }}
|
{{ entry.get_surname() }}, {{ entry.get_first_name() }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{% if entry.club %}
|
{% if entry.get_club() %}
|
||||||
{{ entry.get_club() }}
|
{{ entry.get_club() }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
@ -9,7 +9,7 @@ from flask import abort, Blueprint, jsonify, render_template, redirect, request,
|
|||||||
from flask.helpers import flash, url_for
|
from flask.helpers import flash, url_for
|
||||||
from flask_login import current_user, login_required
|
from flask_login import current_user, login_required
|
||||||
|
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime, timedelta
|
||||||
from json import loads
|
from json import loads
|
||||||
from os import path
|
from os import path
|
||||||
import secrets
|
import secrets
|
||||||
@ -91,7 +91,7 @@ def _register():
|
|||||||
flash(message=message, category='error')
|
flash(message=message, category='error')
|
||||||
return jsonify({'error': message}), 401
|
return jsonify({'error': message}), 401
|
||||||
return send_errors_to_client(form=form)
|
return send_errors_to_client(form=form)
|
||||||
return render_template('admin/auth/register.html', form=form)
|
return render_template('/admin/auth/register.html', form=form)
|
||||||
|
|
||||||
@admin.route('/reset/', methods=['GET','POST'])
|
@admin.route('/reset/', methods=['GET','POST'])
|
||||||
def _reset():
|
def _reset():
|
||||||
@ -117,7 +117,7 @@ def _reset():
|
|||||||
user.clear_reset_tokens()
|
user.clear_reset_tokens()
|
||||||
if request.args.get('verification') == verification_token:
|
if request.args.get('verification') == verification_token:
|
||||||
form = UpdatePassword()
|
form = UpdatePassword()
|
||||||
return render_template('/auth/update_password.html', form=form, user=user.id)
|
return render_template('/admin/auth/update-password.html', form=form, user=user.id)
|
||||||
flash('The verification of your password reset request failed and the token has been invalidated. Please make a new reset password request.', 'error')
|
flash('The verification of your password reset request failed and the token has been invalidated. Please make a new reset password request.', 'error')
|
||||||
|
|
||||||
return render_template('/admin/auth/reset.html', form=form)
|
return render_template('/admin/auth/reset.html', form=form)
|
||||||
@ -258,6 +258,8 @@ def _tests(filter:str=None):
|
|||||||
if filter not in ['create','active','scheduled','expired','all']: return redirect(url_for('admin._tests', filter='active'))
|
if filter not in ['create','active','scheduled','expired','all']: return redirect(url_for('admin._tests', filter='active'))
|
||||||
if filter == 'create':
|
if filter == 'create':
|
||||||
form = CreateTest()
|
form = CreateTest()
|
||||||
|
form.start_date.default = datetime.now()
|
||||||
|
form.expiry_date.default = date.today() + timedelta(days=1)
|
||||||
form.time_limit.choices = get_time_options()
|
form.time_limit.choices = get_time_options()
|
||||||
form.dataset.choices = get_dataset_choices()
|
form.dataset.choices = get_dataset_choices()
|
||||||
form.time_limit.default='none'
|
form.time_limit.default='none'
|
||||||
|
@ -5,7 +5,7 @@ load_dotenv('../.env')
|
|||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
APP_HOST = '0.0.0.0'
|
APP_HOST = '0.0.0.0'
|
||||||
DATA = os.getenv('DATA')
|
DATA = './data/'
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
TESTING = False
|
TESTING = False
|
||||||
SECRET_KEY = os.getenv('SECRET_KEY')
|
SECRET_KEY = os.getenv('SECRET_KEY')
|
||||||
@ -15,16 +15,16 @@ class Config(object):
|
|||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||||
|
|
||||||
MAIL_SERVER = os.getenv('MAIL_SERVER')
|
MAIL_SERVER = os.getenv('MAIL_SERVER')
|
||||||
MAIL_PORT = int(os.getenv('MAIL_PORT'))
|
MAIL_PORT = int(os.getenv('MAIL_PORT') or 25)
|
||||||
MAIL_USE_TLS = False
|
MAIL_USE_TLS = False
|
||||||
MAIL_USE_SSL = False
|
MAIL_USE_SSL = False
|
||||||
MAIL_DEBUG = False
|
MAIL_DEBUG = False
|
||||||
MAIL_USERNAME = os.getenv('MAIL_USERNAME')
|
MAIL_USERNAME = os.getenv('MAIL_USERNAME')
|
||||||
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
|
MAIL_PASSWORD = os.getenv('MAIL_PASSWORD')
|
||||||
MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER')
|
MAIL_DEFAULT_SENDER = os.getenv('MAIL_DEFAULT_SENDER')
|
||||||
MAIL_MAX_EMAILS = int(os.getenv('MAIL_MAX_EMAILS'))
|
MAIL_MAX_EMAILS = int(os.getenv('MAIL_MAX_EMAILS') or 25)
|
||||||
MAIL_SUPPRESS_SEND = False
|
MAIL_SUPPRESS_SEND = False
|
||||||
MAIL_ASCII_ATTACHMENTS = bool(os.getenv('MAIL_ASCII_ATTACHMENTS'))
|
MAIL_ASCII_ATTACHMENTS = bool(os.getenv('MAIL_ASCII_ATTACHMENTS') or True)
|
||||||
|
|
||||||
class Production(Config):
|
class Production(Config):
|
||||||
pass
|
pass
|
||||||
|
@ -6,8 +6,6 @@ from wtforms import BooleanField, IntegerField, PasswordField, SelectField, Stri
|
|||||||
from wtforms.fields import DateTimeLocalField
|
from wtforms.fields import DateTimeLocalField
|
||||||
from wtforms.validators import InputRequired, Email, EqualTo, Length, Optional
|
from wtforms.validators import InputRequired, Email, EqualTo, Length, Optional
|
||||||
|
|
||||||
from datetime import date, datetime, timedelta
|
|
||||||
|
|
||||||
class Login(FlaskForm):
|
class Login(FlaskForm):
|
||||||
username = StringField('Username', validators=[InputRequired(), Length(min=4, max=15)])
|
username = StringField('Username', validators=[InputRequired(), Length(min=4, max=15)])
|
||||||
password = PasswordField('Password', validators=[InputRequired(), Length(min=6, max=30, message='The password must be between 6 and 20 characters long.')])
|
password = PasswordField('Password', validators=[InputRequired(), Length(min=6, max=30, message='The password must be between 6 and 20 characters long.')])
|
||||||
@ -51,8 +49,8 @@ class UpdateAccount(FlaskForm):
|
|||||||
password_reenter = PasswordField('Re-Enter New Password', validators=[EqualTo('password', message='Passwords do not match.')])
|
password_reenter = PasswordField('Re-Enter New Password', validators=[EqualTo('password', message='Passwords do not match.')])
|
||||||
|
|
||||||
class CreateTest(FlaskForm):
|
class CreateTest(FlaskForm):
|
||||||
start_date = DateTimeLocalField('Start Date', format='%Y-%m-%dT%H:%M', validators=[InputRequired()], default = datetime.now() )
|
start_date = DateTimeLocalField('Start Date', format='%Y-%m-%dT%H:%M', validators=[InputRequired()] )
|
||||||
expiry_date = DateTimeLocalField('Expiry Date', format='%Y-%m-%dT%H:%M', validators=[InputRequired()], default = date.today() + timedelta(days=1) )
|
expiry_date = DateTimeLocalField('Expiry Date', format='%Y-%m-%dT%H:%M', validators=[InputRequired()] )
|
||||||
time_limit = SelectField('Time Limit')
|
time_limit = SelectField('Time Limit')
|
||||||
dataset = SelectField('Question Dataset')
|
dataset = SelectField('Question Dataset')
|
||||||
|
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
from .extensions import db
|
|
||||||
from .tools.data import save
|
|
||||||
from .tools.logs import write
|
|
||||||
|
|
||||||
from sqlalchemy_utils import create_database, database_exists
|
|
||||||
|
|
||||||
from cryptography.fernet import Fernet
|
|
||||||
from os import mkdir, path
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
def install_app(app):
|
|
||||||
with app.app_context():
|
|
||||||
data = Path(app.config.get('DATA'))
|
|
||||||
database_uri = app.config.get('SQLALCHEMY_DATABASE_URI')
|
|
||||||
if not path.isdir(f'./{data}'): mkdir(f'./{data}')
|
|
||||||
if not path.isdir(f'./{data}/questions'): mkdir(f'./{data}/questions')
|
|
||||||
if not path.isfile(f'./{data}/.gitignore'):
|
|
||||||
with open(f'./{data}/.gitignore', 'a+') as file: file.write(f'*')
|
|
||||||
if not path.isfile(f'./{data}/config.json'): save({}, 'config.json')
|
|
||||||
if not path.isdir(f'./{data}/logs'): mkdir(f'./{data}/logs')
|
|
||||||
if not path.isfile(f'./{data}/logs/users.log'): write('users.log', 'Log file created.')
|
|
||||||
if not path.isfile(f'./{data}/logs/system.log'): write('system.log', 'Log file created.')
|
|
||||||
if not path.isfile(f'./{data}/logs/tests.log'): write('tests.log', 'Log file created.')
|
|
||||||
if not database_exists(database_uri):
|
|
||||||
create_database(database_uri)
|
|
||||||
write('system.log', 'No database found. Creating a new database.')
|
|
||||||
from .models import Entry, Dataset, Test, User
|
|
||||||
db.create_all()
|
|
||||||
write('system.log', 'Creating database schema.')
|
|
||||||
if not path.isfile(f'./{data}/.encryption.key'):
|
|
||||||
write('system.log', 'No encryption key found. Generating new encryption key.')
|
|
||||||
with open(f'./{data}/.encryption.key', 'wb') as key_file:
|
|
||||||
key = Fernet.generate_key()
|
|
||||||
key_file.write(key)
|
|
@ -102,7 +102,7 @@ class Dataset(db.Model):
|
|||||||
with open(file_path, 'w') as file:
|
with open(file_path, 'w') as file:
|
||||||
dump(data, file, indent=2)
|
dump(data, file, indent=2)
|
||||||
write('system.log', f'Dataset {self.id} edited by {current_user.get_username()}.')
|
write('system.log', f'Dataset {self.id} edited by {current_user.get_username()}.')
|
||||||
flash(f'Dataset {self.name} successfully edited.', 'success')
|
flash(f'Dataset {self.get_name()} successfully edited.', 'success')
|
||||||
db.session.add(self)
|
db.session.add(self)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return True, 'Dataset successfully edited.'
|
return True, 'Dataset successfully edited.'
|
@ -146,7 +146,7 @@ $("#btn-start-quiz").click(function(event){
|
|||||||
data: JSON.stringify({'id': id}),
|
data: JSON.stringify({'id': id}),
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
$(this).fadeOut();
|
$("#btn-start-quiz").fadeOut();
|
||||||
$(".btn-quiz-return").fadeIn();
|
$(".btn-quiz-return").fadeIn();
|
||||||
$(".quiz-console").fadeIn();
|
$(".quiz-console").fadeIn();
|
||||||
$("#quiz-settings").fadeOut();
|
$("#quiz-settings").fadeOut();
|
||||||
|
@ -123,7 +123,7 @@
|
|||||||
<div class="container question-container quiz-start-text">
|
<div class="container question-container quiz-start-text">
|
||||||
<h4 class="question-title">Sample Question</h4>
|
<h4 class="question-title">Sample Question</h4>
|
||||||
<p class="question-header">
|
<p class="question-header">
|
||||||
Korfball is a mixed-sex, controlled-contact, indoor, invasion ball sport. The sport originated in the Netherlands. It is a mixed-sex team sport. Its governing body is the International Korball Federation. There are numerous korfball leagues and associations around the world. A korfball match is officiated by a referee.
|
Korfball is a mixed-sex, controlled-contact, indoor, invasion, team ball sport. The sport originated in the Netherlands. Its governing body is the International Korball Federation. There are numerous korfball leagues and associations around the world. A korfball match is officiated by a referee.
|
||||||
</p>
|
</p>
|
||||||
<p class="question-text">
|
<p class="question-text">
|
||||||
In order to be a referee, what do you need to know?
|
In order to be a referee, what do you need to know?
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<strong class="results-details">Email Address</strong>: {{ entry.get_email() }} <br />
|
<strong class="results-details">Email Address</strong>: {{ entry.get_email() }} <br />
|
||||||
|
|
||||||
{% if entry.club %}
|
{% if entry.get_club() %}
|
||||||
<strong class="results-details">Club</strong>: {{ entry.get_club() }} <br />
|
<strong class="results-details">Club</strong>: {{ entry.get_club() }} <br />
|
||||||
{% endif%}
|
{% endif%}
|
||||||
|
|
||||||
|
1
ref-test/data/.gitignore
vendored
1
ref-test/data/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
*
|
|
34
ref-test/install.py
Executable file
34
ref-test/install.py
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
from main import app
|
||||||
|
from app.extensions import db
|
||||||
|
from app.tools.data import save
|
||||||
|
from app.tools.logs import write
|
||||||
|
from sqlalchemy_utils import create_database, database_exists
|
||||||
|
from cryptography.fernet import Fernet
|
||||||
|
from os import mkdir, path
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
data = Path(app.config.get('DATA'))
|
||||||
|
database_uri = app.config.get('SQLALCHEMY_DATABASE_URI')
|
||||||
|
|
||||||
|
with app.app_context():
|
||||||
|
if not path.isdir(f'./{data}'): mkdir(f'./{data}')
|
||||||
|
if not path.isdir(f'./{data}/questions'): mkdir(f'./{data}/questions')
|
||||||
|
if not path.isfile(f'./{data}/.gitignore'):
|
||||||
|
with open(f'./{data}/.gitignore', 'w') as file: file.write(f'*')
|
||||||
|
if not path.isfile(f'./{data}/config.json'): save({}, 'config.json')
|
||||||
|
if not path.isdir(f'./{data}/logs'): mkdir(f'./{data}/logs')
|
||||||
|
if not path.isfile(f'./{data}/logs/users.log'): write('users.log', 'Log file created.')
|
||||||
|
if not path.isfile(f'./{data}/logs/system.log'): write('system.log', 'Log file created.')
|
||||||
|
if not path.isfile(f'./{data}/logs/tests.log'): write('tests.log', 'Log file created.')
|
||||||
|
if not database_exists(database_uri):
|
||||||
|
create_database(database_uri)
|
||||||
|
write('system.log', 'No database found. Creating a new database.')
|
||||||
|
from app.models import *
|
||||||
|
db.create_all()
|
||||||
|
write('system.log', 'Creating database schema.')
|
||||||
|
if not path.isfile(f'./{data}/.encryption.key'):
|
||||||
|
write('system.log', 'No encryption key found. Generating new encryption key.')
|
||||||
|
with open(f'./{data}/.encryption.key', 'wb') as key_file:
|
||||||
|
key = Fernet.generate_key()
|
||||||
|
key_file.write(key)
|
Reference in New Issue
Block a user