Commit be808d1f authored by Weizhi Cui's avatar Weizhi Cui

Update project

parent 7e4865d0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 13:49
# @File : app.py
# @Description :
"""
from application import create_app
app = create_app()
if __name__ == "__main__":
app.run()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 12:11
# @File : __init__.py
# @Description :
"""
import os
from flask import Flask
from application.extensions import init_plugs
from application.views import init_views
from application.script import init_script
def create_app() -> Flask:
app = Flask(os.path.abspath(os.path.join(os.path.dirname(__file__), ".")))
# 注册各种插件
init_plugs(app)
# 注册路由
init_views(app)
# 注册命令
init_script(app)
return app
System:
Env: public
MySQL:
USER: root
PASSWORD: localhost123
HOST: localhost
PORT: 3306
DB: elp
System:
Env: public123
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 22:31
# @File : __init__.py
# @Description :
"""
from .user import UserDao
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 23:56
# @File : user.py
# @Description :
"""
from application.extensions.init_sqlalchemy import db
from application.models.user import User
class UserDao:
@classmethod
def get_all(cls):
return User.query.all()
@classmethod
def get_by_id(cls, user_id: int):
return User.query.get(user_id)
@classmethod
def create(cls, username: str, password: str, email: str):
new_user = User(username=username, email=email, password=password)
db.session.add(new_user)
db.session.commit()
return new_user
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 12:50
# @File : __init__.py
# @Description :
"""
from flask import Flask
from .init_config import init_config
from .init_logger import init_logger
from .init_sqlalchemy import init_database
from .init_bcrypt import init_bcrypt
from .init_migrate import init_migrate
from .init_apispec import init_apispec
from .init_marshmallow import init_marshmallow
def init_plugs(app: Flask) -> None:
init_config(app)
init_logger(app)
init_database(app)
init_bcrypt(app)
init_migrate(app)
init_apispec(app)
init_marshmallow(app)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 12:01
# @File : init_apispec.py
# @Description :
"""
from flask import Flask
from flask_apispec import FlaskApiSpec
# 初始化 flask-apispec
apispec = FlaskApiSpec()
def init_apispec(app: Flask) -> None:
"""
Initialize the ApiSpec extension
:param app: flask.Flask application instance
:return: None
"""
apispec.init_app(app)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 22:06
# @File : init_bcrypt.py
# @Description :
"""
from flask import Flask
from flask_bcrypt import Bcrypt
bcrypt = Bcrypt()
def init_bcrypt(app: Flask) -> None:
"""
Initialize the bcrypt extension
:param app: flask.Flask application instance
:return: None
"""
bcrypt.init_app(app)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 12:53
# @File : init_config.py
# @Description : flask-dynaconf extension
"""
from flask import Flask
from dynaconf import FlaskDynaconf
def init_config(app: Flask) -> None:
"""
Initialize the dynaconf extension
:param app: flask.Flask application instance
:return: None
"""
FlaskDynaconf(
app=app,
loaders=[
"application.utils.loaders.consul_loader",
"application.utils.loaders.yaml_loader",
],
)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 18:16
# @File : init_logger.py
# @Description :
"""
from flask import Flask
from application.lib import FlaskLoguru
def init_logger(app: Flask) -> None:
"""
Initialize the dynaconf extension
:param app: flask.Flask application instance
:return: None
"""
FlaskLoguru(app)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 12:36
# @File : init_marshmallow.py
# @Description :
"""
from flask import Flask
from flask_marshmallow import Marshmallow
ma = Marshmallow()
def init_marshmallow(app: Flask) -> None:
"""
Initialize the database extension
:param app: flask.Flask application instance
:return: None
"""
ma.init_app(app)
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 01:19
# @File : init_migrate.py
# @Description :
"""
from flask import Flask
from flask_migrate import Migrate
from application.extensions.init_sqlalchemy import db
migrate = Migrate()
def init_migrate(app: Flask) -> None:
"""
Initialize the database extension
:param app: flask.Flask application instance
:return: None
"""
migrate.init_app(app, db)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 22:01
# @File : init_sqlalchemy.py
# @Description :
"""
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from application.utils import dsn
db = SQLAlchemy()
def init_database(app: Flask) -> None:
"""
Initialize the database extension
:param app: flask.Flask application instance
:return: None
"""
app.config.setdefault('SQLALCHEMY_DATABASE_URI', dsn(app))
db.init_app(app)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 12:19
# @File : __init__.py
# @Description :
"""
from .config import ConsulConfig, LocalConfig
from .flask_loguru import FlaskLoguru
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 15:06
# @File : __init__.py.py
# @Description :
"""
from .consul import ConsulConfig
from .local import LocalConfig
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 15:06
# @File : consul.py
# @Description :
"""
from typing import Any
import consul
import yaml
class ConsulConfig:
def __init__(self, host='localhost', port=8500, token=None, dc='dc1'):
self.token = token
self.dc = dc
self.client = consul.Consul(host=host, port=port, token=token, dc=dc)
def get(self, key: str) -> Any:
_, data = self.client.kv.get(key=key, token=self.token, dc=self.dc)
if data is None:
raise KeyError(f'Key {key} not found in Consul.')
return yaml.load(data['Value'], Loader=yaml.FullLoader)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 15:07
# @File : local.py
# @Description :
"""
import os
from typing import Any
import yaml
class LocalConfig:
def __init__(self, config_dir: str):
self.config_dir = config_dir
def load(self, filename: str) -> Any:
filepath = os.path.join(self.config_dir, filename)
if not os.path.exists(filepath):
raise FileNotFoundError(f"No such file or directory: '{filepath}'")
with open(filepath, 'r') as file:
cfg = yaml.safe_load(file)
return cfg
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 17:43
# @File : __init__.py
# @Description :
"""
from .logger import FlaskLoguru
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 18:21
# @File : format.py
# @Description :
"""
import json
def serialize(record: dict) -> str:
time_stamp = record["time"]
time_stamp = time_stamp.strftime("%Y-%m-%d %H:%M:%S")
subset = {
"time": time_stamp,
"message": record["message"],
"level": record["level"].name.lower(),
"tag": "{}:{}".format(record["file"].path, record["line"]),
"field": {"data": record["extra"].get("data", {})},
}
return json.dumps(subset, ensure_ascii=False)
def patching(record: dict) -> str:
record["extra"]["serialized"] = serialize(record)
return "{extra[serialized]}\n"
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 17:44
# @File : logger.py
# @Description :
"""
import sys
from flask import Flask, request, g
from loguru import logger
from .format import patching
class FlaskLoguru:
def __init__(self, app=None):
if app is not None:
self.init_app(app)
def init_app(self, app: Flask):
logger.remove()
logger.add(sys.stderr, format=patching)
if not hasattr(app, "extensions"):
app.extensions = {}
app.extensions.setdefault("loguru", {})
app.extensions["loguru"][self] = logger
@app.before_request
def before_request():
data = dict(
url=request.url,
method=request.method,
ip=request.remote_addr,
request_body=request.get_json(),
)
g.logger = logger.bind(data=data)
g.logger.info('Request started')
@app.after_request
def after_request(response):
g.logger.info('Request completed')
return response
@app.teardown_request
def teardown_request(exception=None):
if exception:
data = dict(
exception=str(exception)
)
g.logger = logger.bind(data=data)
g.logger.exception('An error occurred during the request')
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 22:12
# @File : __init__.py.py
# @Description :
"""
from .user import User
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 22:12
# @File : user.py
# @Description :
"""
from sqlalchemy.ext.hybrid import hybrid_property
from application.extensions.init_bcrypt import bcrypt
from application.extensions.init_sqlalchemy import db
class User(db.Model):
"""Basic user model"""
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(80), unique=True, nullable=False)
_password = db.Column("password", db.String(255), nullable=False)
active = db.Column(db.Boolean, default=True)
@hybrid_property
def password(self):
return self._password
@password.setter
def password(self, password: str):
self._password = bcrypt.generate_password_hash(password).decode('utf-8')
def check_password(self, password: str):
# 判断传过来的密码是否与数据库存的密码一致
return bcrypt.check_password_hash(self._password, password)
def to_dict(self) -> dict:
"""object to dict"""
return {
'id': self.id,
'username': self.username,
'email': self.email,
}
def __repr__(self) -> str:
return f'<User {self.username}>'
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 22:31
# @File : __init__.py.py
# @Description :
"""
from .user import CreateUserItem
from .user import UserSchema
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 00:07
# @File : user.py
# @Description :
"""
from pydantic import BaseModel, EmailStr, field_validator
from application.extensions.init_marshmallow import ma
from application.extensions.init_sqlalchemy import db
from application.models import User
from marshmallow import validates, ValidationError
class CreateUserItem(BaseModel):
username: str
password: str
email: EmailStr
@classmethod
@field_validator("username")
def name_must_contain_only_characters(cls, value):
if not value.isalpha():
raise ValueError("Username must contain only characters.")
return value
class UserSchema(ma.SQLAlchemyAutoSchema):
id = ma.Int(dump_only=True)
username = ma.Str(required=True)
password = ma.String(load_only=True, required=True)
email = ma.Email(required=True)
class Meta:
model = User
sqla_session = db.session
load_instance = True
exclude = ("_password",)
@validates('username')
def validate_username(self, username):
if len(username) < 3:
raise ValidationError('Username must be at least 3 characters.')
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 11:21
# @File : __init__.py.py
# @Description :
"""
from flask import Flask
from .cmdline import init
def init_script(app: Flask) -> None:
app.cli.add_command(init)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 11:21
# @File : cmdline.py
# @Description :
"""
import click
from flask.cli import with_appcontext
@click.command("init")
@with_appcontext
def init():
"""Create a new admin user"""
from application.extensions.init_sqlalchemy import db
from application.models import User
click.echo("create user")
user = User(username="StudentCWZ", email="StudentCWZ@outlook.com", password="qwe!2345", active=True)
db.session.add(user)
db.session.commit()
click.echo("created user admin")
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 22:29
# @File : __init__.py
# @Description :
"""
from .user import UserService
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 00:03
# @File : user.py
# @Description :
"""
from application.dao import UserDao
class UserService:
@classmethod
def get_all_users(cls):
return UserDao.get_all()
@classmethod
def get_user_by_id(cls, user_id: int):
return UserDao.get_by_id(user_id)
@classmethod
def create_user(cls, username: str, password: str, email: str):
return UserDao.create(username, password, email)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 12:15
# @File : __init__.py
# @Description :
"""
from .dsn import dsn
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 00:36
# @File : __init__.py
# @Description :
"""
from .dsn import dsn
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 00:36
# @File : dsn.py
# @Description :
"""
from flask import Flask
def dsn(app: Flask) -> str:
"""
Initialize the MySQL dsn extension
:param app: flask.Flask application instance
:return: dsn
"""
mysql_cfg = app.config.get('MySQL')
if mysql_cfg is None:
raise KeyError('Key MySQL error')
return (f'mysql+pymysql://{app.config.MySQL.USER}:'
f'{app.config.MySQL.PASSWORD}@{app.config.MySQL.HOST}:{app.config.MySQL.PORT}/{app.config.MySQL.DB}')
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 12:16
# @File : __init__.py
# @Description :
"""
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 12:16
# @File : consul_loader.py
# @Description :
"""
import os
from typing import NamedTuple, Union
import requests
from dynaconf.base import LazySettings
from dynaconf.utils.parse_conf import parse_conf_data
from application.lib import ConsulConfig
IDENTIFIER = "consul_loader"
class SourceMetadata(NamedTuple):
loader: str
identifier: str
env: str
merged: bool = False
def load(
obj: LazySettings,
env: str = None,
silent: bool = True,
key: str = None,
validate=False,
) -> Union[bool, None]:
consul_host = os.environ.get('CONSUL_HOST', 'localhost')
consul_port = os.environ.get('CONSUL_PORT', 8500)
consul_dc = os.environ.get('CONSUL_DC', 'dc1')
consul_token = os.getenv('CONSUL_TOKEN')
consul_key = os.getenv('CONSUL_KEY')
# 没有对应环境变量,会进入下一个加载器
if consul_key is None:
return
# 实例 ConsulConfig
client = ConsulConfig(host=consul_host, port=consul_port, token=consul_token, dc=consul_dc)
# 捕获异常
try:
data = client.get(key=consul_key)
except requests.exceptions.ConnectionError:
print(2)
# 连接错误后,则会进入下一个加载器
return
except Exception as e:
# 发生未知错误,才会抛出异常
raise RuntimeError(f'Unknown error: {e}')
# 基于 key 获取所需配置
if key is not None:
data = data[key]
if env is None:
return
try:
# 获取 consul 注册中心的配置信息
result = {
key: parse_conf_data(value, tomlfy=True, box_settings=obj)
for key, value in data.items()
}
except Exception as e:
if silent:
return False
raise e
else:
result['Consul'] = True
# 将 result 配置写入 dynaconf 内置配置中
obj.update(
result,
loader_identifier=IDENTIFIER,
validate=validate,
)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 13:01
# @File : yaml_loader.py
# @Description :
"""
import os
from pathlib import Path
from typing import Union
from dynaconf.base import LazySettings
from dynaconf.utils.parse_conf import parse_conf_data
from application.lib import LocalConfig
IDENTIFIER = "yaml_loader"
def load(
obj: LazySettings,
env: str = None,
silent: bool = True,
key: str = None,
validate=False,
) -> Union[bool, None]:
# 判断是否已经加载 consul 配置,如果加载,则不再加载本地配置
if obj.get('Consul', False):
return
# 获取本地配置文件目录
config_dir = os.path.join(str(Path(__file__).parent.parent.parent), 'config')
# 实例化 LocalConfig 对象
local_cfg = LocalConfig(config_dir)
# 判断当前是否为生产环境,基于不同环境读取本地不同配置文件
if env == 'PRODUCTION':
filename = f'{env.lower()}_config.yaml'
else:
filename = 'config.yaml'
# 基于 key 获取所需配置
if key is None:
cfg = local_cfg.load(filename)
else:
cfg = local_cfg.load(filename)[key]
try:
# 将 cfg 配置写入 dynaconf 内置配置中
if cfg.get(env) is None:
result = {
key: parse_conf_data(value, tomlfy=True, box_settings=obj)
for key, value in cfg.items()
}
else:
result = {
key: parse_conf_data(value, tomlfy=True, box_settings=obj)
for key, value in cfg[env].items()
}
except Exception as e:
if silent:
return False
raise e
else:
if result:
obj.update(
result,
loader_identifier=IDENTIFIER,
validate=validate,
)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/28 22:29
# @File : __init__.py.py
# @Description :
"""
from flask import Flask
from .user import register_user_views
def init_views(app: Flask) -> None:
register_user_views(app)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 00:18
# @File : __init__.py.py
# @Description :
"""
from flask import Flask
from .user import user_api
def register_user_views(app: Flask):
app.register_blueprint(user_api)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
# @Version : Python 3.11.4
# @Software : Sublime Text 4
# @Author : StudentCWZ
# @Email : StudentCWZ@outlook.com
# @Date : 2023/10/29 00:08
# @File : user.py
# @Description :
"""
from flask import Blueprint, request, jsonify
from application.services import UserService
from marshmallow import ValidationError
from application.schemas import UserSchema
user_api = Blueprint('user_api', __name__)
@user_api.route('/users', methods=['GET'])
def get_users():
users = UserService.get_all_users()
return jsonify([user.to_dict() for user in users])
@user_api.route('/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
user = UserService.get_user_by_id(user_id)
if user is None:
return jsonify({'error': 'User not found'}), 404
return jsonify(user.to_dict())
@user_api.route('/users', methods=['POST'])
def create_user():
user_schema = UserSchema()
try:
data = user_schema.load(request.json)
except ValidationError as e:
return jsonify(e.messages), 400
username = data.username
password = data.password
email = data.email
user = UserService.create_user(username, password, email)
return jsonify(user_schema.dump(user)), 201
alembic==1.12.1
annotated-types==0.6.0
apispec==6.3.0
bcrypt==4.0.1
blinker==1.6.3
certifi==2023.7.22
charset-normalizer==3.3.1
click==8.1.7
dnspython==2.4.2
dynaconf==3.2.3
email-validator==2.1.0.post1
Flask==3.0.0
flask-apispec==0.11.4
Flask-Bcrypt==1.0.1
Flask-Migrate==4.0.5
Flask-SQLAlchemy==3.1.1
idna==3.4
itsdangerous==2.1.2
Jinja2==3.1.2
loguru==0.7.2
Mako==1.2.4
MarkupSafe==2.1.3
marshmallow==3.20.1
packaging==23.2
pydantic==2.4.2
pydantic_core==2.10.1
PyMySQL==1.1.0
python-consul==1.1.0
PyYAML==6.0.1
requests==2.31.0
six==1.16.0
SQLAlchemy==2.0.22
typing_extensions==4.8.0
urllib3==2.0.7
webargs==8.3.0
Werkzeug==3.0.1
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment