diff --git a/backend/src/appointment/main.py b/backend/src/appointment/main.py index 53a22b5d7..362cec2de 100644 --- a/backend/src/appointment/main.py +++ b/backend/src/appointment/main.py @@ -121,6 +121,7 @@ def server(): from .routes import google from .routes import schedule from .routes import invite + from .routes import subscriber from .routes import zoom from .routes import webhooks @@ -189,6 +190,7 @@ async def catch_google_refresh_errors(request, exc): app.include_router(google.router, prefix="/google") app.include_router(schedule.router, prefix="/schedule") app.include_router(invite.router, prefix="/invite") + app.include_router(subscriber.router, prefix="/subscriber") app.include_router(webhooks.router, prefix="/webhooks") if os.getenv("ZOOM_API_ENABLED"): app.include_router(zoom.router, prefix="/zoom") diff --git a/backend/src/appointment/routes/subscriber.py b/backend/src/appointment/routes/subscriber.py new file mode 100644 index 000000000..3cbaee8f6 --- /dev/null +++ b/backend/src/appointment/routes/subscriber.py @@ -0,0 +1,32 @@ + +from fastapi import APIRouter, Depends + +from sqlalchemy.orm import Session + +from ..database import repo, schemas, models +from ..database.models import Subscriber +from ..dependencies.auth import get_admin_subscriber +from ..dependencies.database import get_db + +from ..exceptions import validation + +router = APIRouter() + + +@router.get('/', response_model=list[schemas.Subscriber]) +def get_all_subscriber(db: Session = Depends(get_db), admin: Subscriber = Depends(get_admin_subscriber)): + """List all existing invites, needs admin permissions""" + return db.query(models.Subscriber).all() + + +@router.put("/disable/{email}") +def disable_subscriber(email: str, db: Session = Depends(get_db), admin: Subscriber = Depends(get_admin_subscriber)): + """endpoint to disable a subscriber by email, needs admin permissions""" + raise NotImplementedError + + subscriber = repo.subscriber.get_by_email(db, email) + if not subscriber: + raise validation.SubscriberNotFoundException() + # TODO: CAUTION! This actually deletes the subscriber. We might want to only disable them. + # This needs an active flag on the subscribers model. + return repo.subscriber.delete(db, subscriber) diff --git a/frontend/src/router.js b/frontend/src/router.js index 254fea0fe..43012c17a 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -14,6 +14,8 @@ const AppointmentsView = defineAsyncComponent(() => import('@/views/Appointments const SettingsView = defineAsyncComponent(() => import('@/views/SettingsView')); const ProfileView = defineAsyncComponent(() => import('@/views/ProfileView')); const LegalView = defineAsyncComponent(() => import('@/views/LegalView')); +const InvitePanelView = defineAsyncComponent(() => import('@/views/InvitePanelView')); +const SubscriberPanelView = defineAsyncComponent(() => import('@/views/SubscriberPanelView')); /** * Defined routes for Thunderbird Appointment @@ -93,7 +95,12 @@ const routes = [ { path: '/admin/invites', name: 'admin-invite-panel', - component: () => import('@/views/InvitePanelView.vue'), + component: InvitePanelView, + }, + { + path: '/admin/subscribers', + name: 'admin-subscriber-panel', + component: SubscriberPanelView, }, ]; diff --git a/frontend/src/views/SubscriberPanelView.vue b/frontend/src/views/SubscriberPanelView.vue new file mode 100644 index 000000000..faf89f632 --- /dev/null +++ b/frontend/src/views/SubscriberPanelView.vue @@ -0,0 +1,125 @@ + + +