What is a lot of fucking work!
This commit is contained in:
parent
85c07ed4f3
commit
3414b5c334
8 changed files with 586 additions and 216 deletions
549
app.py
549
app.py
|
|
@ -1,7 +1,7 @@
|
|||
import io
|
||||
from typing import Any
|
||||
from fastapi import FastAPI, status, Header, UploadFile, Response
|
||||
from starlette.responses import StreamingResponse
|
||||
from starlette.responses import StreamingResponse, JSONResponse
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from based import db
|
||||
import psycopg
|
||||
|
|
@ -14,13 +14,16 @@ import uvicorn
|
|||
from dba import *
|
||||
from models import (
|
||||
AuthModel,
|
||||
ColumnsDefinitionList,
|
||||
ErrorResponseDefinition,
|
||||
ItemDeletionDefinitionList,
|
||||
ColumnConditionCompat,
|
||||
CreateUserDefinition,
|
||||
ItemsFieldSelectorList,
|
||||
TableDefinition,
|
||||
TableListDefinition,
|
||||
UserDefinition,
|
||||
UserUpdateDefinition,
|
||||
OkResponse,
|
||||
ErrorResponse,
|
||||
AccessTokenResponse,
|
||||
TableItemsResponse,
|
||||
CreateAssetResponse,
|
||||
)
|
||||
from utils import (
|
||||
check_if_admin_access_token,
|
||||
|
|
@ -45,7 +48,11 @@ if found:
|
|||
else:
|
||||
minioClient.make_bucket(BUCKET_NAME)
|
||||
|
||||
app = FastAPI()
|
||||
app = FastAPI(
|
||||
title="Tuuli API",
|
||||
description="Tuuli API for Tuuli frontend\n\nUse `c2316f9686e7a764688b8c1b4c60c5a088b07a3c23a2f6b7c25915a5118d7acc` as access token to test the API",
|
||||
version="0.1.0",
|
||||
)
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
|
|
@ -55,107 +62,275 @@ app.add_middleware(
|
|||
)
|
||||
|
||||
|
||||
@app.post("/api/getAccessToken")
|
||||
@app.post(
|
||||
"/api/getAccessToken",
|
||||
name="Get access token",
|
||||
responses={
|
||||
200: {"model": AccessTokenResponse, "description": "Successful response"},
|
||||
401: {"model": ErrorResponse, "description": "User not found"},
|
||||
},
|
||||
)
|
||||
async def getAccessToken(userData: AuthModel):
|
||||
user = check_user(connector, userData.username, userData.password)
|
||||
if not user:
|
||||
return {"error": "Wrong username or password"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Wrong username or password"),
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
)
|
||||
|
||||
return {"access_token": user.access_token}
|
||||
return AccessTokenResponse(access_token=user.access_token)
|
||||
|
||||
|
||||
@app.get("/api/listTables")
|
||||
@app.get(
|
||||
"/api/listTables",
|
||||
name="List tables",
|
||||
responses={
|
||||
200: {"model": list[TableDefinition], "description": "List of tables"},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires admin-level user access token",
|
||||
},
|
||||
},
|
||||
)
|
||||
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 ErrorResponseDefinition(error="Not allowed")
|
||||
|
||||
return TableListDefinition(
|
||||
tables=[TableDefinition.parse_obj(table) for table in connector.tables()]
|
||||
)
|
||||
|
||||
|
||||
@app.post("/api/createTable/{tableName}")
|
||||
async def createTable(
|
||||
tableName: str,
|
||||
columns: ColumnsDefinitionList,
|
||||
access_token: str | None = Header(default=None),
|
||||
):
|
||||
is_admin = check_if_admin_access_token(connector, access_token)
|
||||
if not is_admin:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"), status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
return [TableDefinition.parse_obj(table) for table in connector.tables()]
|
||||
|
||||
|
||||
@app.post(
|
||||
"/api/createTable/{tableName}",
|
||||
name="Create table",
|
||||
responses={
|
||||
200: {"model": OkResponse, "description": "Table created successfully"},
|
||||
400: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Some generic error happened during table creation",
|
||||
},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires admin-level user access token",
|
||||
},
|
||||
409: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Table with this name already exists",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def createTable(
|
||||
tableName: str,
|
||||
columns: list[str],
|
||||
access_token: str | None = Header(default=None),
|
||||
):
|
||||
"""
|
||||
Parameter `columns` should be a list of strings
|
||||
Each string should be in a following format:
|
||||
`column_name:column_type[:column_options]`
|
||||
|
||||
Where *column_type* should be one of the following:
|
||||
- serial
|
||||
- str
|
||||
- bool
|
||||
- datetime
|
||||
- float
|
||||
- int
|
||||
|
||||
Also *column_options* can be one of the following:
|
||||
- unique
|
||||
- default
|
||||
|
||||
Example:
|
||||
```json
|
||||
[
|
||||
"id:serial:primary",
|
||||
"name:str:unique",
|
||||
"description:str",
|
||||
"is_active:bool",
|
||||
"price:float",
|
||||
"quantity:int"
|
||||
]
|
||||
```
|
||||
|
||||
Notes:
|
||||
- you cannot use *unique* and *default* at the same time
|
||||
- in current implementation you cannot use *default*, because there is no way to
|
||||
specify default value
|
||||
"""
|
||||
|
||||
is_admin = check_if_admin_access_token(connector, access_token)
|
||||
if not is_admin:
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"), status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
try:
|
||||
columnsDefinition = parse_columns_from_definition(",".join(columns.columns))
|
||||
columnsDefinition = parse_columns_from_definition(",".join(columns))
|
||||
create_table(connector, tableName, columnsDefinition)
|
||||
except psycopg.errors.UniqueViolation:
|
||||
return {"error": "Username already exists"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Table already exists"),
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error=str(e)), status_code=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
return {"ok": True}
|
||||
return OkResponse()
|
||||
|
||||
|
||||
@app.post("/api/dropTable/{tableName}")
|
||||
@app.post(
|
||||
"/api/dropTable/{tableName}",
|
||||
name="Drop table",
|
||||
responses={
|
||||
200: {"model": OkResponse, "description": "Table dropped successfully"},
|
||||
400: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Some generic error happened during table creation",
|
||||
},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires admin-level user access token",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def dropTable(
|
||||
tableName: str,
|
||||
access_token: str | None = Header(default=None),
|
||||
):
|
||||
is_admin = check_if_admin_access_token(connector, access_token)
|
||||
if not is_admin:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"), status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
try:
|
||||
drop_table(connector, tableName)
|
||||
ok, e = drop_table(connector, tableName)
|
||||
if not ok:
|
||||
if e:
|
||||
raise e
|
||||
raise Exception("Unknown error")
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error=str(e)), status_code=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
return {"ok": True}
|
||||
return OkResponse()
|
||||
|
||||
|
||||
@app.post("/api/createUser")
|
||||
@app.post(
|
||||
"/api/createUser",
|
||||
name="Create user",
|
||||
responses={
|
||||
200: {"model": OkResponse, "description": "Table dropped successfully"},
|
||||
400: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Some generic error happened during user creation",
|
||||
},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires admin-level user access token",
|
||||
},
|
||||
409: {
|
||||
"model": ErrorResponse,
|
||||
"description": "User with this username already exists",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def createUser(
|
||||
user: UserDefinition,
|
||||
user: CreateUserDefinition,
|
||||
access_token: str | None = Header(default=None),
|
||||
):
|
||||
is_admin = check_if_admin_access_token(connector, access_token)
|
||||
if not is_admin:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"), status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
try:
|
||||
create_user(connector, user.username, user.password)
|
||||
ok, e = create_user(connector, user.username, user.password)
|
||||
if not ok:
|
||||
if e:
|
||||
raise e
|
||||
raise Exception("Unknown error")
|
||||
except psycopg.errors.UniqueViolation:
|
||||
return {"error": "Username already exists"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Username already exists"),
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error=str(e)), status_code=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
return {"ok": True}
|
||||
return OkResponse()
|
||||
|
||||
|
||||
@app.post("/api/updateUser")
|
||||
@app.post(
|
||||
"/api/updateUser",
|
||||
name="Update user",
|
||||
responses={
|
||||
200: {"model": OkResponse, "description": "Table dropped successfully"},
|
||||
400: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Some generic error happened during updating user",
|
||||
},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires admin-level user access token",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def updateUser(
|
||||
user: UserDefinition,
|
||||
user: UserUpdateDefinition,
|
||||
access_token: str | None = Header(default=None),
|
||||
):
|
||||
is_admin = check_if_admin_access_token(connector, access_token)
|
||||
if not is_admin:
|
||||
return {"error": "Not allowed"}
|
||||
|
||||
if not user.user_id or not user.password or not user.access_token:
|
||||
return {"error": "Malformed request"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"), status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
try:
|
||||
update_user(connector, user.user_id, user.password, user.access_token)
|
||||
ok, e = update_user(connector, user.user_id, user.password, user.access_token)
|
||||
if not ok:
|
||||
if e:
|
||||
raise e
|
||||
raise Exception("Unknown error")
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error=str(e)), status_code=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
return {"ok": True}
|
||||
return OkResponse()
|
||||
|
||||
|
||||
@app.post("/items/{tableName}")
|
||||
@app.post(
|
||||
"/items/{tableName}",
|
||||
name="Get items from table",
|
||||
responses={
|
||||
200: {"model": TableItemsResponse, "description": "Table items"},
|
||||
400: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Some generic error happened during getting table items",
|
||||
},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires user access token",
|
||||
},
|
||||
404: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Table not found",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def items(
|
||||
tableName: str,
|
||||
selector: ItemsFieldSelectorList,
|
||||
|
|
@ -163,11 +338,16 @@ async def items(
|
|||
):
|
||||
table_info = connector.getTable(tableName)
|
||||
if not table_info:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Table not found"),
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
is_admin = check_if_admin_access_token(connector, access_token)
|
||||
if table_info["system"] and not is_admin:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"), status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
columns = parse_columns_from_definition(table_info["columns"])
|
||||
columnsNames = set(column.name for column in columns)
|
||||
|
|
@ -175,47 +355,87 @@ async def items(
|
|||
if userSelectedColumns != ["*"]:
|
||||
for column in userSelectedColumns:
|
||||
if column not in columnsNames:
|
||||
return {"error": f"Column {column} not found on table {tableName}"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(
|
||||
error=f"Column {column} not found on table {tableName}"
|
||||
),
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
else:
|
||||
userSelectedColumns = columnsNames
|
||||
userSelectedColumns = list(columnsNames)
|
||||
|
||||
user, group = get_user_by_access_token(connector, access_token)
|
||||
if not user:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"), status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
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"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
elif len(allowedColumns) == 1 and allowedColumns[0] == "*":
|
||||
pass
|
||||
else:
|
||||
for column in userSelectedColumns:
|
||||
if column not in allowedColumns:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
table_items = connector.selectFromTable(
|
||||
tableName, selector.fields if selector.fields else ["*"]
|
||||
)
|
||||
|
||||
return {"items": table_items}
|
||||
return TableItemsResponse(items=table_items)
|
||||
|
||||
|
||||
@app.post("/items/{tableName}/+")
|
||||
@app.post(
|
||||
"/items/{tableName}/+",
|
||||
name="Create item",
|
||||
responses={
|
||||
200: {"model": OkResponse, "description": "Item created successfully"},
|
||||
400: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Some generic error happened during creating item",
|
||||
},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires user access token",
|
||||
},
|
||||
404: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Table or column not found",
|
||||
},
|
||||
409: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Unique constraint violation",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def itemsCreate(
|
||||
tableName: str,
|
||||
item: dict[str, str],
|
||||
item: dict[str, Any],
|
||||
access_token: str | None = Header(default=None),
|
||||
):
|
||||
table_info = connector.getTable(tableName)
|
||||
if not table_info:
|
||||
return {"error": "Not found"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Table not found"),
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
is_admin = check_if_admin_access_token(connector, access_token)
|
||||
if table_info["system"] and not is_admin:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"), status_code=status.HTTP_403_FORBIDDEN
|
||||
)
|
||||
|
||||
user, group = get_user_by_access_token(connector, access_token)
|
||||
if not is_admin:
|
||||
|
|
@ -223,27 +443,63 @@ async def itemsCreate(
|
|||
connector, tableName, group.id if group else -1
|
||||
)
|
||||
if not allowedColumns:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
elif len(allowedColumns) == 1 and allowedColumns[0] == "*":
|
||||
pass
|
||||
else:
|
||||
for column in item:
|
||||
if column not in allowedColumns:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
try:
|
||||
connector.insertIntoTable(tableName, item)
|
||||
except psycopg.errors.UndefinedColumn:
|
||||
return {"error": "Column not found"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Column not found"),
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
except psycopg.errors.UniqueViolation:
|
||||
return {"error": "Unique constraint violation"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Unique violation"),
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error=str(e)), status_code=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
return {"ok": True}
|
||||
return OkResponse()
|
||||
|
||||
|
||||
@app.post("/items/{tableName}/*")
|
||||
@app.post(
|
||||
"/items/{tableName}/*",
|
||||
name="Update item in table",
|
||||
responses={
|
||||
200: {"model": OkResponse, "description": "Item updated successfully"},
|
||||
400: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Some generic error happened during updating item",
|
||||
},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires user access token",
|
||||
},
|
||||
404: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Table or column not found",
|
||||
},
|
||||
409: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Unique constraint violation",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def itemsUpdate(
|
||||
tableName: str,
|
||||
item: dict[str, str],
|
||||
|
|
@ -252,11 +508,17 @@ async def itemsUpdate(
|
|||
):
|
||||
table_info = connector.getTable(tableName)
|
||||
if not table_info:
|
||||
return {"error": "Not found"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Table not found"),
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
is_admin = check_if_admin_access_token(connector, access_token)
|
||||
if table_info["system"] and not is_admin:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
user, group = get_user_by_access_token(connector, access_token)
|
||||
if not is_admin:
|
||||
|
|
@ -264,41 +526,84 @@ async def itemsUpdate(
|
|||
connector, tableName, group.id if group else -1
|
||||
)
|
||||
if not allowedColumns:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
elif len(allowedColumns) == 1 and allowedColumns[0] == "*":
|
||||
pass
|
||||
else:
|
||||
for column in item:
|
||||
if column not in allowedColumns:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
try:
|
||||
connector.updateDataInTable(
|
||||
tableName,
|
||||
[ColumnUpdate(column=c, value=item[c]) for c in item],
|
||||
[ColumnCondition(column=c, value=oldItem[c]) for c in oldItem],
|
||||
[
|
||||
ColumnCondition(column=c, operator="eq", value=oldItem[c])
|
||||
for c in oldItem
|
||||
],
|
||||
)
|
||||
except psycopg.errors.UniqueViolation:
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Unique violation"),
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
)
|
||||
except psycopg.errors.UndefinedColumn:
|
||||
return {"error": "Column not found"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Column not found"),
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error=str(e)), status_code=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
return {"ok": True}
|
||||
return OkResponse()
|
||||
|
||||
|
||||
@app.post("/items/{tableName}/-")
|
||||
@app.post(
|
||||
"/items/{tableName}/-",
|
||||
name="Delete item from table",
|
||||
responses={
|
||||
200: {"model": OkResponse, "description": "Item deleted successfully"},
|
||||
400: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Some generic error happened during deleting item",
|
||||
},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires user access token",
|
||||
},
|
||||
404: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Table or column not found",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def itemsDelete(
|
||||
tableName: str,
|
||||
deleteWhere: ItemDeletionDefinitionList,
|
||||
deleteWhere: list[ColumnConditionCompat],
|
||||
access_token: str | None = Header(default=None),
|
||||
):
|
||||
table_info = connector.getTable(tableName)
|
||||
if not table_info:
|
||||
return {"error": "Not found"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Table not found"),
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
|
||||
is_admin = check_if_admin_access_token(connector, access_token)
|
||||
if table_info["system"] and not is_admin:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
user, group = get_user_by_access_token(connector, access_token)
|
||||
if not is_admin:
|
||||
|
|
@ -306,27 +611,44 @@ async def itemsDelete(
|
|||
connector, tableName, group.id if group else -1
|
||||
)
|
||||
if not allowedColumns:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
elif len(allowedColumns) == 1 and allowedColumns[0] == "*":
|
||||
pass
|
||||
else:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
try:
|
||||
connector.deleteFromTable(
|
||||
tableName,
|
||||
[
|
||||
ColumnCondition(where.name, where.value, where.isString, where.isLike)
|
||||
for where in deleteWhere.defs
|
||||
],
|
||||
[ColumnCondition(dw.column, dw.operator, dw.value) for dw in deleteWhere],
|
||||
)
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error=str(e)), status_code=status.HTTP_400_BAD_REQUEST
|
||||
)
|
||||
|
||||
return {"ok": True}
|
||||
return OkResponse()
|
||||
|
||||
|
||||
@app.get("/assets/{fid}")
|
||||
@app.get(
|
||||
"/assets/{fid}",
|
||||
name="Get asset",
|
||||
responses={
|
||||
200: {
|
||||
"description": "Asset found",
|
||||
"content": {"application/octet-stream": {}},
|
||||
},
|
||||
404: {
|
||||
"description": "Asset not found",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def getAsset(fid: str, access_token: str | None = Header(default=None)):
|
||||
asset = get_asset(connector, access_token, fid)
|
||||
if not asset:
|
||||
|
|
@ -349,14 +671,38 @@ async def getAsset(fid: str, access_token: str | None = Header(default=None)):
|
|||
response.release_conn()
|
||||
|
||||
|
||||
@app.post("/assets/+")
|
||||
@app.post(
|
||||
"/assets/+",
|
||||
name="Put asset",
|
||||
responses={
|
||||
200: {
|
||||
"model": CreateAssetResponse,
|
||||
"description": "Asset created successfully",
|
||||
},
|
||||
400: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Some generic error happened during creating asset",
|
||||
},
|
||||
403: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Requesting this endpoint requires user access token",
|
||||
},
|
||||
500: {
|
||||
"model": ErrorResponse,
|
||||
"description": "Failed put asset into storage",
|
||||
},
|
||||
},
|
||||
)
|
||||
async def createAsset(
|
||||
asset: UploadFile,
|
||||
access_token: str | None = Header(default=None),
|
||||
):
|
||||
user, _ = get_user_by_access_token(connector, access_token)
|
||||
if not user:
|
||||
return {"error": "Not allowed"}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Not allowed"),
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
|
||||
filename = asset.filename
|
||||
if not filename:
|
||||
|
|
@ -372,10 +718,19 @@ async def createAsset(
|
|||
),
|
||||
length=asset.size,
|
||||
)
|
||||
if not result:
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Failed put asset into storage"),
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
)
|
||||
|
||||
if not create_asset(connector, filename, "", str(result.version_id)):
|
||||
return {"error": "Failed to create asset"}
|
||||
return {"ok": True, "fid": result.version_id}
|
||||
return JSONResponse(
|
||||
ErrorResponse(error="Failed to create asset"),
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
return CreateAssetResponse(fid=result.version_id)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue