Swagger API documentation

This commit is contained in:
2024-12-09 19:06:50 +01:00
parent 9df62d037d
commit 4215bbf9c2
18 changed files with 1383 additions and 121 deletions

View File

@@ -1,3 +1,9 @@
/**
* @swagger
* tags:
* name: Account
* description: API to manage accounts
*/
import { Router, Request, Response } from "express";
import { Account } from "../models/user/account.model";
import { validateString } from "../scripts/validateHelper";
@@ -11,20 +17,38 @@ import { encryptString } from "../scripts/encryptScripts";
export const account = Router()
account.get("/", verifyToken, (req: Request, res: Response) => {
Account.findAll({
include: [ AccountRole ]
})
.then(accounts => {
res.status(200).json(accounts)
})
.catch(error => {
res.status(500).send()
})
})
// Login user
account.get("/account/login", async (req: Request, res: Response) => {
/**
* @swagger
* /accounts/login:
* get:
* summary: Start login process
* tags: [Account]
* parameters:
* - in: query
* name: username
* schema:
* type: string
* required: true
* description: Username
* - in: query
* name: password
* schema:
* type: string
* required: true
* description: User password
* responses:
* 200:
* description: Login successful
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/loginResponse'
* 401:
* description: Wrong credentials
* 500:
* description: Internal server error
*/
account.get("/login", async (req: Request, res: Response) => {
const encryptedPassword = encryptString(String(req.query.password))
try {
@@ -47,10 +71,7 @@ account.get("/account/login", async (req: Request, res: Response) => {
})
} else {
// Status: 401 Unauthorized
res.status(401).json({
code: 401,
message: "Unauthorized"
})
res.status(401).send()
}
} catch (e) {
res.status(500).send()
@@ -58,12 +79,35 @@ account.get("/account/login", async (req: Request, res: Response) => {
})
account.get("/account/data", verifyToken, async(req: Request, res: Response) => {
/**
* @swagger
* /accounts/account:
* get:
* summary: Get all data about an user account
* tags: [Account]
* security:
* - JWT: []
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/useraccount'
* 401:
* description: Unauthorized
* 500:
* description: Internal server error
*/
account.get("/account", verifyToken, async(req: Request, res: Response) => {
Account.findOne({
where: {
id: req["id"]
},
include: [ Address, AccountRole, Payment ]
include: [ Address, AccountRole, Payment ],
attributes: {
exclude: [ "accountRoleId" ]
}
})
.then(account => {
res.status(200).json(account)
@@ -74,7 +118,31 @@ account.get("/account/data", verifyToken, async(req: Request, res: Response) =>
})
// Creating a new user
/**
* @swagger
* /accounts/account:
* post:
* summary: Create a new user account
* tags: [Account]
* requestBody:
* description: Minimal user data body
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/minimalAccount'
* responses:
* 201:
* description: Created
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/useraccount'
* 400:
* description: Username/password too short
* 409:
* description: Username already in use
*/
account.post("/account", async (req: Request, res: Response) => {
// Check if username is valid
if (!validateString(req.body.username, 4))
@@ -121,6 +189,28 @@ account.post("/account", async (req: Request, res: Response) => {
})
})
/**
* @swagger
* /accounts/account:
* patch:
* summary: Update an user accounts data
* tags: [Account]
* security:
* - JWT: []
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/useraccount'
* 401:
* description: Unauthorized
* 500:
* description: Internal server error
*/
account.patch("/account", verifyToken, (req: Request, res: Response) => {
Account.update(req.body,
{
@@ -164,7 +254,31 @@ account.patch("/account", verifyToken, (req: Request, res: Response) => {
})
})
account.delete("/account/:id", (req: Request, res: Response) => {
/**
* @swagger
* /accounts/account/{id}:
* delete:
* summary: Delete an user account
* tags: [Account]
* security:
* - JWT: []
* parameters:
* - in: path
* name: id
* schema:
* type: number
* required: true
* description: ID of user account
* responses:
* 200:
* description: Success
* 401:
* description: Unauthorized
* 500:
* description: Internal server error
*/
account.delete("/account/:id", verifyToken, (req: Request, res: Response) => {
Account.destroy({
where: {
id: req.params.id
@@ -176,4 +290,37 @@ account.delete("/account/:id", (req: Request, res: Response) => {
.catch(error => {
res.status(500).send()
})
})
/**
* @swagger
* /accounts/:
* get:
* summary: Request all user accounts
* tags: [Account]
* security:
* - JWT: []
* responses:
* 200:
* description: Success
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/useraccount'
* 401:
* description: Unauthorized
* 500:
* description: Internal server error
*/
account.get("/", verifyToken, (req: Request, res: Response) => {
Account.findAll({
include: [ AccountRole ]
})
.then(accounts => {
res.status(200).json(accounts)
})
.catch(error => {
res.status(500).send()
})
})

View File

@@ -1,18 +1,38 @@
/**
* @swagger
* tags:
* name: Api
* description: Main API access point for misc events
*/
import { Request, Response, NextFunction, Router } from 'express'
import { deleteAllTables, deleteExerciseProgressTables, prepopulateDatabase, prepopulateExerciseDatabase } from '../scripts/databaseHelper'
export const api = Router()
/**
* Status check endpoint
* @swagger
* /api:
* get:
* summary: Status check endpoint
* tags: [Api]
* responses:
* 200:
* description: Server is up and running
*/
api.get("/", (req: Request, res: Response, next: NextFunction) => {
res.status(200).send()
})
/**
* Reset the whole database to factory state
* Doesn't effect ExerciseTable and ExerciseGroupTable
* @swagger
* /api/resetdatabase:
* get:
* summary: Reset the database to factory state
* description: Doesn't effect ExerciseTable and ExerciseGroupTable
* tags: [Api]
* responses:
* 200:
* description: Reset successful
*/
api.get("/resetdatabase", async (req: Request, res: Response, next: NextFunction) => {
// Step 1: Delete all data tables
@@ -26,7 +46,15 @@ api.get("/resetdatabase", async (req: Request, res: Response, next: NextFunction
})
/**
* Reset ExerciseTable and ExerciseGroupTable to factory state
* @swagger
* /api/resetExerciseProgress:
* get:
* summary: Reset exercises to factory state
* description: Reset ExerciseTable and ExerciseGroupTable to factory state
* tags: [Api]
* responses:
* 200:
* description: Reset successful
*/
api.get("/resetExerciseProgress", async (req: Request, res: Response, next: NextFunction) => {
deleteExerciseProgressTables()

View File

@@ -1,3 +1,9 @@
/**
* @swagger
* tags:
* name: Bands
* description: API to manage the bands
*/
import { Member } from "../models/acts/member.model";
import { Band } from "../models/acts/band.model";
import { Request, Response, Router } from "express";
@@ -13,7 +19,33 @@ import { sequelize } from "../database";
export const band = Router()
/**
* Get all bands
* @swagger
* /bands:
* get:
* summary: Download all available bands
* tags: [Bands]
* parameters:
* - in: query
* name: sort
* schema:
* type: string
* required: false
* description: Sort bands by number of concerts ascending (asc) or descending (desc)
* - in: query
* name: count
* schema:
* type: number
* required: false
* description: Limit number of results
* responses:
* 200:
* description: List of band objects
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/band'
* 500:
* description: Internal server error
*/
band.get("/", (req: Request, res: Response) => {
let sort = req.query.sort
@@ -71,7 +103,7 @@ band.get("/", (req: Request, res: Response) => {
/**
* Get all information about one band
*/
band.get("/band/:name", (req: Request, res: Response) => {
band.get("/:name", (req: Request, res: Response) => {
Band.findOne({
where: {
name: { [Op.like]: req.params.name }

View File

@@ -1,8 +1,30 @@
/**
* @swagger
* tags:
* name: Cities
* description: API to manage the cities
*/
import { City } from "../models/locations/city.model";
import { Request, Response, Router } from "express";
export const city = Router()
/**
* @swagger
* /cities:
* get:
* summary: Download all cities
* tags: [Cities]
* responses:
* 200:
* description: List of all cities as objects
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/city'
* 500:
* description: Internal server error
*/
city.get("/", (req: Request, res: Response) => {
City.findAll()
.then(cities => {

View File

@@ -1,3 +1,9 @@
/**
* @swagger
* tags:
* name: Exercises
* description: API to manage the exercise progress
*/
import { Op } from "sequelize";
import { Exercise } from "../models/exercises/exercise.model";
import { ExerciseGroup } from "../models/exercises/exerciseGroup.model";
@@ -6,11 +12,28 @@ import { Request, Response, Router } from "express";
export const exercises = Router()
/**
* Get all Exercises grouped in ExerciseGroups
* @swagger
* /exercises:
* get:
* summary: Download all exercises
* tags: [Exercises]
* responses:
* 200:
* description: Array of all exercises
* type: array
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/exercise'
* 500:
* description: Internal server error
*/
exercises.get("/", (req: Request, res: Response) => {
Exercise.findAll({
include: [ ExerciseGroup ]
include: [ ExerciseGroup ],
attributes: {
exclude: [ "exerciseGroupId" ]
}
})
.then(result => {
result.sort((a, b) => {
@@ -25,11 +48,39 @@ exercises.get("/", (req: Request, res: Response) => {
})
/**
* Update state of an Exercise
*
* @param groupNr Number of exercise group (not ID)
* @param exerciseNr Number of exercise (not ID)
* @param state New state boolean
* @swagger
* /exercises/{groupNr}/{exerciseNr}/{state}:
* post:
* summary: Update an exercise solved state
* tags: [Exercises]
* parameters:
* - in: path
* name: groupNr
* schema:
* type: number
* required: true
* description: Number of exercise group (not ID)
* - in: path
* name: exerciseNr
* schema:
* type: number
* required: true
* description: Number of exercise (not ID)
* - in: path
* name: state
* schema:
* type: number
* required: true
* description: 1 = Solved, 0 = Unsolved
* responses:
* 200:
* description: Edited exercise
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/exercise'
* 500:
* description: Internal server error
*/
exercises.post("/:groupNr/:exerciseNr/:state", (req: Request, res: Response) => {
Exercise.findOne({
@@ -43,7 +94,10 @@ exercises.post("/:groupNr/:exerciseNr/:state", (req: Request, res: Response) =>
}
]
},
include: [ ExerciseGroup ]
include: [ ExerciseGroup ],
attributes: {
exclude: [ "exerciseGroupId" ]
}
})
.then(async exercise => {
let changed = false

View File

@@ -1,5 +1,11 @@
/**
* @swagger
* tags:
* name: Files
* description: API for handling static files
*/
import { Request, Response, NextFunction, Router } from 'express'
import fs, { createReadStream } from "fs"
import fs from "fs"
import multer from "multer"
const upload = multer({ dest: './backend/images/' })
import licenses from "../data/licenses.json"
@@ -8,7 +14,18 @@ import path from 'path'
export const files = Router()
/**
* Get all folders
* @swagger
* /files/folders:
* get:
* summary: Get all static folders
* tags: [Files]
* responses:
* 200:
* description: Login successful
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/folder'
*/
files.get("/folders", async (req: Request, res: Response) => {
let dirNames = fs.readdirSync(path.resolve(__dirname, "../images"))
@@ -26,9 +43,25 @@ files.get("/folders", async (req: Request, res: Response) => {
/**
* Get all uploaded file names by folder name
*
* @param folder Name of folder on server
* @swagger
* /files/{folder}:
* get:
* summary: Get all files in one folder
* tags: [Files]
* parameters:
* - in: path
* name: folder
* schema:
* type: string
* required: true
* description: Name of folder
* responses:
* 200:
* description: Login successful
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/file'
*/
files.get("/:folder", async (req: Request, res: Response) => {
let result = []

View File

@@ -1,3 +1,9 @@
/**
* @swagger
* tags:
* name: Orders
* description: API to manage orders
*/
import { Router, Request, Response } from "express";
import { Order } from "../models/ordering/order.model";
import { Concert } from "../models/acts/concert.model";
@@ -15,8 +21,34 @@ import { Account } from "../models/user/account.model";
export const order = Router()
// Get all orders
/**
* @swagger
* /orders:
* get:
* summary: Get orders of an account or all available
* tags: [Orders]
* security:
* - JWT: []
* parameters:
* - in: query
* name: id
* schema:
* type: string
* required: false
* description: User account id to filter the orders
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/order'
* 500:
* description: Internal server error
*/
order.get("/", verifyToken, (req: Request, res: Response) => {
const accountId = req.query.id
Order.findAll({
include: [
{
@@ -47,69 +79,58 @@ order.get("/", verifyToken, (req: Request, res: Response) => {
},
Address,
Payment,
Account
]
Account,
],
attributes: {
exclude: [ "accountId", "addressId", "paymentId" ]
}
})
.then(orders => {
res.status(200).json(orders)
if (accountId != undefined) {
let filteredOrders = orders.filter(order => {
return order.id == accountId
})
res.status(200).json(filteredOrders)
} else {
res.status(200).json(orders)
}
})
.catch(error => {
res.status(500).send()
})
})
/**
* @swagger
* /orders:
* post:
* summary: Place a new order
* tags: [Orders]
* security:
* - JWT: []
* parameters:
* - in: query
* name: id
* schema:
* type: string
* required: false
* description: User account id to filter the orders
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/order'
* 500:
* description: Internal server error
*/
order.post("/", verifyToken, (req: Request, res: Response) => {
req.body["accountId"] = req["id"]
// Get all orders of one account by it's user id
order.get("/:id", (req: Request, res: Response) => {
Order.findAll({
where: { accountId: req.params.id },
include: [
{
model: Ticket,
include: [
{
model: Concert,
include: [
{
model: Band
},
{
model: Location,
include: [ City ]
}
],
attributes: {
exclude: [
"categoryId",
"brandId"
]
}
},
{
model: Seat,
include: [
{
model: SeatRow,
include: [ SeatGroup ]
}
]
}
]
},
Payment,
Address
]
})
.then(orders => {
res.status(200).json(orders)
})
.catch(error => {
res.status(500).send()
})
})
console.log(req.body)
// Place a new order
order.post("/", (req: Request, res: Response) => {
Order.create(req.body)
.then(async order => {
for (let ticket of req.body.tickets) {