diff --git a/README.md b/README.md index 3eb6e40bb9542d4b34113c1ef2a7ab13fa7613bc..58014528a23420a946f66234292ddf35e3ad380a 100755 --- a/README.md +++ b/README.md @@ -89,14 +89,22 @@ chmod +x /etc/cron.daily/stechuhr_data_retention ## Configuration -### Application +Stechuhr-Server allows you to use _multiple_ configuration files, each overriding the previous one either in full or partly. In any case a default configuration is used, which might or might not fit your purpose (probably not). + +To maintain control a helper script exists at `stechuhr_server/config.py` which allows you to create a new config, print the currently used ones, etc. If your system python has the `toml` dependency installed run it using `python3 stechuhr_server/config.py` and it will display the help. If you _don't_ have the toml dependency installed you can: + +1. Install it +2. Use the python in env (see installation above): `path/to/env/bin/python stechuhr_server/config.py` +3. Use python poetry: `poetry run config` + +### Config section: application Application related settings. Here the database can be exposed via a GET request for debugging purposes. Make sure this is off in production, or make sure no such http requests can be made from the public internet. -### Database +### Config section: database.path Set the path to change where the database file is stored. Make sure that the path is writeable by the service user -### ID verification +### Config section: database.id_patterns in `config.toml` you can add a list of regex patterns that stechuhr (*both on server and on client!*) uses to verify the Card IDs. These two patterns for example allow upper/lowercase hex strings with lengths either between 6 and 16 characters OR exactly 24 characters: @@ -110,4 +118,8 @@ id_patterns = [ ] ``` -If in doubt consider [testing your regexes here](https://regexplained.com/) \ No newline at end of file +If in doubt consider [testing your regexes here](https://regexplained.com/) + +### Config section: retention + +You might not be allowed to keep the collected data around for later. Here you can specify the number of days you wanna keep the data around (in Germany this might be 28 days, but inform yourself). You will additionally need to [install the data retention script](#Data Retention) \ No newline at end of file diff --git a/stechuhr_server/config.py b/stechuhr_server/config.py index abacf7b2e8428b14559ecb9ad6cca4070ad7a217..de4d584e5f7b73e79727edd16c21a09e30c09b71 100644 --- a/stechuhr_server/config.py +++ b/stechuhr_server/config.py @@ -21,10 +21,10 @@ expose_visitor_data = false expose_current_visitor_number = false [database] -# sqlite db path, use ":memory:" for RAM db +# Path of the sqlite database file, use ":memory:" to use in RAM only database path = "visitors.db" -# A list of possible regex patterns for the id (logical OR!) +# A list of possible regex patterns for the card ids (combined by logical OR!) id_patterns = [ "^806[A-Z0-9]{9}04$", "^FB6A1E60$", @@ -33,15 +33,15 @@ id_patterns = [ "^FB67D500$", ] -# minimum and maximum lengths for the received strings +# Minimum and maximum lengths for the received data fields min_entrance_length = 1 max_entrance_length = 128 min_location_length = 1 max_location_length = 128 [retention] -# how old is data allowed to be (in days) -duration = 365 +# Duration in days to keep data around (German law is 28 days) +duration = 28 """ # Config for the logger, there should be no need to make @@ -149,6 +149,7 @@ def has_no_existing_config() -> bool: """ return len(get_existing_config_file_paths()) == 0 + def merge(this: dict, that: dict) -> dict: """ Merge dict this in to dict that @@ -160,6 +161,7 @@ def merge(this: dict, that: dict) -> dict: this[key] = value return this + def initialize_config(logger=None) -> dict: """ Initialize a configuration. If none exists, create a default one @@ -208,8 +210,8 @@ def main(): Gets run only if config.py is called directly or via `poetry run config` Entry point for the CLI application """ - import sys + # List of available commands and their respective functions commands = { "default" : print_default, "paths": print_paths, @@ -218,45 +220,82 @@ def main(): "test": test } + # List of available options + availaible_options = [ + ["-h", "--help"] + ] - + # If no argument has been passed display the help and exit if len(sys.argv) == 1: print_help() exit() + # Extract the command arguments command_args = [c for c in sys.argv[1:] if not c.strip().startswith("-")] + + # Extract the short_options short_options = [c.lstrip("-") for c in sys.argv[1:] if c.strip().startswith("-") and not c.strip().startswith("--")] + + # Flatten the short_options to e.g. so -1234 will result in ["1", "2", "3", "4"] + short_options = [item for sublist in short_options for item in sublist] + + # Extract the long options long_options = [c.lstrip("--") for c in sys.argv[1:] if c.strip().startswith("--")] + errored = False + # Short Options + for o in short_options: + if o not in [a[0].lstrip("-") for a in availaible_options]: + print("Error: the option \"-{}\" does not exist.".format(o), file=sys.stderr) + errored = True + + # Long Options + for o in long_options: + if o not in [a[0].lstrip("--") for a in availaible_options]: + print("Error: the option \"--{}\" does not exist.".format(o), file=sys.stderr) + errored = True + + # If any of the above errored, exit. This allows to display all errors at once + if errored: + print("\nCheck the available commands and options below:") + print() + print_help() + exit() + # Currently we only handle a single command if len(command_args) == 1: command = sys.argv[1] + # Short commands are allowed if they are not ambigous. E.g "te" will trigger "test" if not any([c.startswith(command.strip().lower()) for c in commands.keys()]): + # No fitting command has been found, print helpt and exit print_help() exit() elif len([c for c in commands.keys() if c.startswith(command.strip().lower())]) > 1: + # More than one fitting command has been found, display this message print("Ambiguous Input: There are {} commands starting with \"{}\": {}".format( len([c for c in commands.keys() if c.startswith(command.strip().lower())]), command, ", ".join([c for c in commands.keys() if c.startswith(command.strip().lower())]) )) else: + # A command has been found: choice = [c for c in commands.keys() if c.startswith(command.strip().lower())][0] + + # If there is a -h or --help option, display the function's docstring + # otherwise execute the function if "h" in short_options or "help" in long_options: print("Help: config {}".format(commands[choice].__name__)) print(commands[choice].__doc__) else: commands[choice]() - else: + # If more than one command is given, display the help print_help() def test(): """ - Runs the config initialization as it would in production, prints out the - order in which the config files are read and spits out the final resulting - toml config + Reads all configs like it would in production, prints out the order in which the config files are read and spits out the final resulting toml config """ import pprint config = initialize_config() @@ -265,11 +304,15 @@ def test(): def print_default(): """ - Print default config + Prints the default config.toml """ print(DEFAULT_CONFIG) + def print_paths(): + """ + Prints the potential paths where a config could or should be. If environment variables are used to specify said path, this will be mentioned. If a file doesn't exist, it will be mentioned as well. + """ paths = get_potential_config_file_paths() if paths is not None: for p in paths: @@ -286,6 +329,7 @@ def print_paths(): else: print("There are no paths..") + def print_directories(): """ Prints a list of directories where configs are searched for. @@ -301,9 +345,10 @@ def print_directories(): else: print("There are no directories..") + def create_config(): """ - Interactivally create a config directory with a default config in it. + Interactivally create a config directory at a choice of different places with a default config in it. """ helptext = """Configs are read from the following directories (later overrides earlier): 1. DEFAULT_CONFIG (use config default to inspect) @@ -389,8 +434,10 @@ def create_config(): print("Default Config has been written to {}".format(config_path)) - def print_help(): + """ + Print the help + """ helptext = """========= {} CONFIG ========= Helper tool for managing and installing a stechuhr-server config. @@ -408,9 +455,13 @@ Commands: directories . . . Prints which config directories are read paths . . . . . . Prints which config files are read test . . . . . . Read in the configs and print the resulting combined toml + +Options: + -h, --help . . . Display the help message of a command """.format(APPLICATION_NAME.upper()) print(helptext) + if __name__ == "__main__": main() \ No newline at end of file