diff --git a/api/controllers/admin/__init__.py b/api/controllers/admin/__init__.py index 90a18a07d0..89a4e5183f 100644 --- a/api/controllers/admin/__init__.py +++ b/api/controllers/admin/__init__.py @@ -6,4 +6,5 @@ bp = Blueprint("admin_api", __name__, url_prefix="/admin") api = ExternalApi(bp) from .auth import login -from .stats import stats \ No newline at end of file +from .stats import stats +from .students import students diff --git a/api/controllers/admin/auth/login.py b/api/controllers/admin/auth/login.py index 797932bbf0..35a10e076a 100644 --- a/api/controllers/admin/auth/login.py +++ b/api/controllers/admin/auth/login.py @@ -8,7 +8,7 @@ class SendVerificationCodeApi(Resource): """Send verification code to admin's phone number. --- tags: - - admin + - admin/auth summary: Send Verification Code description: Sends a verification code to the provided admin phone number for authentication parameters: @@ -46,7 +46,7 @@ class LoginApi(Resource): """Admin login with phone number and verification code. --- tags: - - admin + - admin/auth summary: Admin Login description: Authenticates an admin using phone number and verification code parameters: @@ -100,7 +100,7 @@ class LogoutApi(Resource): """Admin logout. --- tags: - - admin + - admin/auth summary: Admin Logout description: Logs out the authenticated admin and invalidates the JWT token security: @@ -118,7 +118,47 @@ class LogoutApi(Resource): """ pass +class RefreshTokenApi(Resource): + def post(self): + """Refresh authentication token. + --- + tags: + - admin/auth + summary: Refresh Token + description: Refreshes an access token using a valid refresh token + security: + - ApiKeyAuth: [] + parameters: + - in: body + name: body + required: true + schema: + type: object + required: + - refresh_token + properties: + refresh_token: + type: string + description: The refresh token provided in the request + responses: + 200: + description: Successfully refreshed token + schema: + type: object + properties: + result: + type: string + example: "success" + data: + type: object + description: New token pair data + 401: + description: Unauthorized, invalid or missing token + """ + pass + # Register the resources api.add_resource(SendVerificationCodeApi, '/auth/send-code') api.add_resource(LoginApi, '/auth/login') -api.add_resource(LogoutApi, '/auth/logout') \ No newline at end of file +api.add_resource(LogoutApi, '/auth/logout') +api.add_resource(RefreshTokenApi, '/auth/refresh-token') \ No newline at end of file diff --git a/api/controllers/admin/stats/stats.py b/api/controllers/admin/stats/stats.py index b885c13705..d98d9f31ed 100644 --- a/api/controllers/admin/stats/stats.py +++ b/api/controllers/admin/stats/stats.py @@ -8,7 +8,7 @@ class RiskStats(Resource): """Get risk level statistics. --- tags: - - admin + - admin/stats summary: Get risk level user counts description: Get counts of users at different risk levels and their changes security: @@ -54,7 +54,7 @@ class UserStats(Resource): """Get daily user statistics. --- tags: - - admin + - admin/stats summary: Get daily active and new user counts description: Get statistics of daily active users and new users security: @@ -102,7 +102,7 @@ class ConversationStats(Resource): """Get daily conversation statistics. --- tags: - - admin + - admin/stats summary: Get daily conversation counts and averages description: Get statistics of daily total conversations and average conversations per user security: diff --git a/api/controllers/admin/students/students.py b/api/controllers/admin/students/students.py new file mode 100644 index 0000000000..dc8ed7e1a8 --- /dev/null +++ b/api/controllers/admin/students/students.py @@ -0,0 +1,389 @@ +from flask import Blueprint +from flask_restful import Api, Resource # type: ignore + +from controllers.admin import api + +class StudentList(Resource): + def get(self): + """Get student list with filters. + --- + tags: + - admin/students + summary: Get filtered student list + description: Get list of students with various filter options + security: + - ApiKeyAuth: [] + parameters: + - name: risk_level + in: query + type: string + enum: [high, medium, low] + description: Filter by risk level + - name: last_chat_after + in: query + type: string + format: date + description: Filter by last conversation date + - name: topics + in: query + type: array + items: + type: string + description: Filter by conversation topics + - name: is_anonymous + in: query + type: boolean + description: Filter anonymous users + - name: page + in: query + type: integer + default: 1 + description: Page number + - name: per_page + in: query + type: integer + default: 20 + description: Items per page + responses: + 200: + description: Student list retrieved successfully + schema: + type: object + properties: + total: + type: integer + description: Total number of students matching filters + students: + type: array + items: + type: object + properties: + id: + type: string + email: + type: string + first_chat_at: + type: string + format: date-time + last_chat_at: + type: string + format: date-time + total_conversations: + type: integer + active_days: + type: integer + topics: + type: array + items: + type: string + risk_level: + type: string + enum: [high, medium, low] + 401: + description: Invalid or missing API key + 400: + description: Invalid filter parameters + """ + pass + +class StudentConversation(Resource): + def get(self, student_id): + """Get student's conversation history. + --- + tags: + - admin/students + summary: Get student conversation history + description: Get complete conversation history for a specific student + security: + - ApiKeyAuth: [] + parameters: + - name: student_id + in: path + type: string + required: true + description: ID of the student + - name: start_time + in: query + type: string + format: date-time + description: Filter conversations after this time + - name: end_time + in: query + type: string + format: date-time + description: Filter conversations before this time + - name: page + in: query + type: integer + default: 1 + description: Page number + - name: per_page + in: query + type: integer + default: 50 + description: Conversations per page + responses: + 200: + description: Conversation history retrieved successfully + schema: + type: object + properties: + total: + type: integer + conversations: + type: array + items: + type: object + properties: + timestamp: + type: string + format: date-time + role: + type: string + enum: [user, assistant] + content: + type: string + 401: + description: Invalid or missing API key + 404: + description: Student not found + """ + pass + +class StudentAnalysis(Resource): + def get(self, student_id): + """Get AI analysis and intervention suggestions. + --- + tags: + - admin/students + summary: Get AI analysis for student + description: Get AI generated analysis, summary and intervention suggestions based on conversation history + security: + - ApiKeyAuth: [] + parameters: + - name: student_id + in: path + type: string + required: true + description: ID of the student + responses: + 200: + description: Analysis retrieved successfully + schema: + type: object + properties: + summary: + type: string + description: Summary of conversation content and key points + analysis: + type: string + description: Psychological analysis from professional perspective + suggestions: + type: string + description: Intervention suggestions for counselors + last_updated: + type: string + format: date-time + 401: + description: Invalid or missing API key + 404: + description: Student not found or no analysis available + """ + pass + +class StudentStatus(Resource): + def put(self, student_id): + """Update student follow-up status. + --- + tags: + - admin/students + summary: Update student status + description: Update the follow-up status of a student + security: + - ApiKeyAuth: [] + parameters: + - name: student_id + in: path + type: string + required: true + description: ID of the student + - name: body + in: body + required: true + schema: + type: object + required: + - status + properties: + status: + type: string + enum: [to_follow, following, resolved] + description: | + Follow-up status: + * to_follow - Needs follow-up + * following - Currently following up + * resolved - Case resolved + responses: + 200: + description: Status updated successfully + schema: + type: object + properties: + success: + type: boolean + example: true + updated_at: + type: string + format: date-time + 401: + description: Invalid or missing API key + 404: + description: Student not found + 400: + description: Invalid status value + """ + pass + + def get(self, student_id): + """Get student follow-up status history. + --- + tags: + - admin/students + summary: Get status history + description: Get the history of status changes for a student + security: + - ApiKeyAuth: [] + parameters: + - name: student_id + in: path + type: string + required: true + description: ID of the student + responses: + 200: + description: Status history retrieved successfully + schema: + type: object + properties: + current_status: + type: string + enum: [to_follow, following, resolved] + history: + type: array + items: + type: object + properties: + status: + type: string + enum: [to_follow, following, resolved] + changed_at: + type: string + format: date-time + changed_by: + type: string + description: Email of admin who made the change + 401: + description: Invalid or missing API key + 404: + description: Student not found + """ + pass + +class StudentNote(Resource): + def put(self, student_id): + """Update student follow-up note. + --- + tags: + - admin/students + summary: Update student note + description: Update the follow-up note for a student (max 1000 characters) + security: + - ApiKeyAuth: [] + parameters: + - name: student_id + in: path + type: string + required: true + description: ID of the student + - name: body + in: body + required: true + schema: + type: object + required: + - note + properties: + note: + type: string + maxLength: 1000 + description: Follow-up note content + responses: + 200: + description: Note updated successfully + schema: + type: object + properties: + success: + type: boolean + example: true + updated_at: + type: string + format: date-time + 401: + description: Invalid or missing API key + 404: + description: Student not found + 400: + description: Note too long + """ + pass + + def get(self, student_id): + """Get student follow-up note history. + --- + tags: + - admin/students + summary: Get note history + description: Get the history of note changes for a student + security: + - ApiKeyAuth: [] + parameters: + - name: student_id + in: path + type: string + required: true + description: ID of the student + responses: + 200: + description: Note history retrieved successfully + schema: + type: object + properties: + current_note: + type: string + history: + type: array + items: + type: object + properties: + note: + type: string + changed_at: + type: string + format: date-time + changed_by: + type: string + description: Email of admin who made the change + 401: + description: Invalid or missing API key + 404: + description: Student not found + """ + pass + +api.add_resource(StudentList, '/students') +api.add_resource(StudentConversation, '/students//conversation') +api.add_resource(StudentAnalysis, '/students//analysis') +api.add_resource(StudentStatus, '/students//status') +api.add_resource(StudentNote, '/students//note') + diff --git a/api/controllers/service_api/auth/login.py b/api/controllers/service_api/auth/login.py index e7ec285bc2..213dedf39c 100644 --- a/api/controllers/service_api/auth/login.py +++ b/api/controllers/service_api/auth/login.py @@ -31,7 +31,7 @@ class LogoutApi(Resource): """Logout user. --- tags: - - user-end + - user/auth summary: Logout User description: Logs out the authenticated user and invalidates the session security: @@ -61,7 +61,7 @@ class EmailCodeLoginSendEmailApi(Resource): """Send email code for login. --- tags: - - user-end + - user/auth summary: Email Code Login Email Sending description: Sends an email with a verification code for login parameters: @@ -131,7 +131,7 @@ class EmailCodeLoginApi(Resource): """Login using email code. --- tags: - - user-end + - user/auth summary: Email Code Login description: Allows the user to login using a verification code and token sent via email parameters: @@ -222,7 +222,7 @@ class RefreshTokenApi(Resource): """Refresh authentication token. --- tags: - - user-end + - user/auth summary: Refresh Token description: Refreshes an access token using a valid refresh token security: