openapi: 3.0.0 servers: - url: /api/v1 - url: https://odyssey.wancat.cc/api/v1 - url: http://localhost:3000/api/v1 info: description: Linux Odyssey API version: '1.0.0' title: Session API contact: email: wancat@wancat.cc license: name: Apache 2.0 url: 'http://www.apache.org/licenses/LICENSE-2.0.html' tags: - name: admins description: Secured Admin-only calls - name: developers description: Operations available to regular developers paths: /sessions: get: tags: - signed-in summary: list existing sessions of current user security: - cookieAuth: [] parameters: - in: query name: quest_id description: find sessions by quest id schema: type: string - in: query name: status description: find sessions by status schema: type: string enum: [active, finished, inactive] responses: '200': description: list of existing session content: application/json: schema: type: array items: $ref: '#/components/schemas/SessionSummary' post: summary: create a new session for current user tags: - signed-in security: - cookieAuth: [] requestBody: description: session data content: application/json: schema: type: object properties: quest_id: type: string example: helloworld responses: '201': description: session created content: application/json: schema: $ref: '#/components/schemas/Session' '400': description: Invalid input content: application/json: schema: type: object properties: message: type: string /sessions/active: post: summary: 'Get or create an active session.' tags: - signed-in description: 'This endpoint returns the latest active session for the user, or creates a new one if no active session exists.' requestBody: required: true content: application/json: schema: type: 'object' required: - quest_id properties: quest_id: type: 'string' description: 'The ID of the quest.' example: 'helloworld' responses: 200: description: 'Return a active session.' content: application/json: schema: $ref: '#/components/schemas/Session' 400: description: 'Bad Request. The request is invalid or malformed.' 500: description: 'Internal Server Error.' /sessions/{session_id}: get: tags: - signed-in summary: get a specific session of current user by ID security: - cookieAuth: [] parameters: - in: path name: session_id description: ID of the session to retrieve required: true schema: type: string format: objectId example: 64b7a3a3c182b4826dd1aaa1 responses: '200': description: the session content: application/json: schema: $ref: '#/components/schemas/Session' '404': description: cannot find specific session content: application/json: schema: type: object properties: message: type: string delete: tags: - signed-in summary: delete a specific session by ID security: - cookieAuth: [] parameters: - in: path name: session_id required: true schema: type: string format: objectId example: 64b7a3a3c182b4826dd1aaa1 responses: '204': description: Session successfully deleted '404': description: Session not found content: application/json: schema: type: object properties: message: type: string example: 'Session not found.' '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string example: 'Unauthorized.' /auth/register: post: summary: Register a new user requestBody: required: true content: application/json: schema: type: object properties: username: type: string format: username example: alex email: type: string format: email example: alex@example.com password: type: string format: password example: 123456 responses: '201': description: User created headers: Set-Cookie: schema: type: string example: connect.sid=s%3Aq1Z; Path=/; HttpOnly; SameSite=Strict; Secure content: application/json: schema: type: object properties: token: type: string description: Access token example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... '400': description: Bad Request content: application/json: schema: type: object properties: message: type: string example: Missing username, email or password '409': description: Conflict content: application/json: schema: type: object properties: message: type: string example: User already exists /auth/register-from-session: post: summary: Register a new user from a session, for social login to pick a username security: - cookieAuth: [] requestBody: required: true content: application/json: schema: type: object properties: username: type: string format: username example: alex responses: '201': description: User created headers: Set-Cookie: schema: type: string example: connect.sid=s%3Aq1Z; Path=/; HttpOnly; SameSite=Strict; Secure /auth/login: post: summary: Log in a user requestBody: required: true content: application/json: schema: type: object properties: username: type: string format: username example: alex password: type: string format: password example: 123456 responses: '200': description: User logged in headers: Set-Cookie: schema: type: string example: connect.sid=s%3Aq1Z; Path=/; HttpOnly; SameSite=Strict; Secure content: application/json: schema: type: object properties: message: type: string example: Logged in successfully '400': description: Bad Request content: application/json: schema: type: object properties: message: type: string example: Missing username or password '401': description: Unauthorized content: application/json: schema: type: object properties: message: type: string example: Incorrect username or password /auth/logout: post: summary: Log out a user tags: - signed-in security: - cookieAuth: [] responses: '200': description: User logged out content: application/json: schema: type: object properties: message: type: string example: Logged out successfully /auth/check-username: get: summary: Check if the username is already taken parameters: - in: query name: username description: username to check required: true schema: type: string format: username example: alex - in: query name: email description: email to check required: true schema: type: string format: email example: alex@example.com responses: '200': description: Username / Email checking result content: application/json: schema: type: object properties: type: type: string example: Username is available available: type: boolean example: true '400': description: Bad Request content: application/json: schema: type: object properties: message: type: string example: Username is already taken /auth/available-methods: get: summary: Get available login methods responses: '200': description: Available login methods content: application/json: schema: type: object properties: local: type: boolean example: true github: type: boolean example: true google: type: boolean example: true facebook: type: boolean example: true /auth/check-session: get: summary: Check if the session is valid responses: '200': description: Result content: application/json: schema: type: object properties: loggedIn: type: boolean example: true /auth/google: get: summary: Initiate OAuth2 login with Google operationId: initiateOAuth security: - GoogleOAuth: [] responses: 302: description: Redirect to Google's OAuth 2.0 authorization endpoint 500: description: Internal Server Error /auth/google/callback: get: summary: OAuth2 callback endpoint operationId: oauthCallback parameters: - name: code in: query description: Authorization code from Google required: true schema: type: string responses: 200: description: Successful Operation 400: description: Bad Request 500: description: Internal Server Error /quests: get: summary: Get quests list responses: '200': description: Quests summary list content: application/json: schema: type: array items: $ref: '#/components/schemas/QuestSummary' /quests/{quest_id}: get: summary: get a quest's detail by name parameters: - in: path name: quest_id description: name of the quest to retrieve required: true schema: type: string responses: '200': description: the quest content: application/json: schema: $ref: '#/components/schemas/Quest' '404': description: cannot find specific quest content: application/json: schema: type: object properties: message: type: string /commands: post: summary: Record a command that was executed in a session tags: - signed-in security: - cookieAuth: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/Command' responses: '201': description: Command recorded successfully content: application/json: schema: $ref: '#/components/schemas/CommandResponse' '400': description: Invalid request body '401': description: Unauthorized components: schemas: User: type: object properties: _id: type: string format: objectId example: 64b7a3a3c182b4826dd1aaa1 username: type: string example: 'alex' email: type: string format: email Quest: type: object properties: _id: type: string example: helloworld title: type: string example: Hello World instruction: type: string example: 'In this quest, you need to learn how to use `ls` to list the file.' order: type: number QuestSummary: type: object properties: _id: type: string example: helloworld title: type: string example: Hello World order: type: number Session: type: object properties: _id: type: string format: objectId example: 64b7a3a3c182b4826dd1aaa1 user: $ref: '#/components/schemas/User' quest: $ref: '#/components/schemas/Quest' created_at: type: string format: date-time updated_at: type: string format: date-time finished_at: type: string format: date-time hints: type: array items: type: string example: '`ls -al` to list detail information of all files.' progress: type: string description: current stage id example: helloworld completed: type: array description: list of completed stage ids items: type: string example: helloworld SessionSummary: type: object properties: _id: type: string format: objectId example: 64b7a3a3c182b4826dd1aaa1 quest: $ref: '#/components/schemas/Quest' created_at: type: string format: date-time updated_at: type: string format: date-time finished_at: type: string format: date-time TreeNode: type: object properties: name: type: string display: type: boolean children: type: array items: $ref: '#/components/schemas/TreeNode' Command: type: object required: - pwd - command properties: pwd: type: string example: '/root' description: The current working directory command: type: string example: 'ls -al /' description: The command that was executed output: type: string description: The output of the command error: type: string description: The error message of the command CommandResponse: type: object properties: responses: type: array items: $ref: '#/components/schemas/CommandResponseItem' hints: type: array items: type: string example: '`ls -al` to list detail information of all files.' end: type: boolean description: Whether the session has ended CommandResponseItem: type: object required: - type - content properties: type: type: string enum: [narrative, dialogue] content: type: array items: type: string example: 'You have completed the quest!' color: type: string enum: [red, green, blue, yellow, purple, cyan, white, gray, black] speaker: type: string example: 'Unix Spirit' securitySchemes: cookieAuth: type: apiKey in: cookie name: connect.sid GoogleOAuth: type: oauth2 flows: authorizationCode: authorizationUrl: https://accounts.google.com/o/oauth2/auth tokenUrl: https://accounts.google.com/o/oauth2/token scopes: # Define your scopes here openid: OpenID profile: User profile email: User email