Skip to content

Commit

Permalink
Added option to disable registration (Fixes #27)
Browse files Browse the repository at this point in the history
  • Loading branch information
Casvt committed Nov 13, 2023
1 parent 8dbc36d commit a4a3c17
Show file tree
Hide file tree
Showing 10 changed files with 482 additions and 31 deletions.
4 changes: 4 additions & 0 deletions backend/custom_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,7 @@ class APIKeyExpired(CustomException):

def __init__(self, e=None) -> None:
return

class NewAccountsNotAllowed(CustomException):
"""It's not allowed to create a new account"""
api_response = {'error': 'NewAccountsNotAllowed', 'result': {}, 'code': 403}
43 changes: 31 additions & 12 deletions backend/db.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#-*- coding: utf-8 -*-

from datetime import datetime
import logging
from datetime import datetime
from sqlite3 import Connection, ProgrammingError, Row
from threading import current_thread, main_thread
from time import time
Expand Down Expand Up @@ -219,7 +219,26 @@ def migrate_db(current_db_version: int) -> None:

if current_db_version == 7:
# V7 -> V8
from backend.settings import _format_setting, default_settings
from backend.users import register_user

cursor.executescript("""
DROP TABLE config;
CREATE TABLE IF NOT EXISTS config(
key VARCHAR(255) PRIMARY KEY,
value BLOB NOT NULL
);
"""
)
cursor.executemany("""
INSERT OR IGNORE INTO config(key, value)
VALUES (?, ?);
""",
map(
lambda kv: (kv[0], _format_setting(*kv)),
default_settings.items()
)
)

cursor.executescript("""
ALTER TABLE users
Expand All @@ -243,6 +262,8 @@ def migrate_db(current_db_version: int) -> None:
def setup_db() -> None:
"""Setup the database
"""
from backend.settings import (_format_setting, default_settings, get_setting,
set_setting)
cursor = get_db()
cursor.execute("PRAGMA journal_mode = wal;")

Expand Down Expand Up @@ -314,26 +335,24 @@ def setup_db() -> None:
);
CREATE TABLE IF NOT EXISTS config(
key VARCHAR(255) PRIMARY KEY,
value TEXT NOT NULL
value BLOB NOT NULL
);
""")

cursor.execute("""
cursor.executemany("""
INSERT OR IGNORE INTO config(key, value)
VALUES ('database_version', ?);
VALUES (?, ?);
""",
(__DATABASE_VERSION__,)
map(
lambda kv: (kv[0], _format_setting(*kv)),
default_settings.items()
)
)
current_db_version = int(cursor.execute(
"SELECT value FROM config WHERE key = 'database_version' LIMIT 1;"
).fetchone()[0])

current_db_version = get_setting('database_version')
logging.debug(f'Current database version {current_db_version} and desired database version {__DATABASE_VERSION__}')
if current_db_version < __DATABASE_VERSION__:
migrate_db(current_db_version)
cursor.execute(
"UPDATE config SET value = ? WHERE key = 'database_version';",
(__DATABASE_VERSION__,)
)
set_setting('database_version', __DATABASE_VERSION__)

return
110 changes: 110 additions & 0 deletions backend/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#-*- coding: utf-8 -*-

import logging
from backend.custom_exceptions import InvalidKeyValue, KeyNotFound
from backend.db import __DATABASE_VERSION__, get_db

default_settings = {
'allow_new_accounts': True,
'database_version': __DATABASE_VERSION__
}

def _format_setting(key: str, value):
"""Turn python value in to database value
Args:
key (str): The key of the value
value (Any): The value itself
Raises:
InvalidKeyValue: The value is not valid
Returns:
Any: The converted value
"""
if key == 'database_version':
try:
value = int(value)
except ValueError:
raise InvalidKeyValue(key, value)

elif key == 'allow_new_accounts':
if not isinstance(value, bool):
raise InvalidKeyValue(key, value)
value = int(value)
return value

def _reverse_format_setting(key: str, value):
"""Turn database value in to python value
Args:
key (str): The key of the value
value (Any): The value itself
Returns:
Any: The converted value
"""
if key == 'allow_new_accounts':
value = value == 1
return value

def get_setting(key: str):
"""Get a value from the config
Args:
key (str): The key of which to get the value
Raises:
KeyNotFound: Key is not in config
Returns:
Any: The value of the key
"""
result = get_db().execute(
"SELECT value FROM config WHERE key = ? LIMIT 1;",
(key,)
).fetchone()
if result is None:
raise KeyNotFound(key)

result = _reverse_format_setting(key, result[0])

return result

def get_admin_settings() -> dict:
"""Get all admin settings
Returns:
dict: The admin settings
"""
return dict((
(key, _reverse_format_setting(key, value))
for (key, value) in get_db().execute("""
SELECT key, value
FROM config
WHERE key = 'allow_new_accounts';
"""
)
))

def set_setting(key: str, value) -> None:
"""Set a value in the config
Args:
key (str): The key for which to set the value
value (Any): The value to give to the key
Raises:
KeyNotFound: The key is not in the config
InvalidKeyValue: The value is not allowed for the key
"""
if not key in (*default_settings, 'database_version'):
raise KeyNotFound(key)

value = _format_setting(key, value)

get_db().execute(
"UPDATE config SET value = ? WHERE key = ?;",
(value, key)
)
return
10 changes: 9 additions & 1 deletion backend/users.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
#-*- coding: utf-8 -*-

import logging
from backend.custom_exceptions import (AccessUnauthorized, UsernameInvalid,

from backend.custom_exceptions import (AccessUnauthorized,
NewAccountsNotAllowed, UsernameInvalid,
UsernameTaken, UserNotFound)
from backend.db import get_db
from backend.notification_service import NotificationServices
from backend.reminders import Reminders
from backend.security import generate_salt_hash, get_hash
from backend.settings import get_setting
from backend.static_reminders import StaticReminders
from backend.templates import Templates

Expand Down Expand Up @@ -134,12 +137,17 @@ def register_user(username: str, password: str) -> int:
Raises:
UsernameInvalid: Username not allowed or contains invalid characters
UsernameTaken: Username is already taken; usernames must be unique
NewAccountsNotAllowed: In the admin panel, new accounts are set to be
not allowed.
Returns:
user_id (int): The id of the new user. User registered successful
"""
logging.info(f'Registering user with username {username}')

if not get_setting('allow_new_accounts'):
raise NewAccountsNotAllowed

# Check if username is valid
_check_username(username)

Expand Down
Loading

0 comments on commit a4a3c17

Please sign in to comment.