initial commit
by this point we have: - flask boilerplate - sqlite - user creation/deletion cli
This commit is contained in:
commit
00314f155a
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
venv
|
||||
__pycache__/
|
||||
.env
|
||||
config.yml
|
||||
instance/
|
8
config.yml.example
Normal file
8
config.yml.example
Normal 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
16
requirements.txt
Normal 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
0
sachet/__init__.py
Normal file
22
sachet/server/__init__.py
Normal file
22
sachet/server/__init__.py
Normal 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)
|
0
sachet/server/auth/__init__.py
Normal file
0
sachet/server/auth/__init__.py
Normal file
7
sachet/server/auth/views.py
Normal file
7
sachet/server/auth/views.py
Normal 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
65
sachet/server/commands.py
Normal 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
39
sachet/server/config.py
Normal 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
19
sachet/server/models.py
Normal 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
|
Loading…
Reference in New Issue
Block a user