Dump changes
This commit is contained in:
parent
b49c6ced26
commit
a4b572dcc7
40 changed files with 186 additions and 37 deletions
14
.env.dev
14
.env.dev
|
|
@ -1,13 +1,13 @@
|
||||||
CGNO_ID_JWT_SECRET=secret
|
JWT_SECRET=secret
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
CGNO_ID_DB_USERNAME=root
|
DB_USERNAME=root
|
||||||
CGNO_ID_DB_PASSWORD=root
|
DB_PASSWORD=root
|
||||||
CGNO_ID_DB_HOST=127.0.0.1
|
DB_HOST=127.0.0.1
|
||||||
CGNO_ID_DB_NAME=cgno-id
|
DB_NAME=cgno-id
|
||||||
#
|
#
|
||||||
|
|
||||||
# Root
|
# Root
|
||||||
CGNO_ROOT_EMAIL=cognioandrey@gmail.com
|
ROOT_EMAIL=cognioandrey@gmail.com
|
||||||
CGNO_ROOT_PASSWORD=password
|
ROOT_PASSWORD=password
|
||||||
#
|
#
|
||||||
BIN
app/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
app/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/config.cpython-39.pyc
Normal file
BIN
app/__pycache__/config.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/db.cpython-39.pyc
Normal file
BIN
app/__pycache__/db.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/init.cpython-39.pyc
Normal file
BIN
app/__pycache__/init.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/main.cpython-39.pyc
Normal file
BIN
app/__pycache__/main.cpython-39.pyc
Normal file
Binary file not shown.
0
app/access_control/__init__.py
Normal file
0
app/access_control/__init__.py
Normal file
BIN
app/access_control/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
app/access_control/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/access_control/__pycache__/role.cpython-39.pyc
Normal file
BIN
app/access_control/__pycache__/role.cpython-39.pyc
Normal file
Binary file not shown.
6
app/access_control/role.py
Normal file
6
app/access_control/role.py
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
from app.user.model import User
|
||||||
|
|
||||||
|
|
||||||
|
def has_role(name: str, user: User):
|
||||||
|
if user.role.name != name:
|
||||||
|
raise Exception()
|
||||||
BIN
app/auth/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
app/auth/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/auth/__pycache__/dto.cpython-39.pyc
Normal file
BIN
app/auth/__pycache__/dto.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/auth/__pycache__/handlers.cpython-39.pyc
Normal file
BIN
app/auth/__pycache__/handlers.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/auth/__pycache__/middleware.cpython-39.pyc
Normal file
BIN
app/auth/__pycache__/middleware.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/auth/__pycache__/service.cpython-39.pyc
Normal file
BIN
app/auth/__pycache__/service.cpython-39.pyc
Normal file
Binary file not shown.
|
|
@ -10,8 +10,8 @@ from app.auth.dto import Credentials
|
||||||
from app.config import config
|
from app.config import config
|
||||||
from app.user.service import get_user_by_username, passwords_match
|
from app.user.service import get_user_by_username, passwords_match
|
||||||
|
|
||||||
JWT_SECRET = config["CGNO_ID_JWT_SECRET"]
|
JWT_SECRET = config["JWT_SECRET"]
|
||||||
JWT_ISSUER = "Energia"
|
JWT_ISSUER = "cognio ID"
|
||||||
|
|
||||||
|
|
||||||
def authenticate(credentials: Credentials, db: Session) -> Optional[str]:
|
def authenticate(credentials: Credentials, db: Session) -> Optional[str]:
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
from app.config import config
|
from app.config import config
|
||||||
|
|
||||||
DATABASE_URL = f"postgresql://{config['CGNO_ID_DB_USERNAME']}:{config['CGNO_ID_DB_PASSWORD']}@{config['CGNO_ID_DB_HOST']}/{config['CGNO_ID_DB_NAME']}"
|
DATABASE_URL = f"postgresql://{config['DB_USERNAME']}:{config['DB_PASSWORD']}@{config['DB_HOST']}/{config['DB_NAME']}"
|
||||||
|
|
||||||
engine = create_engine(DATABASE_URL)
|
engine = create_engine(DATABASE_URL)
|
||||||
|
|
||||||
|
|
|
||||||
23
app/init.py
Normal file
23
app/init.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
from app.config import config
|
||||||
|
from app.db import session_factory
|
||||||
|
from app.role.service import create_admin_role
|
||||||
|
from app.user.service import create_root_user
|
||||||
|
|
||||||
|
|
||||||
|
def init_root_user():
|
||||||
|
db = session_factory()
|
||||||
|
|
||||||
|
root_email = config["ROOT_EMAIL"]
|
||||||
|
root_password = config["ROOT_PASSWORD"]
|
||||||
|
|
||||||
|
create_root_user(db, root_email, root_password)
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
|
def init_admin_role():
|
||||||
|
db = session_factory()
|
||||||
|
|
||||||
|
create_admin_role(db)
|
||||||
|
|
||||||
|
db.close()
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
|
import uvicorn
|
||||||
from fastapi import FastAPI, APIRouter
|
from fastapi import FastAPI, APIRouter
|
||||||
from starlette.middleware.cors import CORSMiddleware
|
from starlette.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
from app.user.handlers import router as user_router
|
from app.user.handlers import router as user_router
|
||||||
from app.auth.handlers import router as auth_router
|
from app.auth.handlers import router as auth_router
|
||||||
from app.user.root import init_root_user
|
from app.init import init_root_user, init_admin_role
|
||||||
|
|
||||||
|
|
||||||
def main_router() -> APIRouter:
|
def main_router() -> APIRouter:
|
||||||
|
|
@ -15,6 +16,7 @@ def main_router() -> APIRouter:
|
||||||
|
|
||||||
app = FastAPI(title="cognio ID API")
|
app = FastAPI(title="cognio ID API")
|
||||||
|
|
||||||
|
app.add_event_handler("startup", init_admin_role)
|
||||||
app.add_event_handler("startup", init_root_user)
|
app.add_event_handler("startup", init_root_user)
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
CORSMiddleware,
|
CORSMiddleware,
|
||||||
|
|
@ -25,3 +27,6 @@ app.add_middleware(
|
||||||
)
|
)
|
||||||
|
|
||||||
app.include_router(main_router())
|
app.include_router(main_router())
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
uvicorn.run("app.main:app")
|
||||||
|
|
|
||||||
BIN
app/migrations/__pycache__/env.cpython-39.pyc
Normal file
BIN
app/migrations/__pycache__/env.cpython-39.pyc
Normal file
Binary file not shown.
|
|
@ -9,8 +9,9 @@ from alembic import context
|
||||||
|
|
||||||
sys.path.append(str(pathlib.Path(__file__).resolve().parents[2]))
|
sys.path.append(str(pathlib.Path(__file__).resolve().parents[2]))
|
||||||
|
|
||||||
from app.db import DATABASE_URL
|
from app.db import DATABASE_URL, EntityBase
|
||||||
from app.user.model import User
|
from app.user.model import User
|
||||||
|
from app.role.model import Role
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
# access to the values within the .ini file in use.
|
# access to the values within the .ini file in use.
|
||||||
|
|
@ -24,7 +25,7 @@ fileConfig(config.config_file_name)
|
||||||
# for 'autogenerate' support
|
# for 'autogenerate' support
|
||||||
# from myapp import mymodel
|
# from myapp import mymodel
|
||||||
# target_metadata = mymodel.Base.metadata
|
# target_metadata = mymodel.Base.metadata
|
||||||
target_metadata = [User.metadata]
|
target_metadata = EntityBase.metadata
|
||||||
|
|
||||||
# other values from the config, defined by the needs of env.py,
|
# other values from the config, defined by the needs of env.py,
|
||||||
# can be acquired:
|
# can be acquired:
|
||||||
|
|
|
||||||
39
app/migrations/versions/2a84260bc774_add_roles.py
Normal file
39
app/migrations/versions/2a84260bc774_add_roles.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
"""Add roles
|
||||||
|
|
||||||
|
Revision ID: 2a84260bc774
|
||||||
|
Revises: 646ae6f3e17a
|
||||||
|
Create Date: 2021-02-28 23:06:29.207602
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '2a84260bc774'
|
||||||
|
down_revision = '646ae6f3e17a'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_table('roles',
|
||||||
|
sa.Column('id', sa.Integer(), nullable=False),
|
||||||
|
sa.Column('name', sa.String(length=64), nullable=False),
|
||||||
|
sa.Column('description', sa.Text(), nullable=True),
|
||||||
|
sa.Column('creation_date', sa.DateTime(), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('id'),
|
||||||
|
sa.UniqueConstraint('name')
|
||||||
|
)
|
||||||
|
op.add_column('users', sa.Column('role_id', sa.Integer(), nullable=True))
|
||||||
|
op.create_foreign_key(None, 'users', 'roles', ['role_id'], ['id'])
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_constraint(None, 'users', type_='foreignkey')
|
||||||
|
op.drop_column('users', 'role_id')
|
||||||
|
op.drop_table('roles')
|
||||||
|
# ### end Alembic commands ###
|
||||||
Binary file not shown.
Binary file not shown.
0
app/role/__init__.py
Normal file
0
app/role/__init__.py
Normal file
BIN
app/role/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
app/role/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/role/__pycache__/model.cpython-39.pyc
Normal file
BIN
app/role/__pycache__/model.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/role/__pycache__/service.cpython-39.pyc
Normal file
BIN
app/role/__pycache__/service.cpython-39.pyc
Normal file
Binary file not shown.
14
app/role/model.py
Normal file
14
app/role/model.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from sqlalchemy import Column, Integer, String, DateTime, Text
|
||||||
|
|
||||||
|
from app.db import EntityBase
|
||||||
|
|
||||||
|
|
||||||
|
class Role(EntityBase):
|
||||||
|
__tablename__ = "roles"
|
||||||
|
|
||||||
|
id = Column(Integer, primary_key=True)
|
||||||
|
name = Column(String(64), unique=True, nullable=False)
|
||||||
|
description = Column(Text)
|
||||||
|
creation_date = Column(DateTime, nullable=False, default=datetime.utcnow())
|
||||||
49
app/role/service.py
Normal file
49
app/role/service.py
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from app.role.model import Role
|
||||||
|
|
||||||
|
|
||||||
|
def create_role(db: Session, role: Role) -> Role:
|
||||||
|
role.name = role.name.lower()
|
||||||
|
|
||||||
|
if get_role_by_name(db, role.name) is not None:
|
||||||
|
raise Exception()
|
||||||
|
|
||||||
|
db.add(role)
|
||||||
|
db.commit()
|
||||||
|
db.refresh(role)
|
||||||
|
|
||||||
|
return role
|
||||||
|
|
||||||
|
|
||||||
|
def get_role_by_name(db: Session, name: str) -> Optional[Role]:
|
||||||
|
return db.query(Role).filter(Role.name == name).one_or_none()
|
||||||
|
|
||||||
|
|
||||||
|
def get_role_by_id(db: Session, id: int) -> Optional[Role]:
|
||||||
|
return db.query(Role).filter(Role.id == id).one_or_none()
|
||||||
|
|
||||||
|
|
||||||
|
def get_roles(db: Session) -> list[Role]:
|
||||||
|
return db.query(Role).all()
|
||||||
|
|
||||||
|
|
||||||
|
def create_admin_role(db: Session):
|
||||||
|
admin_role = get_role_by_name(db, "admin")
|
||||||
|
|
||||||
|
if admin_role is None:
|
||||||
|
db.add(Role(name="admin"))
|
||||||
|
db.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def delete_role_by_id(db: Session, id: int):
|
||||||
|
role = get_role_by_id(db, id)
|
||||||
|
|
||||||
|
if role.name == "admin":
|
||||||
|
return
|
||||||
|
|
||||||
|
if role is not None:
|
||||||
|
db.delete(role)
|
||||||
|
db.commit()
|
||||||
BIN
app/user/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
app/user/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/user/__pycache__/dto.cpython-39.pyc
Normal file
BIN
app/user/__pycache__/dto.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/user/__pycache__/handlers.cpython-39.pyc
Normal file
BIN
app/user/__pycache__/handlers.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/user/__pycache__/model.cpython-39.pyc
Normal file
BIN
app/user/__pycache__/model.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/user/__pycache__/service.cpython-39.pyc
Normal file
BIN
app/user/__pycache__/service.cpython-39.pyc
Normal file
Binary file not shown.
|
|
@ -4,6 +4,7 @@ from fastapi import APIRouter, Depends, HTTPException
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from starlette.responses import Response
|
from starlette.responses import Response
|
||||||
|
|
||||||
|
from app.access_control.role import has_role
|
||||||
from app.auth.middleware import get_auth_user
|
from app.auth.middleware import get_auth_user
|
||||||
from app.user.dto import UserCreationModel, UserResourceModel
|
from app.user.dto import UserCreationModel, UserResourceModel
|
||||||
from app.user.model import User
|
from app.user.model import User
|
||||||
|
|
@ -21,6 +22,7 @@ async def create_user(
|
||||||
) -> UserResourceModel:
|
) -> UserResourceModel:
|
||||||
user = model.to_entity()
|
user = model.to_entity()
|
||||||
created_user = user_service.create_user(db, user)
|
created_user = user_service.create_user(db, user)
|
||||||
|
|
||||||
return UserResourceModel.from_entity(created_user)
|
return UserResourceModel.from_entity(created_user)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import enum
|
import enum
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from sqlalchemy import Column, String, Integer, DateTime, Enum, Date
|
from sqlalchemy import Column, String, Integer, DateTime, Enum, Date, ForeignKey
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from app.db import EntityBase
|
from app.db import EntityBase
|
||||||
|
from app.role.model import Role
|
||||||
|
|
||||||
|
|
||||||
class Sex(enum.Enum):
|
class Sex(enum.Enum):
|
||||||
|
|
@ -22,8 +24,14 @@ class User(EntityBase):
|
||||||
username = Column(String(length=32), unique=True, nullable=False)
|
username = Column(String(length=32), unique=True, nullable=False)
|
||||||
email = Column(String, unique=True, nullable=False)
|
email = Column(String, unique=True, nullable=False)
|
||||||
password = Column(String, nullable=False)
|
password = Column(String, nullable=False)
|
||||||
|
role_id = Column(Integer, ForeignKey("roles.id"))
|
||||||
given_name = Column(String(length=32), nullable=False)
|
given_name = Column(String(length=32), nullable=False)
|
||||||
family_name = Column(String(length=32))
|
family_name = Column(String(length=32))
|
||||||
sex = Column(Enum(Sex), nullable=False, default=Sex.NOT_KNOWN)
|
sex = Column(Enum(Sex), nullable=False, default=Sex.NOT_KNOWN)
|
||||||
birthdate = Column(Date)
|
birthdate = Column(Date)
|
||||||
creation_date = Column(DateTime, nullable=False, default=datetime.utcnow())
|
creation_date = Column(DateTime, nullable=False, default=datetime.utcnow())
|
||||||
|
|
||||||
|
role = relationship("Role", back_populates="users")
|
||||||
|
|
||||||
|
|
||||||
|
Role.users = relationship("User", back_populates="role")
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
from datetime import date
|
|
||||||
|
|
||||||
from app.config import config
|
|
||||||
from app.db import session_factory
|
|
||||||
from app.user import service as user_service
|
|
||||||
from app.user.model import User
|
|
||||||
|
|
||||||
|
|
||||||
def init_root_user():
|
|
||||||
db = session_factory()
|
|
||||||
root_user = user_service.get_user_by_username(db, "root")
|
|
||||||
|
|
||||||
if root_user is None:
|
|
||||||
user_service.create_user(db, User(
|
|
||||||
username="root",
|
|
||||||
email=config["CGNO_ROOT_EMAIL"],
|
|
||||||
password=config["CGNO_ROOT_PASSWORD"],
|
|
||||||
given_name="Root",
|
|
||||||
birthdate=date.today()
|
|
||||||
))
|
|
||||||
db.close()
|
|
||||||
|
|
@ -1,15 +1,18 @@
|
||||||
|
from datetime import date
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from passlib.context import CryptContext
|
from passlib.context import CryptContext
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from app.user.model import User
|
from app.user.model import User
|
||||||
|
from app.role import service as role_service
|
||||||
|
|
||||||
pwd_context = CryptContext(schemes=["bcrypt"])
|
pwd_context = CryptContext(schemes=["bcrypt"])
|
||||||
|
|
||||||
|
|
||||||
def create_user(db: Session, user: User) -> User:
|
def create_user(db: Session, user: User) -> User:
|
||||||
if get_user_by_username_or_email(db, user.username, user.email) is not None:
|
existing_user = get_user_by_username_or_email(db, user.username, user.email)
|
||||||
|
if existing_user is not None:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
user.password = pwd_context.hash(user.password)
|
user.password = pwd_context.hash(user.password)
|
||||||
|
|
@ -31,8 +34,28 @@ def get_user_by_username_or_email(db: Session, username: str, email: str) -> Opt
|
||||||
return db.query(User).filter(User.username == username, User.email == email).one_or_none()
|
return db.query(User).filter(User.username == username, User.email == email).one_or_none()
|
||||||
|
|
||||||
|
|
||||||
|
def create_root_user(db: Session, root_email: str, root_password: str):
|
||||||
|
root_user = get_user_by_username(db, "root")
|
||||||
|
admin_role = role_service.get_role_by_name(db, "admin")
|
||||||
|
|
||||||
|
if root_user is None:
|
||||||
|
root_user = User(
|
||||||
|
username="root",
|
||||||
|
email=root_email,
|
||||||
|
password=root_password,
|
||||||
|
given_name="Root",
|
||||||
|
role=admin_role,
|
||||||
|
birthdate=date.today()
|
||||||
|
)
|
||||||
|
create_user(db, root_user)
|
||||||
|
|
||||||
|
|
||||||
def delete_user_by_id(db: Session, id: int):
|
def delete_user_by_id(db: Session, id: int):
|
||||||
user = get_user_by_id(db, id)
|
user = get_user_by_id(db, id)
|
||||||
|
|
||||||
|
if user.username == "root":
|
||||||
|
raise Exception()
|
||||||
|
|
||||||
if user is not None:
|
if user is not None:
|
||||||
db.delete(user)
|
db.delete(user)
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
|
||||||
|
|
@ -8,4 +8,4 @@ services:
|
||||||
env_file:
|
env_file:
|
||||||
- ./.env.dev
|
- ./.env.dev
|
||||||
environment:
|
environment:
|
||||||
- CGNO_ID_DB_HOST=host.docker.internal
|
- DB_HOST=host.docker.internal
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue