add ResourceType endpoints

This commit is contained in:
Jonathan Griffin 2025-04-15 10:33:39 +02:00
parent cd70633d1f
commit 59a7206161

View file

@ -4,7 +4,7 @@ import uuid
from typing import Optional from typing import Optional
from decouple import config from decouple import config
from fastapi import Depends, HTTPException, Header, Query, Response from fastapi import Depends, HTTPException, Header, Query, Response, Request
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@ -31,12 +31,11 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
@public_app.post("/token") @public_app.post("/token")
async def login(host: str = Header(..., alias="Host"), form_data: OAuth2PasswordRequestForm = Depends()): async def login(host: str = Header(..., alias="Host"), form_data: OAuth2PasswordRequestForm = Depends()):
subdomain = host.split(".")[0] subdomain = host.split(".")[0]
# Missing authentication part, to add # Missing authentication part, to add
if form_data.username != config("SCIM_USER") or form_data.password != config("SCIM_PASSWORD"): if form_data.username != config("SCIM_USER") or form_data.password != config("SCIM_PASSWORD"):
raise HTTPException(status_code=401, detail="Invalid credentials") raise HTTPException(status_code=401, detail="Invalid credentials")
subdomain = "Openreplay EE"
tenant = tenants.get_by_name(subdomain) tenant = tenants.get_by_name(subdomain)
access_token, refresh_token = create_tokens(tenant_id=tenant["tenantId"]) access_token, refresh_token = create_tokens(tenant_id=tenant["tenantId"])
@ -49,7 +48,71 @@ async def refresh_token(r: RefreshRequest):
payload = verify_refresh_token(r.refresh_token) payload = verify_refresh_token(r.refresh_token)
new_access_token, _ = create_tokens(tenant_id=payload["tenant_id"]) new_access_token, _ = create_tokens(tenant_id=payload["tenant_id"])
return {"access_token": new_access_token, "token_type": "Bearer"} return {"access_token": new_access_token, "token_type": "bearer"}
RESOURCE_TYPE_IDS_TO_RESOURCE_TYPE_DETAILS = {
"User": {
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:ResourceType"],
"id": "User",
"name": "User",
"endpoint": "/Users",
"description": "User account",
"schema": "urn:ietf:params:scim:schemas:core:2.0:User",
}
}
def _not_found_error_response(resource_id: str):
return JSONResponse(
status_code=404,
content={
"schemas": ["urn:ietf:params:scim:api:messages:2.0:Error"],
"detail": f"Resource {resource_id} not found",
"status": "404",
}
)
@public_app.get("/ResourceTypes", dependencies=[Depends(auth_required)])
async def get_resource_types(r: Request):
return JSONResponse(
status_code=200,
content={
"totalResults": len(RESOURCE_TYPE_IDS_TO_RESOURCE_TYPE_DETAILS),
"itemsPerPage": len(RESOURCE_TYPE_IDS_TO_RESOURCE_TYPE_DETAILS),
"startIndex": 1,
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"Resources": sorted(
{
**value,
"meta": {
"location": str(r.url_for("get_resource_type", resource_id=value["id"])),
"resourceType": "ResourceType",
}
}
for value in RESOURCE_TYPE_IDS_TO_RESOURCE_TYPE_DETAILS.values()
),
},
)
@public_app.get("/ResourceTypes/{resource_id}", dependencies=[Depends(auth_required)])
async def get_resource_type(r: Request, resource_id: str):
if resource_id not in RESOURCE_TYPE_IDS_TO_RESOURCE_TYPE_DETAILS:
return _not_found_error_response(resource_id)
content = {
**RESOURCE_TYPE_IDS_TO_RESOURCE_TYPE_DETAILS[resource_id],
"meta": {
"location": str(r.url),
"resourceType": "ResourceType",
}
}
return JSONResponse(
status_code=200,
content=content,
)
""" """
User endpoints User endpoints
@ -104,7 +167,7 @@ async def get_users(
if email: if email:
email = email.split(" ")[2].strip('"') email = email.split(" ")[2].strip('"')
result_users = users.get_users_paginated(start_index, count, email) result_users = users.get_users_paginated(start_index, count, email)
serialized_users = [] serialized_users = []
for user in result_users: for user in result_users:
serialized_users.append( serialized_users.append(
@ -168,7 +231,7 @@ async def create_user(r: UserRequest):
tenant_id = 1 tenant_id = 1
existing_user = users.get_by_email_only(r.userName) existing_user = users.get_by_email_only(r.userName)
deleted_user = users.get_deleted_user_by_email(r.userName) deleted_user = users.get_deleted_user_by_email(r.userName)
if existing_user: if existing_user:
return JSONResponse( return JSONResponse(
status_code = 409, status_code = 409,
@ -205,7 +268,7 @@ async def create_user(r: UserRequest):
) )
return JSONResponse(status_code=201, content=res.model_dump(mode='json')) return JSONResponse(status_code=201, content=res.model_dump(mode='json'))
@public_app.put("/Users/{user_id}", dependencies=[Depends(auth_required)]) @public_app.put("/Users/{user_id}", dependencies=[Depends(auth_required)])
def update_user(user_id: str, r: UserRequest): def update_user(user_id: str, r: UserRequest):
@ -239,7 +302,7 @@ def update_user(user_id: str, r: UserRequest):
active = r.active, # ignore for now, since, can't insert actual timestamp active = r.active, # ignore for now, since, can't insert actual timestamp
groups = [], # ignore groups = [], # ignore
) )
return JSONResponse(status_code=201, content=res.model_dump(mode='json')) return JSONResponse(status_code=201, content=res.model_dump(mode='json'))
except Exception as e: except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) raise HTTPException(status_code=500, detail=str(e))
@ -266,7 +329,7 @@ def delete_user(user_uuid: str):
user = users.get_by_uuid(user_uuid, tenant_id) user = users.get_by_uuid(user_uuid, tenant_id)
if not user: if not user:
raise HTTPException(status_code=404, detail="User not found") raise HTTPException(status_code=404, detail="User not found")
users.__hard_delete_user_uuid(user_uuid) users.__hard_delete_user_uuid(user_uuid)
return Response(status_code=204, content="") return Response(status_code=204, content="")
@ -393,7 +456,7 @@ def update_put_group(group_id: str, r: GroupRequest):
group = roles.get_role_by_group_id(tenant_id, group_id) group = roles.get_role_by_group_id(tenant_id, group_id)
if not group: if not group:
raise HTTPException(status_code=404, detail="Group not found") raise HTTPException(status_code=404, detail="Group not found")
if r.operations and r.operations[0].op == "replace" and r.operations[0].path is None: if r.operations and r.operations[0].op == "replace" and r.operations[0].path is None:
roles.update_group_name(tenant_id, group["data"]["groupId"], r.operations[0].value["displayName"]) roles.update_group_name(tenant_id, group["data"]["groupId"], r.operations[0].value["displayName"])
return Response(status_code=200, content="") return Response(status_code=200, content="")
@ -408,7 +471,7 @@ def update_put_group(group_id: str, r: GroupRequest):
"value": user["data"]["userId"], "value": user["data"]["userId"],
"display": user["name"] "display": user["name"]
}) })
return JSONResponse( return JSONResponse(
status_code=200, status_code=200,
content=GroupResponse( content=GroupResponse(