feat(backend): start multi-tenant support (WIP) (#680)

* fix ts types

* feat(code-generation): ♻️ update code-generation formats

* new scope

* add step button

* fix linter error

* update code-generation tags

* feat(backend):  start multi-tenant support

* feat(backend):  group invitation token generation and signup

* refactor(backend): ♻️ move group admin actions to admin router

* set url base to include `/admin`

* feat(frontend):  generate user sign-up links

* test(backend):  refactor test-suite to further decouple tests (WIP)

* feat(backend): 🐛 assign owner on backup import for recipes

* fix(backend): 🐛 assign recipe owner on migration from other service

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden
2021-09-09 08:51:29 -08:00
committed by GitHub
parent 3c504e7048
commit bdaf758712
90 changed files with 1793 additions and 949 deletions

View File

@@ -1,6 +1,6 @@
from fastapi import APIRouter
from . import api_tokens, crud, favorites, images, passwords, registration, sign_up
from . import api_tokens, crud, favorites, images, passwords, registration
# Must be used because of the way FastAPI works with nested routes
user_prefix = "/users"
@@ -9,9 +9,6 @@ router = APIRouter()
router.include_router(registration.router, prefix=user_prefix, tags=["Users: Registration"])
router.include_router(sign_up.admin_router, prefix=user_prefix, tags=["Users: Sign-Up"])
router.include_router(sign_up.public_router, prefix=user_prefix, tags=["Users: Sign-Up"])
router.include_router(crud.user_router, prefix=user_prefix, tags=["Users: CRUD"])
router.include_router(crud.admin_router, prefix=user_prefix, tags=["Users: CRUD"])

View File

@@ -8,7 +8,7 @@ router = APIRouter(prefix="/register")
@router.post("", response_model=UserOut, status_code=status.HTTP_201_CREATED)
def reset_user_password(
def register_new_user(
data: CreateUserRegistration, registration_service: RegistrationService = Depends(RegistrationService.public)
):
return registration_service.register_user(data)

View File

@@ -1,72 +0,0 @@
import uuid
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status
from sqlalchemy.orm.session import Session
from mealie.core.dependencies import get_admin_user
from mealie.core.security import hash_password
from mealie.db.database import db
from mealie.db.db_setup import generate_session
from mealie.routes.routers import AdminAPIRouter
from mealie.schema.user import PrivateUser, SignUpIn, SignUpOut, SignUpToken, UserIn
from mealie.services.events import create_user_event
public_router = APIRouter(prefix="/sign-ups")
admin_router = AdminAPIRouter(prefix="/sign-ups")
@admin_router.get("", response_model=list[SignUpOut])
async def get_all_open_sign_ups(session: Session = Depends(generate_session)):
""" Returns a list of open sign up links """
return db.sign_ups.get_all(session)
@admin_router.post("", response_model=SignUpToken)
async def create_user_sign_up_key(
background_tasks: BackgroundTasks,
key_data: SignUpIn,
current_user: PrivateUser = Depends(get_admin_user),
session: Session = Depends(generate_session),
):
""" Generates a Random Token that a new user can sign up with """
sign_up = {
"token": str(uuid.uuid1().hex),
"name": key_data.name,
"admin": key_data.admin,
}
background_tasks.add_task(
create_user_event, "Sign-up Token Created", f"Created by {current_user.full_name}", session=session
)
return db.sign_ups.create(session, sign_up)
@public_router.post("/{token}")
async def create_user_with_token(
background_tasks: BackgroundTasks, token: str, new_user: UserIn, session: Session = Depends(generate_session)
):
""" Creates a user with a valid sign up token """
# Validate Token
db_entry: SignUpOut = db.sign_ups.get(session, token, limit=1)
if not db_entry:
raise HTTPException(status.HTTP_400_BAD_REQUEST)
# Create User
new_user.admin = db_entry.admin
new_user.password = hash_password(new_user.password)
db.users.create(session, new_user.dict())
# DeleteToken
background_tasks.add_task(
create_user_event, "Sign-up Token Used", f"New User {new_user.full_name}", session=session
)
db.sign_ups.delete(session, token)
@admin_router.delete("/{token}")
async def delete_token(token: str, session: Session = Depends(generate_session)):
""" Removed a token from the database """
db.sign_ups.delete(session, token)