flask server
This commit is contained in:
parent
5acb2992ce
commit
0a71a6c840
54 changed files with 5876 additions and 0 deletions
0
server/flask/application/backend/data/__init__.py
Normal file
0
server/flask/application/backend/data/__init__.py
Normal file
33
server/flask/application/backend/data/dao_file_metadata.py
Normal file
33
server/flask/application/backend/data/dao_file_metadata.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
from .db import get_db
|
||||
from .data_models import DataError
|
||||
from sqlite3 import IntegrityError
|
||||
|
||||
_INSER_METADATA_SQL = "INSERT INTO file_metadata(file_key,metadata) "\
|
||||
"VALUES(:file_key, :metadata)"
|
||||
_DELETE_METADATA_SQL = "DELETE FROM file_metadata WHERE file_key=:file_key"
|
||||
def insert_metadata(metadata: dict):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
|
||||
delete_params = map(lambda key: {'file_key':key}, metadata.keys())
|
||||
delete_params = list(delete_params)
|
||||
db_cursor.executemany(_DELETE_METADATA_SQL, delete_params)
|
||||
|
||||
insert_params = map(lambda item: {'file_key':item[0], 'metadata':item[1]}, metadata.items())
|
||||
insert_params = list(insert_params)
|
||||
|
||||
|
||||
db_cursor.executemany(_INSER_METADATA_SQL, insert_params)
|
||||
db.commit()
|
||||
|
||||
def get_metadata(file_key: str):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT metadata FROM file_metadata WHERE file_key=:file_key",{"file_key":file_key})
|
||||
rows = db_cursor.fetchone()
|
||||
|
||||
if (rows is None):
|
||||
return dict()
|
||||
|
||||
converted_tuple_array = map(lambda metadata: (file_key, metadata), rows)
|
||||
return dict(converted_tuple_array)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
from .db import get_db
|
||||
from .data_models import DataError
|
||||
from sqlite3 import IntegrityError
|
||||
|
||||
_INSER_METADATA_SQL = "INSERT INTO file_metadata_of_user(user_id,file_key,metadata) "\
|
||||
"VALUES(:user_id, :file_key, :metadata)"
|
||||
_DELETE_METADATA_SQL = "DELETE FROM file_metadata_of_user WHERE user_id=:user_id AND file_key=:file_key"
|
||||
def insert_metadata(user_id: str, metadata: dict):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
|
||||
delete_params = map(lambda key: {'user_id':user_id, 'file_key':key}, metadata.keys())
|
||||
delete_params = list(delete_params)
|
||||
db_cursor.executemany(_DELETE_METADATA_SQL, delete_params)
|
||||
|
||||
insert_params = map(lambda item: {'user_id':user_id, 'file_key':item[0], 'metadata':item[1]}, metadata.items())
|
||||
insert_params = list(insert_params)
|
||||
|
||||
|
||||
db_cursor.executemany(_INSER_METADATA_SQL, insert_params)
|
||||
db.commit()
|
||||
|
||||
def get_metadata(user_id: str):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT file_key, metadata FROM file_metadata_of_user WHERE user_id=:user_id",{"user_id":user_id})
|
||||
rows = db_cursor.fetchall()
|
||||
|
||||
converted_tuple_array = map(lambda row: (row['file_key'], row['metadata']), rows)
|
||||
return dict(converted_tuple_array)
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
from .db import get_db
|
||||
from .data_models import DataError
|
||||
from sqlite3 import IntegrityError
|
||||
|
||||
def is_valid_token(token):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT COUNT(*) FROM registration_token where token = :token", {"token": token})
|
||||
rows = db_cursor.fetchone()
|
||||
|
||||
return rows[0] == 1
|
||||
|
||||
def insert_token(token):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
try:
|
||||
db_cursor.execute("INSERT INTO registration_token(token) VALUES(:token)", {"token": token})
|
||||
except IntegrityError as e:
|
||||
return DataError.REGISTRATION_CODE_ALREADY_EXISTS
|
||||
db.commit()
|
||||
|
||||
def delete_token(token):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("DELETE FROM registration_token WHERE token=:token", {"token": token})
|
||||
db.commit()
|
||||
|
||||
def get_tokens():
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT * FROM registration_token")
|
||||
rows = db_cursor.fetchall()
|
||||
|
||||
return list(map(lambda row: row['token'],rows))
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
from .db import get_db
|
||||
import time
|
||||
|
||||
_DELETE_EXPIRED_SESSION_SQL = "DELETE FROM reset_password_token where expires_at <= :time"
|
||||
def _delete_expired_tokens(db):
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute(_DELETE_EXPIRED_SESSION_SQL, {"time": time.time()})
|
||||
db.commit()
|
||||
|
||||
def is_valid_token(token, username):
|
||||
db = get_db()
|
||||
_delete_expired_tokens(db)
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT COUNT(*) FROM reset_password_token where token = :token AND username = :username", {"token": token, "username": username})
|
||||
rows = db_cursor.fetchone()
|
||||
|
||||
return rows[0] == 1
|
||||
|
||||
def insert_token(token, username, expires_at):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
params = {
|
||||
"token": token,
|
||||
"username": username,
|
||||
"expires_at": expires_at
|
||||
}
|
||||
db_cursor.execute("INSERT INTO reset_password_token(token, username, expires_at) VALUES(:token, :username, :expires_at)", params)
|
||||
db.commit()
|
||||
|
||||
def delete_tokens(username):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("DELETE FROM reset_password_token WHERE username=:username", {"username": username})
|
||||
db.commit()
|
||||
78
server/flask/application/backend/data/dao_session.py
Normal file
78
server/flask/application/backend/data/dao_session.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
from .db import get_db
|
||||
from .data_models import Session
|
||||
import time
|
||||
|
||||
_DELETE_EXPIRED_SESSION_SQL = "DELETE FROM session where refresh_expires_at <= :time"
|
||||
def _delete_expired_tokens(db):
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute(_DELETE_EXPIRED_SESSION_SQL, {"time": time.time()})
|
||||
db.commit()
|
||||
|
||||
_GET_USER_FOR_ACCESS_TOKEN_SQL = "SELECT user_id FROM session where access_token = :token and access_expires_at >= :time"
|
||||
def get_user_for_token(access_token: str):
|
||||
db = get_db()
|
||||
_delete_expired_tokens(db)
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute(_GET_USER_FOR_ACCESS_TOKEN_SQL, {"token": access_token, "time": time.time()})
|
||||
rows = db_cursor.fetchall()
|
||||
|
||||
if (len(rows) == 1):
|
||||
return rows[0][0]
|
||||
return None
|
||||
|
||||
_INSER_SESSION_SQL = "INSERT INTO session(user_id, access_token, refresh_token, access_expires_at, refresh_expires_at)"\
|
||||
"VALUES(:user_id, :access_token, :refresh_token, :access_expires_at, :refresh_expires_at)"
|
||||
|
||||
def _session_insert(db_cursor, session: Session):
|
||||
params = {
|
||||
"user_id": session.user_id,
|
||||
"access_token": session.access_token,
|
||||
"refresh_token": session.refresh_token,
|
||||
"access_expires_at": session.access_expires_at,
|
||||
"refresh_expires_at": session.refresh_expires_at,
|
||||
}
|
||||
db_cursor.execute(_INSER_SESSION_SQL, params)
|
||||
|
||||
def insert_user_session(session: Session):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
_session_insert(db_cursor, session)
|
||||
db.commit()
|
||||
|
||||
def delete_user_session(access_token: str):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("DELETE FROM session WHERE access_token = :token", {"token": access_token})
|
||||
db.commit()
|
||||
|
||||
def delete_all_user_session_by_user_id(user_id: int):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("DELETE FROM session WHERE user_id = :id", {"id": user_id})
|
||||
db.commit()
|
||||
|
||||
def create_new_single_session(session: Session):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("DELETE FROM session where user_id = :id", {"id": session.user_id})
|
||||
_session_insert(db_cursor, session)
|
||||
db.commit()
|
||||
|
||||
def get_user_for_refresh_token(refresh_token: str):
|
||||
db = get_db()
|
||||
_delete_expired_tokens(db)
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT user_id FROM session where refresh_token = :token", {"token": refresh_token})
|
||||
rows = db_cursor.fetchall()
|
||||
|
||||
if (len(rows) == 1):
|
||||
return rows[0][0]
|
||||
return None
|
||||
|
||||
def swap_refresh_session(refresh_token: str, session: Session):
|
||||
db = get_db()
|
||||
_delete_expired_tokens(db)
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("DELETE FROM session WHERE refresh_token = :token", {"token": refresh_token})
|
||||
_session_insert(db_cursor, session)
|
||||
db.commit()
|
||||
107
server/flask/application/backend/data/dao_users.py
Normal file
107
server/flask/application/backend/data/dao_users.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
from .data_models import User
|
||||
from .data_models import RegisteringUser
|
||||
from .data_models import DataError
|
||||
from .db import get_db
|
||||
from sqlite3 import IntegrityError
|
||||
from passlib.hash import sha256_crypt
|
||||
|
||||
def _user_from_row(row):
|
||||
return User(
|
||||
id = row['id'],
|
||||
name = row['username'],
|
||||
otp_secret = row['otp_secret'],
|
||||
was_otp_verified = row['was_otp_verified'] != 0,
|
||||
privileged = row['privileged'] != 0,
|
||||
)
|
||||
|
||||
def get_user_by_id(user_id: int):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT * FROM user where id = :user_id", {"user_id": user_id})
|
||||
row = db_cursor.fetchone()
|
||||
|
||||
if (row is None):
|
||||
return None
|
||||
|
||||
return _user_from_row(row)
|
||||
|
||||
def get_user_by_name(username: str):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT * FROM user where username = :name", {"name": username})
|
||||
row = db_cursor.fetchone()
|
||||
|
||||
if (row is None):
|
||||
return None
|
||||
|
||||
return _user_from_row(row)
|
||||
|
||||
def get_user_by_name_and_password(user_name: str, password: str):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT * FROM user where username = :user_name", {"user_name": user_name})
|
||||
row = db_cursor.fetchone()
|
||||
|
||||
if (row is None):
|
||||
sha256_crypt.hash('') # do hashing even if no user is found
|
||||
return None
|
||||
|
||||
is_password_wrong = not sha256_crypt.verify(password, row['password'] or '')
|
||||
if is_password_wrong:
|
||||
return None
|
||||
|
||||
return _user_from_row(row)
|
||||
|
||||
def get_users():
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute("SELECT * FROM user")
|
||||
rows = db_cursor.fetchall()
|
||||
|
||||
return map(_user_from_row, rows)
|
||||
|
||||
_INSER_USER_SQL = "INSERT INTO user(username, password, otp_secret, privileged, was_otp_verified)"\
|
||||
"VALUES(:name, :pass, :otp, :privileged, :otp_verified)"
|
||||
def insert_user(user: RegisteringUser):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
hashed_password = sha256_crypt.hash(user.password)
|
||||
|
||||
params = {
|
||||
"name": user.name,
|
||||
"pass": hashed_password,
|
||||
"otp": user.otp_secret,
|
||||
"privileged": 1 if user.privileged else 0,
|
||||
"otp_verified": 1 if user.was_otp_verified else 0,
|
||||
}
|
||||
try:
|
||||
db_cursor.execute(_INSER_USER_SQL, params)
|
||||
except IntegrityError as e:
|
||||
return DataError.USER_NAME_NOT_VALID
|
||||
db.commit()
|
||||
return db_cursor.lastrowid
|
||||
|
||||
def update_user_privilige(user_id: int, privileged: bool):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute('UPDATE user SET privileged = :privileged WHERE id=:id',{'id':user_id, 'privileged': privileged})
|
||||
db.commit()
|
||||
|
||||
def update_user_otp_verification(user_id: int, was_otp_verified: bool):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute('UPDATE user SET was_otp_verified = :otp_verified WHERE id=:id',{'id':user_id, 'otp_verified': was_otp_verified})
|
||||
db.commit()
|
||||
|
||||
def update_user_password(user_id: int, new_password: str):
|
||||
hashed_password = sha256_crypt.hash(new_password)
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute('UPDATE user SET password = :pass WHERE id=:id',{'id':user_id, 'pass': hashed_password})
|
||||
db.commit()
|
||||
|
||||
def delete_user_by_id(user_id: int):
|
||||
db = get_db()
|
||||
db_cursor = db.cursor()
|
||||
db_cursor.execute('DELETE FROM user WHERE id=:id',{'id':user_id})
|
||||
db.commit()
|
||||
106
server/flask/application/backend/data/data_models.py
Normal file
106
server/flask/application/backend/data/data_models.py
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
from enum import Enum
|
||||
from enum import IntEnum
|
||||
|
||||
class Session:
|
||||
def __init__(self, user_id, access_token, refresh_token, access_expires_at, refresh_expires_at):
|
||||
self.user_id = user_id
|
||||
self.access_token = access_token
|
||||
self.refresh_token = refresh_token
|
||||
self.access_expires_at = access_expires_at
|
||||
self.refresh_expires_at = refresh_expires_at
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Session):
|
||||
return False
|
||||
return self.user_id == other.user_id \
|
||||
and self.access_token == other.access_token \
|
||||
and self.refresh_token == other.refresh_token \
|
||||
and self.access_expires_at == other.access_expires_at \
|
||||
and self.refresh_expires_at == other.refresh_expires_at \
|
||||
|
||||
def __str__(self):
|
||||
return 'Session(user_id={},access_token={},refresh_token={},access_expires_at={},refresh_expires_at={})'.format(self.user_id, self.access_token, self.refresh_token, self.access_expires_at, self.refresh_expires_at)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class RegisteringUser:
|
||||
def __init__(self, name, password, otp_secret, privileged = False, was_otp_verified = False):
|
||||
self.name = name
|
||||
self.password = password
|
||||
self.otp_secret = otp_secret
|
||||
self.privileged = privileged
|
||||
self.was_otp_verified = was_otp_verified
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, User):
|
||||
return False
|
||||
|
||||
return self.name == other.name \
|
||||
and self.password == other.password \
|
||||
and self.otp_secret == other.otp_secret \
|
||||
and self.privileged == other.privileged \
|
||||
and self.was_otp_verified == other.was_otp_verified \
|
||||
|
||||
def __str__(self):
|
||||
return 'User(name={},pass={},otp={},privileged={},otp_active={})'\
|
||||
.format(self.name, self.password, self.otp_secret, self.privileged, self.was_otp_verified)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class User:
|
||||
def __init__(self, id, name, otp_secret, privileged, was_otp_verified):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.otp_secret = otp_secret
|
||||
self.privileged = privileged
|
||||
self.was_otp_verified = was_otp_verified
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, User):
|
||||
return False
|
||||
|
||||
return self.id == other.id \
|
||||
and self.name == other.name \
|
||||
and self.otp_secret == other.otp_secret \
|
||||
and self.privileged == other.privileged \
|
||||
and self.was_otp_verified == other.was_otp_verified \
|
||||
|
||||
def __str__(self):
|
||||
return 'User(id={},name={},otp={},privileged={},otp_active={})'\
|
||||
.format(self.id, self.name, self.otp_secret, self.privileged, self.was_otp_verified)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
class DataError(Enum):
|
||||
USER_NAME_NOT_VALID = 1
|
||||
REGISTRATION_CODE_ALREADY_EXISTS = 2
|
||||
|
||||
class ResponseCode(IntEnum):
|
||||
SUCCESS_FOUND_USER = 200
|
||||
SUCCESS_SAVED_PASSWORD = 201
|
||||
SUCCESS_SAVED_USER_FILE_METADATA = 202
|
||||
SUCCESS_SAVED_FILE_METADATA = 203
|
||||
SUCCESS_SAVED_REGISTRATION_TOKEN = 205
|
||||
SUCCESS_DELETED_USER = 206
|
||||
SUCCESS_RESET_OTP_VERIFICATION = 207
|
||||
SUCCESS_SAVED_RESET_PASSWORD_TOKEN = 208
|
||||
SUCCESS_DELETED_TOKEN = 209
|
||||
|
||||
|
||||
ALREADY_TAKEN_USERNAME = 411
|
||||
NOT_FOUND_USER = 412
|
||||
INVALID_USERNAME_TO_EDIT = 413
|
||||
CANT_SAVE_USER_FILE_METADATA = 414
|
||||
CANT_SAVE_FILE_METADATA = 415
|
||||
INVALID_FILE_KEY = 416
|
||||
INVALID_PASSWORD = 421
|
||||
INVALID_NEW_PASSWORD = 422
|
||||
UNKNOWN_REGISTRATION_TOKEN = 430
|
||||
INVALID_OTP = 431
|
||||
INVALID_REFRESH_TOKEN = 450
|
||||
INVALID_RESET_PASSWORD_TOKEN = 459
|
||||
INVALID_REGISTRATION_TOKEN = 460
|
||||
UNKNOWN_RESET_PASSWORD_TOKEN = 461
|
||||
82
server/flask/application/backend/data/db.py
Normal file
82
server/flask/application/backend/data/db.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import sqlite3
|
||||
from os import path
|
||||
import argparse
|
||||
from flask import current_app, g
|
||||
from passlib.hash import sha256_crypt
|
||||
|
||||
default_database_name = "sqlitedb"
|
||||
|
||||
def get_db():
|
||||
current_app.config.get('DATABASE_PATH')
|
||||
if 'db' not in g:
|
||||
db_path = current_app.config.get('DATABASE_PATH')
|
||||
if (db_path is None):
|
||||
db_path = path.join(current_app.instance_path, current_app.config['DATABASE_NAME'])
|
||||
g.db = sqlite3.connect(db_path, detect_types=sqlite3.PARSE_DECLTYPES)
|
||||
g.db.row_factory = sqlite3.Row
|
||||
|
||||
return g.db
|
||||
|
||||
def close_db(e=None):
|
||||
db = g.pop('db', None)
|
||||
|
||||
if db is not None:
|
||||
db.close()
|
||||
|
||||
def init_db(db_path = None, schema_path = None):
|
||||
if db_path is None:
|
||||
db = get_db()
|
||||
else:
|
||||
db = sqlite3.connect(db_path, detect_types=sqlite3.PARSE_DECLTYPES)
|
||||
|
||||
if schema_path is None:
|
||||
with current_app.open_resource('data/schema.sql') as f:
|
||||
script = f.read().decode('UTF-8')
|
||||
else:
|
||||
with open(schema_path, "r") as f:
|
||||
script = f.read()
|
||||
|
||||
db.executescript(script)
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
def init_app(app):
|
||||
app.teardown_appcontext(close_db)
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="DB Init ArgumentParser", formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument("-u", "--username", type=str, help="username of adming user", required=True)
|
||||
parser.add_argument("-p", "--password", type=str, help="password of adming user", required=True)
|
||||
parser.add_argument("-s", "--otp-secret", type=str, help="otp secret of admin user, python pyotp.random_base32()", required=False)
|
||||
args = parser.parse_args()
|
||||
config = vars(args)
|
||||
username = config['username']
|
||||
password = config['password']
|
||||
otp_secret = config['otp_secret']
|
||||
if (otp_secret is None):
|
||||
import pyotp
|
||||
otp_secret = pyotp.random_base32()
|
||||
|
||||
db_path = path.join('/server/instance/', default_database_name)
|
||||
if path.exists(db_path):
|
||||
print('Database already exists at {}. Will NOT override, if necessary first delete first then restart initialization!'.format(db_path))
|
||||
exit(1)
|
||||
schema_path = path.join(path.dirname(__file__), 'schema.sql')
|
||||
init_db(db_path = db_path, schema_path = schema_path)
|
||||
db = sqlite3.connect(db_path, detect_types=sqlite3.PARSE_DECLTYPES)
|
||||
db.row_factory = sqlite3.Row
|
||||
db_cursor = db.cursor()
|
||||
|
||||
hashed_password = sha256_crypt.hash(password)
|
||||
sql = "INSERT INTO user(username, password, otp_secret, privileged, was_otp_verified)"\
|
||||
"VALUES(:name, :pass, :otp, :privileged, :otp_verified)"
|
||||
params = {
|
||||
"name": username,
|
||||
"pass": hashed_password,
|
||||
"otp": otp_secret,
|
||||
"privileged": True,
|
||||
"otp_verified": False,
|
||||
}
|
||||
db_cursor.execute(sql, params)
|
||||
db.commit()
|
||||
db.close()
|
||||
47
server/flask/application/backend/data/schema.sql
Normal file
47
server/flask/application/backend/data/schema.sql
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
DROP TABLE IF EXISTS user;
|
||||
DROP TABLE IF EXISTS registration_token;
|
||||
DROP TABLE IF EXISTS reset_password_token;
|
||||
DROP TABLE IF EXISTS session;
|
||||
DROP TABLE IF EXISTS file_metadata_of_user;
|
||||
|
||||
CREATE TABLE user (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
otp_secret TEXT NOT NULL,
|
||||
privileged INTEGER NOT NULL,
|
||||
was_otp_verified INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE registration_token (
|
||||
token TEXT PRIMARY KEY NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE reset_password_token (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
token TEXT NOT NULL,
|
||||
username TEXT NOT NULL,
|
||||
expires_at INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE session (
|
||||
user_id INTEGER NOT NULL,
|
||||
access_token TEXT NOT NULL,
|
||||
refresh_token TEXT NOT NULL,
|
||||
access_expires_at INTEGER NOT NULL,
|
||||
refresh_expires_at INTEGER NOT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES user (id)
|
||||
);
|
||||
|
||||
CREATE TABLE file_metadata_of_user (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
file_key TEXT NOT NULL,
|
||||
metadata TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE file_metadata (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
file_key TEXT NOT NULL,
|
||||
metadata TEXT NOT NULL
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue