This is a rest api service for course management at the university.
The project implements minimal api with api versioning, repository pattern, custom JWT authorization, fluent validation, integration and unit tests.
- xUnit
- .NET 8
- ASP.NET Core 8
- Entity Framework Core 8
- PostgreSQL
- FluentValidation
- IdentityModel
- Asp.Versioning
- Swashbuckle
- Docker
Allows you to run all integration and unit tests.
> dotnet test # donet SKD is required-
api.app - container for all application layers
-
api.database - postgresql database container
-
Build and start Docker images based on the configuration defined in the docker-compose.yml
> make up # docker-compose up --build
-
Stop and remove containers
> make down # docker-compose down
| container | port | login | password | GUI |
|---|---|---|---|---|
| api.database | 5432 | user | password | - |
| api.app | 8000 | - | - | http://localhost:8000/swagger/index.html |
-
Swagger UI
http://localhost:8000/swagger/index.html -
https://github.com/gitEugeneL/Course-management-system/blob/dev/swagger.json
Authentication is implemented using a JWT access token and refresh token.
AccessToken is used to authorize users, the refresh token is used to update a pair of tokens.
RefreshToken is recorded in the database and allows each user to have 5 active devices at the same time.
POST /api/v1/auth/register(allows you to register)
name type data type required string password required string firstName not required string lastName not required string universityNumber not required string
http code content-type response 201application/json{"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "universityNumber": "string"}400application/jsonarray409application/jsonstring
POST /api/v1/auth/register(allows you to login, issues accessToken and refreshToken)
name type data type required string password required string
http code content-type response 200application/json{"accessTokenType": "string", "accessToken": "string", "refreshToken": "string", "refreshTokenExpires": "2024-04-19T18:14:59.908Z"}400application/jsonarray404application/jsonstring
POST /api/v1/auth/refresh(allows to refresh access and refresh tokens)
name type data type "refreshToken" required string
http code content-type response 200application/json{"accessTokenType": "string", "accessToken": "string", "refreshToken": "string", "refreshTokenExpires": "2024-04-19T18:14:59.908Z"}401application/jsonstring
POST /api/v1/auth/refresh(allows to logout and deactivates refresh token)
name type data type "refreshToken" required string
http code content-type response 204application/jsonNoContent401application/jsonstring
Functionality that allows to manage and interact with courses
POST /api/v1/courses(allows to create new course 🔒️[professor auth policy])
name type data type "name" required string "description" required string "maxParticipants" required int
http code content-type response 201application/json{"courseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6","ownerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "description": "string", "maxParticipants": 0, "countParticipants": 0, "finalized": true, "createdAt": "2024-04-19T18:37:43.448Z"}400application/jsonarray401application/jsonstring403application/jsonstring409application/jsonstring
PUT /api/v1/courses(allows to update your courses 🔒️[professor auth policy])
name type data type "courseId" required uuid "description" required string "maxParticipants" required int "finalize" required boolean
http code content-type response 200application/json{"courseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "ownerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "description": "string", "maxParticipants": 0, "countParticipants": 0, "finalized": true, "createdAt": "2024-04-19T18:50:26.257Z"}400application/jsonarray401application/jsonstring403application/jsonstring404application/jsonstring
PUT /api/v1/courses/{ courseName:string }(allows to delete your courses 🔒️[professor auth policy])
http code content-type response 204application/jsonNoContent401application/jsonstring403application/jsonstring404application/jsonstring
PATCH /api/v1/courses/join/{ courseName:string }(allows to join the course 🔒️[student auth policy])
http code content-type response 200application/jsonstging401application/jsonstring403application/jsonstring404application/jsonstring409application/jsonstring
PATCH /api/v1/courses/leave/{ courseName:string }(allows to leave the course 🔒️[student auth policy])
http code content-type response 200application/jsonstging401application/jsonstring403application/jsonstring404application/jsonstring409application/jsonstring
GET /api/v1/courses(allows you to get all courses 🔒️[base auth policy])
name type data type SortByCreated not required boolean SortByAvailableCourses not required boolean SortByMyCourses not required boolean PageNumber not required int32 PageSize not required int32
http code content-type response 200application/json{ "items": [ { "courseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "ownerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "description": "string", "maxParticipants": 0, "countParticipants": 0, "finalized": true, "createdAt": "2024-04-19T19:04:00.291Z" } ], "pageNumber": 0, "totalPages": 0, "totalItemsCount": 0 }401application/jsonstring403application/jsonstring
GET /api/v1/courses/{ courseName:string }(allows you to get one course by name 🔒️[base auth policy])
http code content-type response 200application/json{"courseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "ownerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "description": "string", "maxParticipants": 0, "countParticipants": 0, "finalized": true, "createdAt": "2024-04-19T19:07:27.865Z"}401application/jsonstring403application/jsonstring404application/jsonstring
Functionality that allows to manage course participants
PATCH /api/v1/participants(allows you to grade the student 🔒️[professor auth policy])
name type data type "userId" required uuid "courseId" required uuid "grade" required int "professorNote" required string
http code content-type response 200application/json{"course": { "courseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "ownerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "description": "string", "maxParticipants": 0, "countParticipants": 0, "finalized": true, "createdAt": "2024-04-19T19:40:56.771Z" }, "user": { "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "universityNumber": "string" }, "grade": 0, "professorNote": "string"}401application/jsonstring403application/jsonstring404application/jsonstring
GET /api/v1/participants/{ courseName:string }(allows you to grade the student 🔒️[professor auth policy])
name type data type PageNumber not required int32 PageSize not required int32
http code content-type response 200application/json{"items": [ { "course": { "courseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "ownerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "description": "string", "maxParticipants": 0, "countParticipants": 0, "finalized": true, "createdAt": "2024-04-19T19:50:54.089Z" }, "user": { "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "universityNumber": "string" } ,"grade": 0, "professorNote": "string" } ], "pageNumber": 0, "totalPages": 0, "totalItemsCount": 0 }401application/jsonstring403application/jsonstring404application/jsonstring
GET /api/v1/participants(allows you to get all your participants and courses 🔒️[student auth policy])
http code content-type response 200application/json{{"course": { "courseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "ownerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "name": "string", "description": "string", "maxParticipants": 0, "countParticipants": 0, "finalized": true, "createdAt": "2024-04-19T19:43:59.773Z" }, "user": { "userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "email": "string", "firstName": "string", "lastName": "string", "universityNumber": "string" }, "grade": 0, "professorNote": "string"}}401application/jsonstring403application/jsonstring