diff --git a/app.py b/app.py index dcb509d..cf0f80e 100644 --- a/app.py +++ b/app.py @@ -1,24 +1,28 @@ import io from typing import Any -from fastapi import FastAPI, status, Header, UploadFile +from fastapi import FastAPI, status, Header, UploadFile, Response from starlette.responses import StreamingResponse from fastapi.middleware.cors import CORSMiddleware from based import db import psycopg -from hashlib import sha256 from secrets import token_hex from minio import Minio -from minio.error import S3Error from minio.helpers import ObjectWriteResult from urllib3 import HTTPResponse +import uvicorn from dba import * from models import ( + AuthModel, ColumnsDefinitionList, + ErrorResponseDefinition, ItemDeletionDefinitionList, ItemsFieldSelectorList, + TableDefinition, + TableListDefinition, UserDefinition, ) +from secutils import hash_password from utils import ( check_if_admin_access_token, parse_columns_from_definition, @@ -52,14 +56,27 @@ app.add_middleware( ) +@app.post("/api/getAccessToken") +async def getAccessToken(userData: AuthModel): + user = check_user(connector, userData.username, userData.password) + if not user: + return {"error": "Wrong username or password"} + + return {"access_token": user.access_token} + + @app.get("/api/listTables") -async def listTables(access_token: str | None = Header(default=None)): +async def listTables( + response: Response, + access_token: str | None = Header(default=None), +) -> TableListDefinition | ErrorResponseDefinition: is_admin = check_if_admin_access_token(connector, access_token) if not is_admin: - return {"error": "Not allowed"} + return ErrorResponseDefinition(error="Not allowed") - tables = connector.tables() - return tables + return TableListDefinition( + tables=[TableDefinition.parse_obj(table) for table in connector.tables()] + ) @app.post("/api/createTable/{tableName}") @@ -160,14 +177,11 @@ async def items( if column not in allowedColumns: return {"error": "Not allowed"} - print(columnsNames) - print(selector) - table_items = connector.selectFromTable( tableName, selector.fields if selector.fields else ["*"] ) - return table_items + return {"items": table_items} @app.post("/items/{tableName}/+") @@ -210,6 +224,49 @@ async def itemsCreate( return {"ok": True} +@app.post("/items/{tableName}/*") +async def itemsUpdate( + tableName: str, + item: dict[str, str], + oldItem: dict[str, str], + access_token: str | None = Header(default=None), +): + table_info = connector.getTable(tableName) + if not table_info: + return {"error": "Not found"} + + is_admin = check_if_admin_access_token(connector, access_token) + if table_info["system"] and not is_admin: + return {"error": "Not allowed"} + + user, group = get_user_by_access_token(connector, access_token) + if not is_admin: + allowedColumns = get_allowed_columns_for_group( + connector, tableName, group.id if group else -1 + ) + if not allowedColumns: + return {"error": "Not allowed"} + elif len(allowedColumns) == 1 and allowedColumns[0] == "*": + pass + else: + for column in item: + if column not in allowedColumns: + return {"error": "Not allowed"} + + try: + connector.updateDataInTable( + tableName, + [ColumnUpdate(column=c, value=item[c]) for c in item], + [ColumnCondition(column=c, value=oldItem[c]) for c in oldItem], + ) + except psycopg.errors.UndefinedColumn: + return {"error": "Column not found"} + except Exception as e: + return {"error": str(e)} + + return {"ok": True} + + @app.post("/items/{tableName}/-") async def itemsDelete( tableName: str, @@ -300,3 +357,7 @@ async def createAsset( if not create_asset(connector, filename, "", str(result.version_id)): return {"error": "Failed to create asset"} return {"ok": True, "fid": result.version_id} + + +if __name__ == "__main__": + uvicorn.run(app, host="0.0.0.0", port=8000)