# Mail Subscription API Documentation [TOC] ## Base URL ``` /api/v1 ``` ## Authentication This system uses **Django Session Authentication** combined with a **CSRF Token mechanism** for security. ### Login Validates LDAP credentials and, upon success, sets the authentication cookies. ``` POST /api/v1/auth/login/ ``` - Permission: `AllowAny` - Request Body ```json { "username": "b13902xxx", "password": "secret" } ``` - Response: `200 OK` ```json { "username": "b13902xxx", "is_staff": false } ``` - Response Headers ``` Set-Cookie: sessionid=abc123xyz...; HttpOnly; Path=/; SameSite=Lax; Secure Set-Cookie: csrftoken=def456uvw...; Path=/; SameSite=Lax; Secure ``` > :bookmark_tabs: **Note: CSRF token** > > Include the CSRF token in headers for all state-changing requests (`POST`, `PUT`, `DELETE`). The frontend must manually read the csrftoken value from the cookies and include it in the HTTP headers as `X-CSRFToken: ` > > ```python > import Cookies from 'js-cookie'; > const csrfToken = Cookies.get('csrftoken'); > ``` ### Check Session Used by the frontend upon page load/refresh to verify if the user's session is still active and to retrieve their role for rendering decisions. ``` GET /api/v1/auth/me/ ``` - Permission: `IsAuthenticated` - Response: `200 OK` ```json { "username": "b13902xxx", "is_admin": false } ``` - Error Response: `403 Forbidden` ### Logout ``` POST /api/v1/auth/logout/ ``` - Permission: `IsAuthenticated` - Request Headers: `X-CSRFToken: ` - Response: `205 Reset Content` > After calling this API, the backend will instruct the browser to clear the cookies. The frontend should then clear its own global state and redirect the user to the login page. --- ## User Endpoints for standard users to manage their own mailing list subscriptions. The backend automatically identifies the user via the **session cookie**. ### Get User Setting Retrieves the subscription status of all available aliases for the currently logged-in user. ``` GET /api/v1/user/subscriptions/ ``` - Permission: `IsAuthenticated` - Response: `200 OK` ```json [ { "alias_name": "workstation", "display_name": "工作站", "description": "工作站清理、重開機公告", "is_subscribed": true }, { "alias_name": "activities", "display_name": "系上活動", "description": "演講、交流", "is_subscribed": false }, { "alias_3": ... ... } ] ``` ### Update User Setting ``` PUT /api/v1/user/subscriptions/ ``` - Permission: `IsAuthenticated` - Request Headers: `X-CSRFToken: ` - Request Body ```json { "workstation": false, "activities": true, "alias_3": true, ... } ``` - Response: `200 OK` ```json { "status": "success", "message": "已收到訂閱狀態更新請求,將於 10 分鐘內生效" } ``` > :bookmark_tabs: **Note: Rate Limiting (Cooldown)** > This endpoint is protected by a rate limiter to prevent spam and LDAP sync overload. If a user calls this endpoint too frequently, the server will reject the request and return a `429 Too Many Requests` error. ## Admin Endpoints for administrators (users in the NASA mail group) to manage mailing list aliases and their subscribers. > :bookmark_tabs: **Note: Permissions** > All endpoints in this section require the permission (`is_admin=True`). If a standard user attempts to access these, the server will return a `403 Forbidden` response. ### Get All Aliases Retrieves a list of all existing aliases and their basic information. ``` GET /api/v1/admin/aliases/ ``` - Permission: `IsAdminUser` - Response: `200 OK` ```json [ { "alias_name": "workstation", "display_name": "工作站", "description": "工作站清理、重開機公告" }, { "alias_name": "activities", "display_name": "系上活動", "description": "演講、交流" } ] ``` ### Create Alias Creates a new mailing list alias. ``` POST /api/v1/admin/aliases/ ``` - Permission: `IsAdminUser` - Request Headers: `X-CSRFToken: ` - Request Body ```json { "alias_name": "new_alias", "display_name": "新群組", "description": "這是一個新建立的群組" } ``` - Response: `201 Created` ### Update Alias ``` PATCH /api/v1/admin/aliases// ``` - Permission: `IsAdminUser` - Request Headers: `X-CSRFToken: ` - Request body: 只需要傳遞想要更新的欄位即可: ```json { "display_name": "新工作站公告", "description": "更新後的工作站清理、重開機與維護公告" } ``` **Response `200 OK`** ```json { "alias_name": "workstation", "display_name": "新工作站公告", "description": "更新後的工作站清理、重開機與維護公告" } ``` **Possible Errors** - `400 Bad Request` — 欄位驗證失敗(例如 `display_name` 或 `description` 超過字數限制)。 ```json { "error": "Validation failed", "code": "VALIDATION_ERROR", "details": { "display_name": ["Ensure this field has no more than 255 characters."], "description": ["Ensure this field has no more than 500 characters."] } } ``` - `404 Not Found` — 指定的 alias 不存在。 ```json { "error": "The requested resource was not found.", "code": "NOT_FOUND" } ``` - `500 Internal Server Error` — 伺服器錯誤。 ### Delete Alias Deletes an entire mailing list alias. ``` DELETE /api/v1/admin/aliases// ``` - Permission: `IsAdminUser` - Request Headers: `X-CSRFToken: ` - Response: `204 No Content` ### Get Alias Subscribers Retrieves a list of all users currently subscribed to a specific alias. ``` GET /api/v1/admin/aliases//users/ ``` - Permission: `IsAdminUser` - Response: `200 OK` ```json [ "b13902001", "b13902002", "b13902003" ] ``` ### Add Subscriber to Alias Manually adds a specific user (by UID) to an alias. ``` POST /api/v1/admin/aliases//users/ ``` - Permission: `IsAdminUser` - Request Headers: `X-CSRFToken: ` - Request Body ```json { "uid": "b13902xxx" } ``` - Response: `200 OK` ### Remove Subscriber from Alias Manually removes a specific user from an alias. The user's UID is passed directly in the URL path. ``` DELETE /api/v1/admin/aliases//users// ``` - Permission: `IsAdminUser` - Request Headers: `X-CSRFToken: ` - Response: `204 No Content` ## Error Responses ### 400 Bad Request ```json { "error": "Validation failed", "code": "VALIDATION_ERROR", "details": { "alias_name": ["Alias name can only contain lowercase letters and numbers."], "uid": ["Ensure this field has exactly 9 characters."] } } ``` ### 401 Unauthorized ```json { "error": "Authentication credentials were not provided or CSRF verification failed.", "code": "NOT_AUTHENTICATED" } ``` ### 403 Forbidden ```json { "error": "You do not have permission to perform this action.", "code": "PERMISSION_DENIED" } ``` ### 404 Not Found ```json { "error": "The requested resource was not found.", "code": "NOT_FOUND" } ``` ### 409 Conflict ```json { "error": "Alias name already exists.", "code": "CONFLICT", "details": { "existing_alias": "workstation" } } ``` ### 429 Too Many Requests ```json { "error": "Request was throttled.", "code": "TOO_MANY_REQUESTS", "details": { "wait_seconds": 45 } } ``` ### 500 Internal Server Error ```json { "error": "An unexpected error occurred. Please contact the administrator.", "code": "INTERNAL_SERVER_ERROR" } ```