groups WIP

This commit is contained in:
2025-07-29 20:22:14 +03:00
parent 2ef27a9137
commit c203a890dc
9 changed files with 155 additions and 26 deletions

3
.gitignore vendored
View File

@ -81,6 +81,9 @@ venv/
# .env # .env
.env .env
# data
data/
# testing # testing
test.py test.py
test.sql test.sql

Binary file not shown.

View File

@ -7,7 +7,7 @@ from api.models import User
from api.utils import get_current_user from api.utils import get_current_user
from settings.settings import load_settings, reset_settings, save_settings from settings.settings import load_settings, reset_settings, save_settings
general_router = APIRouter(prefix="/api", tags=["status"]) general_router = APIRouter(prefix="/api", tags=["general"])
@general_router.get('/ping') @general_router.get('/ping')

72
src/api/groups.py Normal file
View File

@ -0,0 +1,72 @@
from typing import Annotated
from fastapi import APIRouter, Depends, HTTPException, status
from psycopg2._psycopg import connection
import db.users as db
import settings.settings as settings
from api.models import User
from api.utils import get_current_user
from db.internal import get_db_connection
groups_router = APIRouter(prefix="/api/groups", tags=["groups"])
@groups_router.get("/my")
async def read_users_groups(current_user: Annotated[User, Depends(get_current_user)]):
return current_user
@groups_router.post("/user")
async def read_users_any_groups(
username: str,
conn: Annotated[connection, Depends(get_db_connection)],
current_user: Annotated[User, Depends(get_current_user)]
):
if current_user.role not in settings.settings.admin_roles:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Not allowed",
)
user = User()
user_data = db.get_user(conn, username)
if user_data is None:
return HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="No such user",
)
user.fill(user_data)
return user
@groups_router.post("/add")
async def add_group(
groupname: str,
conn: Annotated[connection, Depends(get_db_connection)],
current_user: Annotated[User, Depends(get_current_user)]
):
# TODO
pass
# if not settings.settings.allow_create_admins_by_admins:
# if current_user.role not in settings.settings.admin_roles:
# raise HTTPException(
# status_code=status.HTTP_403_FORBIDDEN,
# detail="Not allowed",
# )
# return db.create_user(conn, username, hashed_password, "admin")
@groups_router.post("/delete")
async def delete_user(
groupname: str,
conn: Annotated[connection, Depends(get_db_connection)],
current_user: Annotated[User, Depends(get_current_user)]
):
# TODO
pass
# if current_user.username == username or current_user.role in settings.settings.admin_roles:
# return db.delete_user(conn, groupname)
# else:
# raise HTTPException(
# status_code=status.HTTP_403_FORBIDDEN,
# detail="Not allowed",
# )

View File

@ -100,6 +100,21 @@ async def update_disabled(
detail="Not allowed", detail="Not allowed",
) )
@users_router.post("/update/role")
async def update_role(
username: str,
role: str,
conn: Annotated[connection, Depends(get_db_connection)],
current_user: Annotated[User, Depends(get_current_user)]
):
if current_user.role in settings.settings.admin_roles:
return db.update_user_role(conn, username, role)
else:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Not allowed",
)
@users_router.post("/update/username") @users_router.post("/update/username")
async def update_username( async def update_username(

View File

@ -1,8 +1,12 @@
import sys
from fastapi import FastAPI from fastapi import FastAPI
from loguru import logger
from api.anon import anon_router from api.anon import anon_router
from api.auth import auth_router from api.auth import auth_router
from api.general import general_router from api.general import general_router
from api.groups import groups_router
from api.users import users_router from api.users import users_router
from db.internal import connect_db, disconnect_db from db.internal import connect_db, disconnect_db
from settings import startup_settings from settings import startup_settings
@ -19,13 +23,24 @@ app = FastAPI(
def create_app(): def create_app():
logger.configure(
handlers=[
{
"sink": sys.stdout,
"level": startup_settings.log_level,
"format": "<level>{level}: {message}</level>",
}
]
)
app.add_event_handler("startup", connect_db) app.add_event_handler("startup", connect_db)
app.add_event_handler("startup", settings_up) app.add_event_handler("startup", settings_up)
app.include_router(general_router) app.include_router(general_router)
app.include_router(auth_router) app.include_router(auth_router)
app.include_router(users_router)
app.include_router(anon_router) app.include_router(anon_router)
app.include_router(users_router)
app.include_router(groups_router)
app.add_event_handler("shutdown", disconnect_db) app.add_event_handler("shutdown", disconnect_db)
app.add_event_handler("shutdown", settings_down) app.add_event_handler("shutdown", settings_down)

View File

@ -75,6 +75,40 @@ def check_user_disabled(
# user updates # user updates
def update_user_disabled(
conn: connection,
username: str,
disabled: bool
):
# if disabled = True => user is disabled
with conn.cursor() as cur:
cur.execute(
"""
update picrinth.users
set disabled = %s
where username = %s
""",
(disabled, username),
)
conn.commit()
def update_user_role(
conn: connection,
username: str,
role: str
):
with conn.cursor() as cur:
cur.execute(
"""
update picrinth.users
set role = %s
where username = %s
""",
(role, username),
)
conn.commit()
def update_user_username( def update_user_username(
conn: connection, conn: connection,
username: str, username: str,
@ -108,24 +142,6 @@ def update_user_password(
conn.commit() conn.commit()
def update_user_disabled(
conn: connection,
username: str,
disabled: bool
):
# if disabled = True -> user is disabled
with conn.cursor() as cur:
cur.execute(
"""
update picrinth.users
set disabled = %s
where username = %s
""",
(disabled, username),
)
conn.commit()
def update_user_last_seen( def update_user_last_seen(
conn: connection, conn: connection,
username: str username: str

View File

@ -20,3 +20,4 @@ access_token_expiration_time = int(config('access_token_expiration_time', defau
# other settings # other settings
swagger_enabled = str_to_bool(str(config('swagger_enabled', 'false'))) swagger_enabled = str_to_bool(str(config('swagger_enabled', 'false')))
log_level = str(config('log_level', default='INFO'))

View File

@ -5,17 +5,24 @@ CREATE TABLE picrinth.users (
"role" text not null default "user", "role" text not null default "user",
"disabled" bool not null, "disabled" bool not null,
groups_ids integer[] NULL, groups_ids integer[] NULL,
last_seen_at timestamp with time zone NULL, last_seen_at timestamp with time zone null,
created_at timestamp with time zone NULL, created_at timestamp with time zone null,
CONSTRAINT userid_pk PRIMARY KEY (id),
CONSTRAINT username_unique UNIQUE (username) CONSTRAINT username_unique UNIQUE (username)
); );
CREATE TABLE picrinth.groups ( CREATE TABLE picrinth.groups (
id serial not null, id serial not null,
groupname text not null, groupname text not null,
join_code text not null, invite_code text not null,
users_ids integer[] null,
created_at timestamp with time zone null, created_at timestamp with time zone null,
CONSTRAINT groupname_unique UNIQUE (username) CONSTRAINT groupname_unique UNIQUE (groupname)
);
create table picrinth.group_members (
username text,
groupname text,
joined_at timestamp with time zone null,
PRIMARY KEY (username, groupname)
FOREIGN KEY (username) REFERENCES users (username) on delete cascade on update cascade
FOREIGN KEY (groupname) REFERENCES groups (groupname) on delete cascade on update cascade
); );