initial commit

by this point we have:

- flask boilerplate
- sqlite
- user creation/deletion cli
This commit is contained in:
dogeystamp 2023-03-09 16:38:57 -05:00
commit 00314f155a
10 changed files with 181 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
venv
__pycache__/
.env
config.yml
instance/

8
config.yml.example Normal file
View File

@ -0,0 +1,8 @@
# vim: filetype=yaml
secret_key: ""
sqlalchemy_basedir: "sqlite:///"
sqlalchemy_basename: "sachet"
# bcrypt_log_rounds: 13

16
requirements.txt Normal file
View File

@ -0,0 +1,16 @@
bcrypt==4.0.1
click==8.1.3
Flask==2.2.3
Flask-Bcrypt==1.0.1
Flask-Cors==3.0.10
Flask-Script==2.0.6
Flask-SQLAlchemy==3.0.3
greenlet==2.0.2
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.2
PyYAML==6.0
six==1.16.0
SQLAlchemy==2.0.5.post1
typing_extensions==4.5.0
Werkzeug==2.2.3

0
sachet/__init__.py Normal file
View File

22
sachet/server/__init__.py Normal file
View File

@ -0,0 +1,22 @@
import os
from flask import Flask
from flask_cors import CORS
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
app = Flask(__name__)
CORS(app)
app_settings = os.getenv(
'APP_SETTINGS',
'sachet.server.config.DevelopmentConfig'
)
app.config.from_object(app_settings)
bcrypt = Bcrypt(app)
db = SQLAlchemy(app)
import sachet.server.commands
from sachet.server.auth.views import auth_blueprint
app.register_blueprint(auth_blueprint)

View File

View File

@ -0,0 +1,7 @@
from flask import Blueprint
auth_blueprint = Blueprint("auth_blueprint", __name__)
@auth_blueprint.route('/')
def index():
return "Hello world"

65
sachet/server/commands.py Normal file
View File

@ -0,0 +1,65 @@
import click
from sachet.server import app, db
from sachet.server.models import User
from flask.cli import AppGroup
db_cli = AppGroup("db")
@db_cli.command("create")
def create_db():
"""Create all db tables."""
db.create_all()
@db_cli.command("drop")
@click.option('--yes', is_flag=True, expose_value=False, prompt="Are you sure you want to drop all tables?")
def drop_db():
"""Drop all db tables."""
db.drop_all()
app.cli.add_command(db_cli)
user_cli = AppGroup("user")
@user_cli.command("create")
@click.option("--admin", default=False, prompt="Set this user as administrator?", help="Set this user an administrator.")
@click.option("--username", prompt="Username", help="Sets the username.")
@click.option("--password",
prompt="Password",
hide_input=True,
help="Sets the user's password (for security, avoid setting this from the command line).")
def create_user(admin, username, password):
"""Create a user directly in the database."""
user = User.query.filter_by(username=username).first()
if not user:
user = User(
username=username,
password=password,
admin=admin
)
db.session.add(user)
db.session.commit()
else:
raise Exception(f"User '{username}' already exists (ID: {user.id})")
@user_cli.command("delete")
@click.option("--username", "selector", help="Delete by username.", flag_value="username", default=True)
@click.option("--id", "selector", help="Delete by ID.", flag_value="ID", default=True)
@click.argument("usersel")
@click.option('--yes', is_flag=True, expose_value=False, prompt=f"Are you sure you want to delete this user?")
def delete_user(selector, usersel):
if selector == "username":
user = User.query.filter_by(username=usersel).first()
elif selector == "ID":
user = User.query.filter_by(id=usersel).first()
if not user:
raise KeyError(f"User ({selector} {usersel}) does not exist.")
else:
db.session.delete(user)
db.session.commit()
app.cli.add_command(user_cli)

39
sachet/server/config.py Normal file
View File

@ -0,0 +1,39 @@
from os import environ, path
import yaml
config_locations = ["/etc/sachet", "."]
config_path = ""
for dir in config_locations:
file_path = f"{dir}/config.yml"
if path.exists(file_path):
config_path = file_path
break
if config_path == "":
raise FileNotFoundError("Please create a configuration: copy config.yml.example to config.yml.")
config = yaml.safe_load(open(config_path))
if config["secret_key"] == "":
raise ValueError("Please set secret_key within the configuration.")
class BaseConfig:
DEBUG = False
SQLALCHEMY_DATABASE_URI = config["sqlalchemy_basedir"] + config["sqlalchemy_basename"] + ".db"
SECRET_KEY = config["secret_key"]
BCRYPT_LOG_ROUNDS = config.get("bcrypt_log_rounds", 13)
SQLALCHEMY_TRACK_MODIFICATIONS = False
class TestingConfig(BaseConfig):
DEBUG = True
SQLALCHEMY_DATABASE_URI = config["sqlalchemy_basedir"] + config["sqlalchemy_basename"] + "_test" + ".db"
BCRYPT_LOG_ROUNDS = config.get("bcrypt_log_rounds", 4)
class DevelopmentConfig(BaseConfig):
DEBUG = True
SQLALCHEMY_DATABASE_URI = config["sqlalchemy_basedir"] + config["sqlalchemy_basename"] + "_dev" + ".db"
BCRYPT_LOG_ROUNDS = config.get("bcrypt_log_rounds", 4)
class ProductionConfig(BaseConfig):
DEBUG = False

19
sachet/server/models.py Normal file
View File

@ -0,0 +1,19 @@
from sachet.server import app, db, bcrypt
import datetime
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(255), unique=True, nullable=False)
password = db.Column(db.String(255), nullable=False)
register_date = db.Column(db.DateTime, nullable=False)
admin = db.Column(db.Boolean, nullable=False, default=False)
def __init__(self, username, password, admin=False):
self.password = bcrypt.generate_password_hash(
password, app.config.get("BCRYPT_LOG_ROUNDS")
).decode()
self.username = username
self.register_date = datetime.datetime.now()
self.admin = admin