-
Notifications
You must be signed in to change notification settings - Fork 0
Websockets #90
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Websockets #90
Changes from all commits
Commits
Show all changes
43 commits
Select commit
Hold shift + click to select a range
fa20849
style: line length
michael-pisman dc5ef91
fix: Corrected resource
michael-pisman dab954d
feat: Added member routes
michael-pisman 95b89d3
feat: Added routes to get resource permissions
michael-pisman ec059d9
fix: Fixed Poll Request schema
michael-pisman 74f4cf3
feat: Added policies routes
michael-pisman cf6a500
feat: Created separate dirrectories for versions
michael-pisman a82257d
feat: Added fastapi fastapi-versioning
michael-pisman 8f5ec84
revert: Removed fastapi-versioning
michael-pisman 1ff7832
feat: API versioning system
michael-pisman 0d28d1d
fix: Remove unused import statement in app.py
michael-pisman 4ab0ee8
test: Moved old tests to test_v1 folder
michael-pisman 731439d
fix: Disable default redoc in FastAPI application
michael-pisman b451ef2
refactor: Added ReDoc endpoints to the router
michael-pisman e17b0e0
refactor: Reordered v2 routes
michael-pisman cebe5bd
refactor: Reordered v1 api routes
michael-pisman ae4bf29
style: flake8
michael-pisman 92db5e7
feat: Add unique ID generation for API endpoints
michael-pisman 3912802
refactor: Replaced version specific function with one function for ge…
michael-pisman 0ef9831
style: Removed extra new lines
michael-pisman 886e583
refactor: Updated websocket authentication
michael-pisman 2006124
fix: Updated WebSocketManager
michael-pisman 12f255f
Added token based authentication for WebSockets
michael-pisman 68c9b7f
feat: Added websocket message schema
michael-pisman 6aa0d57
feat: Created websocket message parser
michael-pisman b498692
feat: Added websocket exceptions
michael-pisman 3126844
refactor: Specified active_user ContextVar type
michael-pisman 8b85dc2
refactor: Updated action parser
michael-pisman dcd8faf
refactor: Improved error handling
michael-pisman 9788101
style: Added comments
michael-pisman f59685d
refactor: Changed websocket_auth to return account
michael-pisman 54d3037
style: Added return type to action_parser
michael-pisman ca63e0a
feat: Added websocket actions
michael-pisman c66a2e5
refactor: Updated filter_arguments to use websocket actions
michael-pisman b14d205
feat: Add group actions to websocket.py
michael-pisman b3ff19d
refactor: Add HTTPException handling to WebSocket route
michael-pisman b0065cb
style: Remove unused import in websocket_manager.py
michael-pisman 7c4bf21
fix: Fixed websocket_auth to query non-expired tokens
michael-pisman ccba456
fix: create_workspace requires data of type BaseModel
michael-pisman 63b6f6a
refactor: Added success response for when action does not return a model
michael-pisman 6a81397
feat: Added group and member actions
michael-pisman 6a838a9
refactor: Updated workspace and group actions, removed member actions
michael-pisman 4c40899
feat: Add member and policy actions
michael-pisman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| from typing import Literal | ||
| from unipoll_api import dependencies | ||
| from . import WorkspaceActions, GroupActions, MembersActions, PolicyActions | ||
| from unipoll_api.schemas import WorkspaceSchemas, GroupSchemas, MemberSchemas | ||
| from unipoll_api.documents import ResourceID | ||
| from unipoll_api.exceptions.resource import APIException | ||
|
|
||
|
|
||
| # Workspace actions | ||
|
|
||
|
|
||
| async def get_workspaces(): | ||
| return await WorkspaceActions.get_workspaces() | ||
|
|
||
|
|
||
| async def create_workspace(name: str, description: str = ""): | ||
| data = WorkspaceSchemas.WorkspaceCreateInput(name=name, description=description) | ||
| return await WorkspaceActions.create_workspace(data) | ||
|
|
||
|
|
||
| async def get_workspace_info(workspace_id: ResourceID): | ||
| workspace = await dependencies.get_workspace(workspace_id) | ||
| return await WorkspaceActions.get_workspace(workspace, **args) | ||
|
|
||
|
|
||
| async def update_workspace_info(workspace_id: ResourceID, name: str, description: str = ""): | ||
| workspace = await dependencies.get_workspace(workspace_id) | ||
| data = WorkspaceSchemas.WorkspaceUpdateRequest(name=name, description=description) | ||
| return await WorkspaceActions.update_workspace(workspace, data) | ||
|
|
||
|
|
||
| async def delete_workspace(workspace_id: ResourceID): | ||
| workspace = await dependencies.get_workspace(workspace_id) | ||
| return await WorkspaceActions.delete_workspace(workspace) | ||
|
|
||
|
|
||
| async def get_workspace_members(workspace_id: ResourceID): | ||
| workspace = await dependencies.get_workspace(workspace_id) | ||
| return await MembersActions.get_members(workspace) | ||
|
|
||
|
|
||
| async def add_workspace_members(workspace_id: ResourceID, account_id_list: list[ResourceID]): | ||
| workspace = await dependencies.get_workspace(workspace_id) | ||
| return await MembersActions.add_members(workspace, account_id_list) | ||
|
|
||
|
|
||
| async def get_workspace_policies(workspace_id: ResourceID): | ||
| workspace = await dependencies.get_workspace(workspace_id) | ||
| return await PolicyActions.get_policies(resource=workspace) | ||
|
|
||
|
|
||
| # Group actions | ||
|
|
||
|
|
||
| async def get_groups(workspace_id: ResourceID): | ||
| workspace = await dependencies.get_workspace(workspace_id) | ||
| return await GroupActions.get_groups(workspace) | ||
|
|
||
|
|
||
| async def create_group(workspace_id: ResourceID, name: str, description: str = ""): | ||
| workspace = await dependencies.get_workspace(workspace_id) | ||
| # data = GroupSchemas.GroupCreateInput(name=name, description=description) | ||
| return await GroupActions.create_group(workspace, name, description) | ||
|
|
||
|
|
||
| async def get_group_info(group_id: ResourceID): | ||
| group = await dependencies.get_group(group_id) | ||
| return await GroupActions.get_group(group) | ||
|
|
||
|
|
||
| async def update_group_info(group_id: ResourceID, name: str, description: str = ""): | ||
| group = await dependencies.get_group(group_id) | ||
| data = GroupSchemas.GroupUpdateRequest(name=name, description=description) | ||
| return await GroupActions.update_group(group, data) | ||
|
|
||
|
|
||
| async def delete_group(group_id: ResourceID): | ||
| group = await dependencies.get_group(group_id) | ||
| return await GroupActions.delete_group(group) | ||
|
|
||
|
|
||
| async def get_group_members(group_id: ResourceID): | ||
| group = await dependencies.get_group(group_id) | ||
| return await MembersActions.get_members(group) | ||
|
|
||
|
|
||
| async def add_group_members(group_id: ResourceID, account_id_list: list[ResourceID]): | ||
| group = await dependencies.get_group(group_id) | ||
| return await MembersActions.add_members(group, account_id_list) | ||
|
|
||
|
|
||
| async def get_group_policies(group_id: ResourceID): | ||
| group = await dependencies.get_group(group_id) | ||
| return await PolicyActions.get_policies(resource=group) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| from fastapi import status | ||
| from unipoll_api.exceptions.resource import APIException | ||
|
|
||
|
|
||
| class AuthenticationError(APIException): | ||
| def __init__(self): | ||
| super().__init__(code=status.WS_1008_POLICY_VIOLATION, | ||
| detail="Invalid access token or authorization header") | ||
|
|
||
|
|
||
| class InvalidAction(APIException): | ||
| def __init__(self, action: str): | ||
| super().__init__(code=status.WS_1003_UNSUPPORTED_DATA, | ||
| detail=f'Action "{action}" not found') | ||
|
|
||
|
|
||
| class InvalidMessageData(APIException): | ||
| def __init__(self, action: str, valid_args: list[str], data: list[str]): | ||
| super().__init__(code=status.WS_1003_UNSUPPORTED_DATA, | ||
| detail=f'Invalid data for action "{action}".' + | ||
| f'Valid arguments are: {valid_args}.' + | ||
| f'You provided: {data}') | ||
|
|
||
|
|
||
| class ActionMissingRequiredArgs(APIException): | ||
| def __init__(self, action: str, required_args: list[str], provided_args: list[str]): | ||
| super().__init__(code=status.WS_1003_UNSUPPORTED_DATA, | ||
| detail=f"The action '{action}' requires arguments: {required_args}. " + | ||
| f"You provided: {provided_args}") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,48 +1,50 @@ | ||
| from fastapi import APIRouter, Depends | ||
| from unipoll_api.dependencies import set_active_user | ||
|
|
||
| # Impport endpoints defined in the routes directory | ||
| from . import account as AccountRoutes | ||
| from . import authentication as AuthenticationRoutes | ||
| from . import group as GroupRoutes | ||
| from . import poll as PollRoutes | ||
| from . import websocket as WebSocketRoutes | ||
| from . import workspace as WorkspaceRoutes | ||
|
|
||
| # Create main router | ||
| router: APIRouter = APIRouter() | ||
|
|
||
| # Add endpoints defined in the routes directory | ||
| router.include_router(WorkspaceRoutes.open_router, | ||
| prefix="/workspaces", | ||
| tags=["Workspaces"], | ||
| dependencies=[Depends(set_active_user)]) | ||
| router.include_router(WorkspaceRoutes.router, | ||
| prefix="/workspaces", | ||
| tags=["Workspaces"], | ||
| dependencies=[Depends(set_active_user)]) | ||
| router.include_router(GroupRoutes.open_router, | ||
| prefix="/groups", | ||
| tags=["Groups"], | ||
| dependencies=[Depends(set_active_user)]) | ||
| router.include_router(GroupRoutes.router, | ||
| prefix="/groups", | ||
| tags=["Groups"], | ||
| dependencies=[Depends(set_active_user)]) | ||
| router.include_router(PollRoutes.router, | ||
| prefix="/polls", | ||
| tags=["Polls"], | ||
| dependencies=[Depends(set_active_user)]) | ||
| router.include_router(WebSocketRoutes.router, | ||
| prefix="/ws", | ||
| tags=["WebSocket"]) | ||
| router.include_router(AccountRoutes.router, | ||
| prefix="/accounts", | ||
| tags=["Accounts"], | ||
| dependencies=[Depends(set_active_user)]) | ||
| router.include_router(AuthenticationRoutes.router, | ||
| prefix="/auth", | ||
| tags=["Authentication"]) | ||
| router.include_router(WebSocketRoutes.router, | ||
| prefix="/ws", | ||
| tags=["WebSocket"]) | ||
| from fastapi import APIRouter | ||
| from fastapi.routing import APIRoute | ||
| from unipoll_api.utils import api_versioning | ||
| from .v1 import router as v1_router | ||
| from .v2 import router as v2_router | ||
| from .swagger_docs import create_doc_router | ||
| from .websocket import router as websocket_router | ||
|
|
||
|
|
||
| # Function to generate unique operation IDs for different API versions | ||
| def generate_unique_id(version: int): | ||
| def func(route: APIRoute): | ||
| return f"api-v{version}-{route.tags[0]}-{route.name}" | ||
| return func | ||
|
|
||
|
|
||
| # Function to create API Router | ||
| def create_router(app, default_version): | ||
| # API Router that contains all of the endpoints | ||
| router = APIRouter() | ||
|
|
||
| # Dictionary of endpoints for each version of the API | ||
| endpoints = { | ||
| 1: v1_router, | ||
| 2: v2_router, | ||
| } | ||
|
|
||
| # Default API version | ||
| router.include_router(endpoints[default_version]) | ||
| router.include_router(websocket_router, prefix="/ws", tags=["WebSocket"]) | ||
|
|
||
| # Add API v1 endpoints to the main router | ||
| router.include_router(v1_router, | ||
| prefix="/v1", | ||
| generate_unique_id_function=generate_unique_id(1)) | ||
| # Add API v1 OpenAPI schemas for documentation | ||
| api_versioning.add_api(v1_router, version=1) | ||
|
|
||
| # Add API v2 endpoints to the main router | ||
| router.include_router(v2_router, | ||
| prefix="/v2", | ||
| generate_unique_id_function=generate_unique_id(2)) | ||
| # Add API v2 OpenAPI schemas for documentation | ||
| api_versioning.add_api(v2_router, version=2) | ||
|
|
||
| # Swagger Documentation Endpoints | ||
| router.include_router(create_doc_router(app, default_version)) | ||
|
|
||
| # Return the main router | ||
| return router |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| from fastapi import APIRouter | ||
| from fastapi.openapi.docs import ( | ||
| get_redoc_html, | ||
| get_swagger_ui_html, | ||
| get_swagger_ui_oauth2_redirect_html, | ||
| ) | ||
| from unipoll_api.utils import api_versioning | ||
|
|
||
|
|
||
| # Function to create router for documentation endpoints | ||
| def create_doc_router(app, default_version): | ||
| # Router for documentation endpoints | ||
| doc_router = APIRouter() | ||
|
|
||
| @doc_router.get("/v{version}/openapi.json", include_in_schema=False) | ||
| async def get_openapi_schema(version: int): | ||
| return api_versioning.openapi_schemas[version] | ||
|
|
||
| # Default Docs | ||
| @doc_router.get("/docs", include_in_schema=False) | ||
| async def default_swagger_ui_html(): | ||
| return get_swagger_ui_html( | ||
| openapi_url=f"/v{default_version}/openapi.json", | ||
| title=app.title + " - Swagger UI", | ||
| oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, | ||
| swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js", | ||
| swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css", | ||
| ) | ||
|
|
||
| # Versioned Docs | ||
| @doc_router.get("/v{version}/docs", include_in_schema=False) | ||
| async def versioned_swagger_ui_html(version: int): | ||
| return get_swagger_ui_html( | ||
| openapi_url=f"/v{version}/openapi.json", | ||
| title=app.title + " - Swagger UI", | ||
| oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, | ||
| swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js", | ||
| swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css", | ||
| ) | ||
|
|
||
| @doc_router.get(app.swagger_ui_oauth2_redirect_url, include_in_schema=False) | ||
| async def swagger_ui_redirect(): | ||
| return get_swagger_ui_oauth2_redirect_html() | ||
|
|
||
| # Default ReDoc | ||
| @doc_router.get("/redoc", include_in_schema=False) | ||
| async def default_redoc_html(): | ||
| return get_redoc_html( | ||
| openapi_url=f"/v{default_version}/openapi.json", | ||
| title=app.title + " - ReDoc", | ||
| redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js", | ||
| ) | ||
|
|
||
| # Versioned ReDoc | ||
| @doc_router.get("/v{version}/redoc", include_in_schema=False) | ||
| async def versioned_redoc_html(version: int): | ||
| return get_redoc_html( | ||
| openapi_url=f"/v{version}/openapi.json", | ||
| title=app.title + " - ReDoc", | ||
| redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js", | ||
| ) | ||
|
|
||
| return doc_router |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The variable 'args' is referenced but not defined in this function. This will result in a NameError at runtime.