Compare commits

..

3 Commits

134 changed files with 1528 additions and 8969 deletions

View File

@ -1,4 +1,5 @@
BUILD_PATH=$1
cd $BUILD_PATH/src || exit 1
docker build -f ./InternshipSystem.Api/Dockerfile -t internship.api .
cd $BUILD_PATH/.docker || exit 1
docker-compose up -d --build --force-recreate

View File

@ -3,28 +3,14 @@ services:
internship.api:
image: internship.api:latest
environment:
CONNECTIONSTRINGS__INTERNSHIPDATABASE: "Host=db.postgres;Port=5432;Database=postgres;Username=postgres;Password=szwoniu"
ASPNETCORE_ENVIRONMENT: Development
ASPNETCORE_URLS: http://+:80
SECURITYOPTIONS__SECRET: iewaiwie3aig9wi3chieBai9eephai
SECURITYOPTIONS__EXPIRATION: 1440 # 24h in minutes
SECURITYOPTIONS__BASEURL: https://logowanie.pg.edu.pl
SECURITYOPTIONS__TOKENPATH: /oauth2.0/accessToken
SECURITYOPTIONS__PROFILEPATH: /oauth2.0/profile
SECURITYOPTIONS__CLIENTID: PraktykiClientId
SECURITYOPTIONS__REDIRECTURL: https://system-praktyk.stg.kadet.net/user/login/check/pg
FILLER__USE_DEFAULT_DATA: "true"
depends_on:
- db.postgres
build: ../src/Internship.Api
ports:
- 8080:80
db.postgres:
image: postgres:latest
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: szwoniu
PGDATA: /postgres
ports:
- 5432:5432
- 5432:5432

63
.vscode/tasks.json vendored
View File

@ -7,14 +7,22 @@
"type": "process",
"args": [
"build",
"${workspaceFolder}/src/InternshipSystem.Api/InternshipSystem.Api.csproj",
"${workspaceFolder}/src/Internship.Api/Internship.Api.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/src/Internship.Api/Internship.Api.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": "$msCompile"
},
{
@ -23,53 +31,27 @@
"type": "process",
"args": [
"watch",
"--project",
"${workspaceFolder}/src/InternshipSystem.Api/InternshipSystem.Api.csproj",
"run",
"${workspaceFolder}/src/Internship.Api/Internship.Api.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
{
"label": "build: api",
"type": "docker-build",
"dockerBuild": {
"dockerfile": "src/InternshipSystem.Api/Dockerfile",
"tag": "internship.api",
"context": "src"
},
"problemMatcher": [],
},
{
"label": "down: api",
"type": "shell",
"command": "docker-compose",
"args": [
"-f",
".docker/docker-compose.yaml",
"down",
"--volumes",
"--remove-orphans"
]
},
{
"label": "up: api",
"label": "up",
"type": "shell",
"command": "docker-compose",
"args": [
"-f",
".docker/docker-compose.yaml",
"up",
],
"dependsOn": [
"build: api",
"down: api"
"--build"
],
"problemMatcher": []
},
{
"label": "restore",
"label": "dotnet restore",
"type": "shell",
"command": "dotnet",
"args": [
@ -77,16 +59,5 @@
],
"problemMatcher": []
},
{
"label": "publish",
"command": "dotnet",
"args": [
"publish",
"--output",
"./obj/docker/publish",
"--runtime",
"linux-x64"
]
}
]
}

View File

@ -5,17 +5,17 @@ VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{A43DB15B-657C-4E02-BC1B-2670DD34D9E0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InternshipSystem.Api", "src\InternshipSystem.Api\InternshipSystem.Api.csproj", "{2C72839D-2E0B-4794-9324-3E9E622251E3}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Internship.Api", "src\Internship.Api\Internship.Api.csproj", "{2C72839D-2E0B-4794-9324-3E9E622251E3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InternshipSystem.Repository", "src\InternshipSystem.Repository\InternshipSystem.Repository.csproj", "{A4697640-0746-4720-9B20-923763612F1A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Internship.Repository", "src\Internship.Repository\Internship.Repository.csproj", "{A4697640-0746-4720-9B20-923763612F1A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InternshipSystem.Core", "src\InternshipSystem.Core\InternshipSystem.Core.csproj", "{2C395A11-E3A2-4454-95A1-82A3EAE791EC}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Internship.Core", "src\Internship.Core\Internship.Core.csproj", "{2C395A11-E3A2-4454-95A1-82A3EAE791EC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{69F62FEE-6768-4B47-9295-4EF5E8E30BEA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InternshipSystem.Api.Test", "test\InternshipSystem.Api.Test\InternshipSystem.Api.Test.csproj", "{90365B6B-B2C6-49D9-84F7-F806B06C1AFE}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Internship.Api.Test", "test\Internship.Api.Test\Internship.Api.Test.csproj", "{90365B6B-B2C6-49D9-84F7-F806B06C1AFE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InternshipSystem.Core.Tests", "test\InternshipSystem.Core.Tests\InternshipSystem.Core.Tests.csproj", "{748544B4-CBDA-4123-9BD9-499F6C90567F}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Internship.Core.Tests", "test\Internship.Core.Tests\Internship.Core.Tests.csproj", "{748544B4-CBDA-4123-9BD9-499F6C90567F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@ -1,867 +0,0 @@
{
"info": {
"_postman_id": "f0858747-6271-4176-9193-ed1f9be0d7d3",
"name": "StudentOperations",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "loginDev",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/dev/login",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"dev",
"login"
]
}
},
"response": []
},
{
"name": "GetInternshipManagementList",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjEwMjY2MzcxLCJleHAiOjE2MTAzNTI3NzEsImlhdCI6MTYxMDI2NjM3MX0.PDrMjCHJlpN2FApL6rC-UAoH1ZWAnUImwWfTDhvB5wI",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/management/internship?OrderByField=InternshipState&SortOrder=Asc",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"internship"
],
"query": [
{
"key": "OrderByField",
"value": "InternshipState"
},
{
"key": "SortOrder",
"value": "Asc"
}
]
}
},
"response": []
},
{
"name": "GetInternshipManagement",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjEwMjY2MzcxLCJleHAiOjE2MTAzNTI3NzEsImlhdCI6MTYxMDI2NjM3MX0.PDrMjCHJlpN2FApL6rC-UAoH1ZWAnUImwWfTDhvB5wI",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/management/internship/1",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"internship",
"1"
]
}
},
"response": []
},
{
"name": "GetInternshipManagementAccept",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjEwMjY2MzcxLCJleHAiOjE2MTAzNTI3NzEsImlhdCI6MTYxMDI2NjM3MX0.PDrMjCHJlpN2FApL6rC-UAoH1ZWAnUImwWfTDhvB5wI",
"type": "string"
}
]
},
"method": "PUT",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "\"\""
},
"url": {
"raw": "http://localhost:8080/management/internship/accept/1",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"internship",
"accept",
"1"
]
}
},
"response": []
},
{
"name": "GetInternshipManagementReject",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjEwMjY2MzcxLCJleHAiOjE2MTAzNTI3NzEsImlhdCI6MTYxMDI2NjM3MX0.PDrMjCHJlpN2FApL6rC-UAoH1ZWAnUImwWfTDhvB5wI",
"type": "string"
}
]
},
"method": "PUT",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "\"Co żeś odrąbał andzeju\""
},
"url": {
"raw": "http://localhost:8080/management/internship/reject/1",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"internship",
"reject",
"1"
]
}
},
"response": []
},
{
"name": "loginEdition",
"request": {
"method": "POST",
"header": [
{
"key": "Authorization",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTUyLCJleHAiOjE2MDEyODM5NTEsImlhdCI6MTYwMTE5NzU1Mn0.0wcNQSXV55MFvEnRLC09nGwCqI7M2kuWdwe0EOV_C6Y",
"type": "text"
},
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "\"138da8a3-855c-4b17-9bd2-5f357679efa9\""
},
"url": {
"raw": "http://localhost:8080/access/loginEdition",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"access",
"loginEdition"
]
}
},
"response": []
},
{
"name": "currentInternship",
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE",
"type": "text"
},
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"url": {
"raw": "http://localhost:8080/internshipRegistration",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"internshipRegistration"
]
}
},
"response": []
},
{
"name": "GetCourseList",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA2NTk2MzI5LCJleHAiOjE2MDY2ODI3MjksImlhdCI6MTYwNjU5NjMyOX0.O-dLJNI3-tNj96xOpz8LE7zrysmJkN069A3Zku2A7S0",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/management/course",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"course"
]
}
},
"response": []
},
{
"name": "GetCourse",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA2NTk2MzI5LCJleHAiOjE2MDY2ODI3MjksImlhdCI6MTYwNjU5NjMyOX0.O-dLJNI3-tNj96xOpz8LE7zrysmJkN069A3Zku2A7S0",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/management/course/1",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"course",
"1"
]
}
},
"response": []
},
{
"name": "CreateCourse",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA2NTk2MzI5LCJleHAiOjE2MDY2ODI3MjksImlhdCI6MTYwNjU5NjMyOX0.O-dLJNI3-tNj96xOpz8LE7zrysmJkN069A3Zku2A7S0",
"type": "string"
}
]
},
"method": "PUT",
"header": [
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"id\": null,\r\n \"name\": \"testowy\",\r\n \"nameEng\": \"test\"\r\n}"
},
"url": {
"raw": "http://localhost:8080/management/course",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"course"
]
}
},
"response": []
},
{
"name": "UpdateCourse",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA2NTk2MzI5LCJleHAiOjE2MDY2ODI3MjksImlhdCI6MTYwNjU5NjMyOX0.O-dLJNI3-tNj96xOpz8LE7zrysmJkN069A3Zku2A7S0",
"type": "string"
}
]
},
"method": "PUT",
"header": [
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"id\": 3,\r\n \"name\": \"testowyUp\",\r\n \"nameEng\": \"testUp\"\r\n}"
},
"url": {
"raw": "http://localhost:8080/management/course",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"course"
]
}
},
"response": []
},
{
"name": "DeleteCourse",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA2NTk2MzI5LCJleHAiOjE2MDY2ODI3MjksImlhdCI6MTYwNjU5NjMyOX0.O-dLJNI3-tNj96xOpz8LE7zrysmJkN069A3Zku2A7S0",
"type": "string"
}
]
},
"method": "DELETE",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/management/course/3",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"course",
"3"
]
}
},
"response": []
},
{
"name": "GetEditionManagementListByCourse",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA2NTk2MzI5LCJleHAiOjE2MDY2ODI3MjksImlhdCI6MTYwNjU5NjMyOX0.O-dLJNI3-tNj96xOpz8LE7zrysmJkN069A3Zku2A7S0",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/management/editions?course=1",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"editions"
],
"query": [
{
"key": "course",
"value": "1"
}
]
}
},
"response": []
},
{
"name": "GetEditionManagementList",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA2NTk2MzI5LCJleHAiOjE2MDY2ODI3MjksImlhdCI6MTYwNjU5NjMyOX0.O-dLJNI3-tNj96xOpz8LE7zrysmJkN069A3Zku2A7S0",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/management/editions",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"editions"
]
}
},
"response": []
},
{
"name": "GetEditionManagement",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA0ODI3ODgzLCJleHAiOjE2MDQ5MTQyODMsImlhdCI6MTYwNDgyNzg4M30.a3mMm3Zk3xpfsmIwlqtpjgWgTNEXv8O4hH_V_L9UFZo",
"type": "string"
}
]
},
"method": "GET",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/management/editions/138da8a3-855c-4b17-9bd2-5f357679efa9",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"editions",
"138da8a3-855c-4b17-9bd2-5f357679efa9"
]
}
},
"response": []
},
{
"name": "CreateEdition",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA2NTk2MzI5LCJleHAiOjE2MDY2ODI3MjksImlhdCI6MTYwNjU5NjMyOX0.O-dLJNI3-tNj96xOpz8LE7zrysmJkN069A3Zku2A7S0",
"type": "string"
}
]
},
"method": "PUT",
"header": [
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"editionStart\": \"2020-11-15T11:02:04.002Z\",\r\n \"editionFinish\": \"2020-11-25T11:02:04.002Z\",\r\n \"reportingStart\": \"2020-11-20T11:02:04.002Z\",\r\n \"course\": {\r\n \"id\": 1,\r\n \"name\": \"Informatyka\",\r\n \"nameEng\": \"Informatics\"\r\n },\r\n \"availableSubjectsIds\": [2],\r\n \"availableInternshipTypesIds\": [8]\r\n}"
},
"url": {
"raw": "http://localhost:8080/management/edition",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"edition"
]
}
},
"response": []
},
{
"name": "UpdateEdition",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA2NTk2MzI5LCJleHAiOjE2MDY2ODI3MjksImlhdCI6MTYwNjU5NjMyOX0.O-dLJNI3-tNj96xOpz8LE7zrysmJkN069A3Zku2A7S0",
"type": "string"
}
]
},
"method": "PUT",
"header": [
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"id\": \"138da8a3-855c-4b17-9bd2-5f357679efa9\",\r\n \"editionStart\": \"2020-11-15T11:02:04.002Z\",\r\n \"editionFinish\": \"2020-11-20T11:02:04.002Z\",\r\n \"reportingStart\": \"2020-11-17T11:02:04.002Z\",\r\n \"course\": {\r\n \"id\": 2,\r\n \"name\": \"Inżynieria Biomedyczna\",\r\n \"nameEng\": \"Biomedical Engineering\"\r\n },\r\n \"availableSubjectsIds\": [3],\r\n \"availableInternshipTypesIds\": [3]\r\n}"
},
"url": {
"raw": "http://localhost:8080/management/editions",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"editions"
]
}
},
"response": []
},
{
"name": "DeleteEditionManagement",
"request": {
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjA0ODI3ODgzLCJleHAiOjE2MDQ5MTQyODMsImlhdCI6MTYwNDgyNzg4M30.a3mMm3Zk3xpfsmIwlqtpjgWgTNEXv8O4hH_V_L9UFZo",
"type": "string"
}
]
},
"method": "DELETE",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/management/editions/be1a4439-0360-477c-85c5-e28bc8542883",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"management",
"editions",
"be1a4439-0360-477c-85c5-e28bc8542883"
]
}
},
"response": []
},
{
"name": "updateRegistration",
"request": {
"method": "PUT",
"header": [
{
"key": "Authorization",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE",
"type": "text"
},
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\r\n \"company\": {\r\n \"id\": 1,\r\n \"nip\": null,\r\n \"name\": null\r\n },\r\n \"branchOffice\": {\r\n \"id\": 1,\r\n \"street\": null,\r\n \"building\": null,\r\n \"city\": null,\r\n \"postalCode\": null,\r\n \"country\": null\r\n },\r\n \"start\": \"2020-07-27T09:43:49.094Z\",\r\n \"end\": \"2020-09-27T09:43:49.094Z\",\r\n \"type\": {\r\n \"id\": 2,\r\n \"type\": null,\r\n \"description\": null,\r\n \"descriptionEng\": null\r\n }\r\n}"
},
"url": {
"raw": "http://localhost:8080/internshipRegistration",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"internshipRegistration"
]
}
},
"response": []
},
{
"name": "GetRegisteredEditions",
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE",
"type": "text"
},
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"url": {
"raw": "http://localhost:8080/editions",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"editions"
]
}
},
"response": []
},
{
"name": "GetEditionsConfiguration",
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"type": "text",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE"
},
{
"key": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"url": {
"raw": "http://localhost:8080/editions/138da8a3-855c-4b17-9bd2-5f357679efa9",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"editions",
"138da8a3-855c-4b17-9bd2-5f357679efa9"
]
}
},
"response": []
},
{
"name": "RegisterForEdition",
"request": {
"method": "POST",
"header": [
{
"key": "Authorization",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImZpcnN0bmFtZSIsImZhbWlseV9uYW1lIjoibGFzdG5hbWUiLCJQZXJzb25OdW1iZXIiOiIxIiwibmJmIjoxNjAxMTk3NTYzLCJleHAiOjE2MDEyODM5NjMsImlhdCI6MTYwMTE5NzU2MywiRWRpdGlvbiI6IjEzOGRhOGEzLTg1NWMtNGIxNy05YmQyLTVmMzU3Njc5ZWZhOSJ9.l7QK1eUIJexnDaFKZ9yx3NWxmB2KrvPpjLUuuP1EJyE",
"type": "text"
},
{
"key": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "\"138da8a3-855c-4b17-9bd2-5f357679efa9\""
},
"url": {
"raw": "http://localhost:8080/register",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"register"
]
}
},
"response": []
}
]
}

View File

@ -1,49 +0,0 @@
# Uruchomienie
Aby uruchomić środowisko deweloperskie wystarczy
```bash
docker build -f ./InternshipSystem.Api/Dockerfile -t internship.api .
docker-compose -f ./.docker/docker-compose.yaml --build --volumes
```
# Opis struktury
Opis struktury projektu
## src/
zawiera kod podzielony na 3 projekty
- Api - Definicja interfejsu wystawianego dla częsci frontendowej
- Core - Logika biznesowa aplikacji, definicja domeny.
- Repository - Definicja repozytorium EFCore
## test/
Zawiera testy jednostkowe projektu. Przy pisaniu wykorzystano Machine-Specification
## .build/
Folder zawierający pliki definiujące CI/CD projektu
## .docker/
Folder zawiera pliki docker-compose przeznaczone do uruchamiania środowiska deweloperskiego, stanowiące również dokumentacje zmiennych środowiskowych konfigurujących projekt
```yaml
CONNECTIONSTRINGS__INTERNSHIPDATABASE: "Host=db.postgres;Port=5432;Database=postgres;Username=postgres;Password=password"
ASPNETCORE_ENVIRONMENT: Development
ASPNETCORE_URLS: http://+:80
SECURITYOPTIONS__SECRET: secret
SECURITYOPTIONS__EXPIRATION: 1440 # 24h in minutes
SECURITYOPTIONS__BASEURL: https://logowanie.pg.edu.pl
SECURITYOPTIONS__TOKENPATH: /oauth2.0/accessToken
SECURITYOPTIONS__PROFILEPATH: /oauth2.0/profile
SECURITYOPTIONS__CLIENTID: PraktykiClientId
SECURITYOPTIONS__REDIRECTURL: https://system-praktyk.net/user/login/check/pg
```
## props/
Folder ze współdzieloną konfiguracją dla grup projektów, np. wersji bibliotek używanych przy pisaniu testów.

5
global.json Normal file
View File

@ -0,0 +1,5 @@
{
"sdk": {
"version": "3.1.103"
}
}

View File

@ -1,10 +0,0 @@
<Project>
<ItemGroup>
<PackageReference Include="Machine.Fakes.FakeItEasy" Version="2.11.0" />
<PackageReference Include="Machine.Specifications" Version="1.0.0" />
<PackageReference Include="Machine.Specifications.Runner.VisualStudio" Version="2.10.1" />
<PackageReference Include="Machine.Specifications.Should" Version="1.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
<PackageReference Include="coverlet.collector" Version="1.2.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,24 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
README.md

View File

@ -0,0 +1,16 @@
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore
# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "./Internship.Api.dll"]

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<!-- <GenerateDocumentationFile>true</GenerateDocumentationFile>-->
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
<PackageReference Include="Serilog" Version="2.9.0" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.3.2" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controllers" />
</ItemGroup>
</Project>

View File

@ -1,9 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using Serilog.Formatting.Compact;
namespace InternshipSystem.Api
namespace Internship.Api
{
public class Program
{

View File

@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
namespace Internship.Api
{
public class Startup
{
private IConfiguration Configuration { get; }
public Startup(IConfiguration configuration) =>
Configuration = configuration;
public void ConfigureServices(IServiceCollection services) =>
services
.AddSwaggerGen(options =>
options.SwaggerDoc("v1", new OpenApiInfo {Title = "InternshipSystem Api - TEST", Version = "v1"}))
.AddControllers()
;
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app
.UseSwagger()
.UseSwaggerUI(options => options.SwaggerEndpoint("/swagger/v1/swagger.json", "InternshipSystem Api"))
.UseHttpsRedirection()
.UseRouting()
.UseAuthorization()
.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}

View File

@ -0,0 +1,11 @@
namespace Internship.Core
{
public class Address
{
public string Street { get; set; }
public string Building { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
}

View File

@ -0,0 +1,10 @@
namespace Internship.Core
{
public class BranchOffice
{
public int Id { get; set; }
public Address Address { get; set; }
public Company Company { get; set; }
public int Provider { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
namespace Internship.Core
{
public class Company
{
public string Nip { get; set; }
public string Name { get; set; }
public RangeOfActivities Range { get; set; }
public Uri SiteAddress { get; set; }
public int Provider { get; set; }
public List<BranchOffice> Branches { get; set; }
}
}

View File

@ -0,0 +1,8 @@
namespace Internship.Core
{
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using System;
namespace Internship.Core
{
public class DeanAcceptance
{
public DateTime AcceptanceDate { get; set; }
public bool IsDeansAcceptanceRequired { get; set; }
public DeanAcceptanceReason Reason { get; set; }
}
public enum DeanAcceptanceReason
{
Semester,
Delay,
Whatever
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
namespace Internship.Core
{
public class Edition
{
public int Id { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public DateTime IPPDeadlineDate { get; set; }
public List<InternshipProgramSubject> Subjects { get; set;}
}
}

View File

@ -0,0 +1,10 @@
using System;
namespace Internship.Core
{
public class Insurance
{
public DateTime InsuranceDeliveryDate { get; set; }
public bool IsInsuranceRequired { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace Internship.Core
{
public class Intern
{
public string AlbumNumber { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public Course Course { get; set; }
public int Semester { get; set; }
}
}

View File

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
namespace Internship.Core
{
public class InternshipEntity
{
public int Id { get; set; }
public Intern Intern { get; set; }
public Edition Edition { get; set; }
public Report Report { get; set; }
public BranchOffice BranchOffice { get; set; }
public InternshipType Type { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public bool IsAccepted { get; set; }
public DeanAcceptance DeanAcceptance { get; set; }
public Insurance Insurance { get; set; }
public int InternshipLengthInWeeks { get; set; }
public float Grade { get; set; }
public List<InternshipProgramSubject> Program { get; set; }
}
}

View File

@ -0,0 +1,9 @@
namespace Internship.Core
{
public class InternshipProgramSubject
{
public int Id { get; set; }
public Course Course { get; set; }
public string Description { get; set; }
}
}

View File

@ -0,0 +1,14 @@
namespace Internship.Core
{
public enum InternshipType
{
Other,
FreeInternship,
GraduateInternship,
FreeApprenticeship,
PaidApprenticeship,
EmploymentContract,
MandateContract,
ContractWork
}
}

View File

@ -0,0 +1,9 @@
namespace Internship.Core
{
public enum RangeOfActivities
{
Other,
National,
International
}
}

View File

@ -0,0 +1,7 @@
namespace Internship.Core
{
public class Report
{
public int Id { get; set; }
}
}

View File

@ -2,12 +2,11 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EFCore.NamingConventions" Version="1.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.4">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
@ -17,7 +16,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\InternshipSystem.Core\InternshipSystem.Core.csproj" />
<ProjectReference Include="..\Internship.Core\Internship.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,39 @@
using Microsoft.EntityFrameworkCore;
using Internship.Core;
namespace Internship.Repository
{
public class InternshipDbContext : DbContext
{
public DbSet<InternshipEntity> Internships { get; set; }
public DbSet<Company> Companies { get; set; }
public DbSet<Edition> Editions { get; set; }
public DbSet<Report> Reports { get; set; }
public DbSet<Intern> Interns { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) =>
optionsBuilder
.UseNpgsql("Host=localhost;Port=5432;Database=postgres;Username=postgres;Password=szwoniu")
.UseSnakeCaseNamingConvention();
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder
.Entity<InternshipEntity>(ie => {
ie.OwnsOne(i => i.DeanAcceptance);
ie.OwnsOne(i => i.Insurance);
});
modelBuilder
.Entity<Company>()
.HasKey(c => c.Nip);
modelBuilder
.Entity<BranchOffice>()
.OwnsOne(b => b.Address);
modelBuilder
.Entity<Intern>()
.HasKey(i => i.AlbumNumber);
}
}
}

View File

@ -0,0 +1,428 @@
// <auto-generated />
using System;
using Internship.Repository;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Internship.Repository.Migrations
{
[DbContext(typeof(InternshipDbContext))]
[Migration("20200612141652_InitialCreate")]
partial class InitialCreate
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
.HasAnnotation("ProductVersion", "3.1.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
modelBuilder.Entity("Internship.Core.BranchOffice", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("CompanyNip")
.HasColumnName("company_nip")
.HasColumnType("text");
b.Property<int>("Provider")
.HasColumnName("provider")
.HasColumnType("integer");
b.HasKey("Id")
.HasName("pk_branch_office");
b.HasIndex("CompanyNip")
.HasName("ix_branch_office_company_nip");
b.ToTable("branch_office");
});
modelBuilder.Entity("Internship.Core.Company", b =>
{
b.Property<string>("Nip")
.HasColumnName("nip")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnName("name")
.HasColumnType("text");
b.Property<int>("Provider")
.HasColumnName("provider")
.HasColumnType("integer");
b.Property<int>("Range")
.HasColumnName("range")
.HasColumnType("integer");
b.Property<string>("SiteAddress")
.HasColumnName("site_address")
.HasColumnType("text");
b.HasKey("Nip")
.HasName("pk_companies");
b.ToTable("companies");
});
modelBuilder.Entity("Internship.Core.Course", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name")
.HasColumnName("name")
.HasColumnType("text");
b.HasKey("Id")
.HasName("pk_course");
b.ToTable("course");
});
modelBuilder.Entity("Internship.Core.Edition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<DateTime>("EndDate")
.HasColumnName("end_date")
.HasColumnType("timestamp without time zone");
b.Property<DateTime>("IPPDeadlineDate")
.HasColumnName("ipp_deadline_date")
.HasColumnType("timestamp without time zone");
b.Property<DateTime>("StartDate")
.HasColumnName("start_date")
.HasColumnType("timestamp without time zone");
b.HasKey("Id")
.HasName("pk_editions");
b.ToTable("editions");
});
modelBuilder.Entity("Internship.Core.Intern", b =>
{
b.Property<string>("AlbumNumber")
.HasColumnName("album_number")
.HasColumnType("text");
b.Property<int?>("CourseId")
.HasColumnName("course_id")
.HasColumnType("integer");
b.Property<string>("Email")
.HasColumnName("email")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnName("name")
.HasColumnType("text");
b.Property<int>("Semester")
.HasColumnName("semester")
.HasColumnType("integer");
b.Property<string>("Surname")
.HasColumnName("surname")
.HasColumnType("text");
b.HasKey("AlbumNumber")
.HasName("pk_interns");
b.HasIndex("CourseId")
.HasName("ix_interns_course_id");
b.ToTable("interns");
});
modelBuilder.Entity("Internship.Core.InternshipEntity", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int?>("BranchOfficeId")
.HasColumnName("branch_office_id")
.HasColumnType("integer");
b.Property<int?>("EditionId")
.HasColumnName("edition_id")
.HasColumnType("integer");
b.Property<DateTime>("EndDate")
.HasColumnName("end_date")
.HasColumnType("timestamp without time zone");
b.Property<float>("Grade")
.HasColumnName("grade")
.HasColumnType("real");
b.Property<string>("InternAlbumNumber")
.HasColumnName("intern_album_number")
.HasColumnType("text");
b.Property<int>("InternshipLengthInWeeks")
.HasColumnName("internship_length_in_weeks")
.HasColumnType("integer");
b.Property<bool>("IsAccepted")
.HasColumnName("is_accepted")
.HasColumnType("boolean");
b.Property<int?>("ReportId")
.HasColumnName("report_id")
.HasColumnType("integer");
b.Property<DateTime>("StartDate")
.HasColumnName("start_date")
.HasColumnType("timestamp without time zone");
b.Property<int>("Type")
.HasColumnName("type")
.HasColumnType("integer");
b.HasKey("Id")
.HasName("pk_internships");
b.HasIndex("BranchOfficeId")
.HasName("ix_internships_branch_office_id");
b.HasIndex("EditionId")
.HasName("ix_internships_edition_id");
b.HasIndex("InternAlbumNumber")
.HasName("ix_internships_intern_album_number");
b.HasIndex("ReportId")
.HasName("ix_internships_report_id");
b.ToTable("internships");
});
modelBuilder.Entity("Internship.Core.InternshipProgramSubject", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int?>("CourseId")
.HasColumnName("course_id")
.HasColumnType("integer");
b.Property<string>("Description")
.HasColumnName("description")
.HasColumnType("text");
b.Property<int?>("EditionId")
.HasColumnName("edition_id")
.HasColumnType("integer");
b.Property<int?>("InternshipEntityId")
.HasColumnName("internship_entity_id")
.HasColumnType("integer");
b.HasKey("Id")
.HasName("pk_internship_program_subject");
b.HasIndex("CourseId")
.HasName("ix_internship_program_subject_course_id");
b.HasIndex("EditionId")
.HasName("ix_internship_program_subject_edition_id");
b.HasIndex("InternshipEntityId")
.HasName("ix_internship_program_subject_internship_entity_id");
b.ToTable("internship_program_subject");
});
modelBuilder.Entity("Internship.Core.Report", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.HasKey("Id")
.HasName("pk_reports");
b.ToTable("reports");
});
modelBuilder.Entity("Internship.Core.BranchOffice", b =>
{
b.HasOne("Internship.Core.Company", "Company")
.WithMany("Branches")
.HasForeignKey("CompanyNip")
.HasConstraintName("fk_branch_office_companies_company_nip");
b.OwnsOne("Internship.Core.Address", "Address", b1 =>
{
b1.Property<int>("BranchOfficeId")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b1.Property<string>("Building")
.HasColumnName("building")
.HasColumnType("text");
b1.Property<string>("City")
.HasColumnName("city")
.HasColumnType("text");
b1.Property<string>("Country")
.HasColumnName("country")
.HasColumnType("text");
b1.Property<string>("PostalCode")
.HasColumnName("postal_code")
.HasColumnType("text");
b1.Property<string>("Street")
.HasColumnName("street")
.HasColumnType("text");
b1.HasKey("BranchOfficeId")
.HasName("pk_branch_office");
b1.ToTable("branch_office");
b1.WithOwner()
.HasForeignKey("BranchOfficeId")
.HasConstraintName("fk_address_branch_office_branch_office_id");
});
});
modelBuilder.Entity("Internship.Core.Intern", b =>
{
b.HasOne("Internship.Core.Course", "Course")
.WithMany()
.HasForeignKey("CourseId")
.HasConstraintName("fk_interns_course_course_id");
});
modelBuilder.Entity("Internship.Core.InternshipEntity", b =>
{
b.HasOne("Internship.Core.BranchOffice", "BranchOffice")
.WithMany()
.HasForeignKey("BranchOfficeId")
.HasConstraintName("fk_internships_branch_office_branch_office_id");
b.HasOne("Internship.Core.Edition", "Edition")
.WithMany()
.HasForeignKey("EditionId")
.HasConstraintName("fk_internships_editions_edition_id");
b.HasOne("Internship.Core.Intern", "Intern")
.WithMany()
.HasForeignKey("InternAlbumNumber")
.HasConstraintName("fk_internships_interns_intern_album_number");
b.HasOne("Internship.Core.Report", "Report")
.WithMany()
.HasForeignKey("ReportId")
.HasConstraintName("fk_internships_reports_report_id");
b.OwnsOne("Internship.Core.DeanAcceptance", "DeanAcceptance", b1 =>
{
b1.Property<int>("InternshipEntityId")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b1.Property<DateTime>("AcceptanceDate")
.HasColumnName("acceptance_date")
.HasColumnType("timestamp without time zone");
b1.Property<bool>("IsDeansAcceptanceRequired")
.HasColumnName("is_deans_acceptance_required")
.HasColumnType("boolean");
b1.Property<int>("Reason")
.HasColumnName("reason")
.HasColumnType("integer");
b1.HasKey("InternshipEntityId")
.HasName("pk_internships");
b1.ToTable("internships");
b1.WithOwner()
.HasForeignKey("InternshipEntityId")
.HasConstraintName("fk_dean_acceptance_internships_internship_entity_id");
});
b.OwnsOne("Internship.Core.Insurance", "Insurance", b1 =>
{
b1.Property<int>("InternshipEntityId")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b1.Property<DateTime>("InsuranceDeliveryDate")
.HasColumnName("insurance_delivery_date")
.HasColumnType("timestamp without time zone");
b1.Property<bool>("IsInsuranceRequired")
.HasColumnName("is_insurance_required")
.HasColumnType("boolean");
b1.HasKey("InternshipEntityId")
.HasName("pk_internships");
b1.ToTable("internships");
b1.WithOwner()
.HasForeignKey("InternshipEntityId")
.HasConstraintName("fk_insurance_internships_internship_entity_id");
});
});
modelBuilder.Entity("Internship.Core.InternshipProgramSubject", b =>
{
b.HasOne("Internship.Core.Course", "Course")
.WithMany()
.HasForeignKey("CourseId")
.HasConstraintName("fk_internship_program_subject_course_course_id");
b.HasOne("Internship.Core.Edition", null)
.WithMany("Subjects")
.HasForeignKey("EditionId")
.HasConstraintName("fk_internship_program_subject_editions_edition_id");
b.HasOne("Internship.Core.InternshipEntity", null)
.WithMany("Program")
.HasForeignKey("InternshipEntityId")
.HasConstraintName("fk_internship_program_subject_internships_internship_entity_id");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,271 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Internship.Repository.Migrations
{
public partial class InitialCreate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "companies",
columns: table => new
{
nip = table.Column<string>(nullable: false),
name = table.Column<string>(nullable: true),
range = table.Column<int>(nullable: false),
site_address = table.Column<string>(nullable: true),
provider = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_companies", x => x.nip);
});
migrationBuilder.CreateTable(
name: "course",
columns: table => new
{
id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
name = table.Column<string>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_course", x => x.id);
});
migrationBuilder.CreateTable(
name: "editions",
columns: table => new
{
id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
start_date = table.Column<DateTime>(nullable: false),
end_date = table.Column<DateTime>(nullable: false),
ipp_deadline_date = table.Column<DateTime>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_editions", x => x.id);
});
migrationBuilder.CreateTable(
name: "reports",
columns: table => new
{
id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
},
constraints: table =>
{
table.PrimaryKey("pk_reports", x => x.id);
});
migrationBuilder.CreateTable(
name: "branch_office",
columns: table => new
{
id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
street = table.Column<string>(nullable: true),
building = table.Column<string>(nullable: true),
city = table.Column<string>(nullable: true),
postal_code = table.Column<string>(nullable: true),
country = table.Column<string>(nullable: true),
company_nip = table.Column<string>(nullable: true),
provider = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_branch_office", x => x.id);
table.ForeignKey(
name: "fk_branch_office_companies_company_nip",
column: x => x.company_nip,
principalTable: "companies",
principalColumn: "nip",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "interns",
columns: table => new
{
album_number = table.Column<string>(nullable: false),
name = table.Column<string>(nullable: true),
surname = table.Column<string>(nullable: true),
email = table.Column<string>(nullable: true),
course_id = table.Column<int>(nullable: true),
semester = table.Column<int>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_interns", x => x.album_number);
table.ForeignKey(
name: "fk_interns_course_course_id",
column: x => x.course_id,
principalTable: "course",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "internships",
columns: table => new
{
id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
intern_album_number = table.Column<string>(nullable: true),
edition_id = table.Column<int>(nullable: true),
report_id = table.Column<int>(nullable: true),
branch_office_id = table.Column<int>(nullable: true),
type = table.Column<int>(nullable: false),
start_date = table.Column<DateTime>(nullable: false),
end_date = table.Column<DateTime>(nullable: false),
is_accepted = table.Column<bool>(nullable: false),
acceptance_date = table.Column<DateTime>(nullable: true),
is_deans_acceptance_required = table.Column<bool>(nullable: true),
reason = table.Column<int>(nullable: true),
insurance_delivery_date = table.Column<DateTime>(nullable: true),
is_insurance_required = table.Column<bool>(nullable: true),
internship_length_in_weeks = table.Column<int>(nullable: false),
grade = table.Column<float>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("pk_internships", x => x.id);
table.ForeignKey(
name: "fk_internships_branch_office_branch_office_id",
column: x => x.branch_office_id,
principalTable: "branch_office",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "fk_internships_editions_edition_id",
column: x => x.edition_id,
principalTable: "editions",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "fk_internships_interns_intern_album_number",
column: x => x.intern_album_number,
principalTable: "interns",
principalColumn: "album_number",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "fk_internships_reports_report_id",
column: x => x.report_id,
principalTable: "reports",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "internship_program_subject",
columns: table => new
{
id = table.Column<int>(nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
course_id = table.Column<int>(nullable: true),
description = table.Column<string>(nullable: true),
edition_id = table.Column<int>(nullable: true),
internship_entity_id = table.Column<int>(nullable: true)
},
constraints: table =>
{
table.PrimaryKey("pk_internship_program_subject", x => x.id);
table.ForeignKey(
name: "fk_internship_program_subject_course_course_id",
column: x => x.course_id,
principalTable: "course",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "fk_internship_program_subject_editions_edition_id",
column: x => x.edition_id,
principalTable: "editions",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "fk_internship_program_subject_internships_internship_entity_id",
column: x => x.internship_entity_id,
principalTable: "internships",
principalColumn: "id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "ix_branch_office_company_nip",
table: "branch_office",
column: "company_nip");
migrationBuilder.CreateIndex(
name: "ix_interns_course_id",
table: "interns",
column: "course_id");
migrationBuilder.CreateIndex(
name: "ix_internship_program_subject_course_id",
table: "internship_program_subject",
column: "course_id");
migrationBuilder.CreateIndex(
name: "ix_internship_program_subject_edition_id",
table: "internship_program_subject",
column: "edition_id");
migrationBuilder.CreateIndex(
name: "ix_internship_program_subject_internship_entity_id",
table: "internship_program_subject",
column: "internship_entity_id");
migrationBuilder.CreateIndex(
name: "ix_internships_branch_office_id",
table: "internships",
column: "branch_office_id");
migrationBuilder.CreateIndex(
name: "ix_internships_edition_id",
table: "internships",
column: "edition_id");
migrationBuilder.CreateIndex(
name: "ix_internships_intern_album_number",
table: "internships",
column: "intern_album_number");
migrationBuilder.CreateIndex(
name: "ix_internships_report_id",
table: "internships",
column: "report_id");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "internship_program_subject");
migrationBuilder.DropTable(
name: "internships");
migrationBuilder.DropTable(
name: "branch_office");
migrationBuilder.DropTable(
name: "editions");
migrationBuilder.DropTable(
name: "interns");
migrationBuilder.DropTable(
name: "reports");
migrationBuilder.DropTable(
name: "companies");
migrationBuilder.DropTable(
name: "course");
}
}
}

View File

@ -0,0 +1,426 @@
// <auto-generated />
using System;
using Internship.Repository;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Internship.Repository.Migrations
{
[DbContext(typeof(InternshipDbContext))]
partial class InternshipDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
.HasAnnotation("ProductVersion", "3.1.5")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
modelBuilder.Entity("Internship.Core.BranchOffice", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("CompanyNip")
.HasColumnName("company_nip")
.HasColumnType("text");
b.Property<int>("Provider")
.HasColumnName("provider")
.HasColumnType("integer");
b.HasKey("Id")
.HasName("pk_branch_office");
b.HasIndex("CompanyNip")
.HasName("ix_branch_office_company_nip");
b.ToTable("branch_office");
});
modelBuilder.Entity("Internship.Core.Company", b =>
{
b.Property<string>("Nip")
.HasColumnName("nip")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnName("name")
.HasColumnType("text");
b.Property<int>("Provider")
.HasColumnName("provider")
.HasColumnType("integer");
b.Property<int>("Range")
.HasColumnName("range")
.HasColumnType("integer");
b.Property<string>("SiteAddress")
.HasColumnName("site_address")
.HasColumnType("text");
b.HasKey("Nip")
.HasName("pk_companies");
b.ToTable("companies");
});
modelBuilder.Entity("Internship.Core.Course", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name")
.HasColumnName("name")
.HasColumnType("text");
b.HasKey("Id")
.HasName("pk_course");
b.ToTable("course");
});
modelBuilder.Entity("Internship.Core.Edition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<DateTime>("EndDate")
.HasColumnName("end_date")
.HasColumnType("timestamp without time zone");
b.Property<DateTime>("IPPDeadlineDate")
.HasColumnName("ipp_deadline_date")
.HasColumnType("timestamp without time zone");
b.Property<DateTime>("StartDate")
.HasColumnName("start_date")
.HasColumnType("timestamp without time zone");
b.HasKey("Id")
.HasName("pk_editions");
b.ToTable("editions");
});
modelBuilder.Entity("Internship.Core.Intern", b =>
{
b.Property<string>("AlbumNumber")
.HasColumnName("album_number")
.HasColumnType("text");
b.Property<int?>("CourseId")
.HasColumnName("course_id")
.HasColumnType("integer");
b.Property<string>("Email")
.HasColumnName("email")
.HasColumnType("text");
b.Property<string>("Name")
.HasColumnName("name")
.HasColumnType("text");
b.Property<int>("Semester")
.HasColumnName("semester")
.HasColumnType("integer");
b.Property<string>("Surname")
.HasColumnName("surname")
.HasColumnType("text");
b.HasKey("AlbumNumber")
.HasName("pk_interns");
b.HasIndex("CourseId")
.HasName("ix_interns_course_id");
b.ToTable("interns");
});
modelBuilder.Entity("Internship.Core.InternshipEntity", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int?>("BranchOfficeId")
.HasColumnName("branch_office_id")
.HasColumnType("integer");
b.Property<int?>("EditionId")
.HasColumnName("edition_id")
.HasColumnType("integer");
b.Property<DateTime>("EndDate")
.HasColumnName("end_date")
.HasColumnType("timestamp without time zone");
b.Property<float>("Grade")
.HasColumnName("grade")
.HasColumnType("real");
b.Property<string>("InternAlbumNumber")
.HasColumnName("intern_album_number")
.HasColumnType("text");
b.Property<int>("InternshipLengthInWeeks")
.HasColumnName("internship_length_in_weeks")
.HasColumnType("integer");
b.Property<bool>("IsAccepted")
.HasColumnName("is_accepted")
.HasColumnType("boolean");
b.Property<int?>("ReportId")
.HasColumnName("report_id")
.HasColumnType("integer");
b.Property<DateTime>("StartDate")
.HasColumnName("start_date")
.HasColumnType("timestamp without time zone");
b.Property<int>("Type")
.HasColumnName("type")
.HasColumnType("integer");
b.HasKey("Id")
.HasName("pk_internships");
b.HasIndex("BranchOfficeId")
.HasName("ix_internships_branch_office_id");
b.HasIndex("EditionId")
.HasName("ix_internships_edition_id");
b.HasIndex("InternAlbumNumber")
.HasName("ix_internships_intern_album_number");
b.HasIndex("ReportId")
.HasName("ix_internships_report_id");
b.ToTable("internships");
});
modelBuilder.Entity("Internship.Core.InternshipProgramSubject", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int?>("CourseId")
.HasColumnName("course_id")
.HasColumnType("integer");
b.Property<string>("Description")
.HasColumnName("description")
.HasColumnType("text");
b.Property<int?>("EditionId")
.HasColumnName("edition_id")
.HasColumnType("integer");
b.Property<int?>("InternshipEntityId")
.HasColumnName("internship_entity_id")
.HasColumnType("integer");
b.HasKey("Id")
.HasName("pk_internship_program_subject");
b.HasIndex("CourseId")
.HasName("ix_internship_program_subject_course_id");
b.HasIndex("EditionId")
.HasName("ix_internship_program_subject_edition_id");
b.HasIndex("InternshipEntityId")
.HasName("ix_internship_program_subject_internship_entity_id");
b.ToTable("internship_program_subject");
});
modelBuilder.Entity("Internship.Core.Report", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.HasKey("Id")
.HasName("pk_reports");
b.ToTable("reports");
});
modelBuilder.Entity("Internship.Core.BranchOffice", b =>
{
b.HasOne("Internship.Core.Company", "Company")
.WithMany("Branches")
.HasForeignKey("CompanyNip")
.HasConstraintName("fk_branch_office_companies_company_nip");
b.OwnsOne("Internship.Core.Address", "Address", b1 =>
{
b1.Property<int>("BranchOfficeId")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b1.Property<string>("Building")
.HasColumnName("building")
.HasColumnType("text");
b1.Property<string>("City")
.HasColumnName("city")
.HasColumnType("text");
b1.Property<string>("Country")
.HasColumnName("country")
.HasColumnType("text");
b1.Property<string>("PostalCode")
.HasColumnName("postal_code")
.HasColumnType("text");
b1.Property<string>("Street")
.HasColumnName("street")
.HasColumnType("text");
b1.HasKey("BranchOfficeId")
.HasName("pk_branch_office");
b1.ToTable("branch_office");
b1.WithOwner()
.HasForeignKey("BranchOfficeId")
.HasConstraintName("fk_address_branch_office_branch_office_id");
});
});
modelBuilder.Entity("Internship.Core.Intern", b =>
{
b.HasOne("Internship.Core.Course", "Course")
.WithMany()
.HasForeignKey("CourseId")
.HasConstraintName("fk_interns_course_course_id");
});
modelBuilder.Entity("Internship.Core.InternshipEntity", b =>
{
b.HasOne("Internship.Core.BranchOffice", "BranchOffice")
.WithMany()
.HasForeignKey("BranchOfficeId")
.HasConstraintName("fk_internships_branch_office_branch_office_id");
b.HasOne("Internship.Core.Edition", "Edition")
.WithMany()
.HasForeignKey("EditionId")
.HasConstraintName("fk_internships_editions_edition_id");
b.HasOne("Internship.Core.Intern", "Intern")
.WithMany()
.HasForeignKey("InternAlbumNumber")
.HasConstraintName("fk_internships_interns_intern_album_number");
b.HasOne("Internship.Core.Report", "Report")
.WithMany()
.HasForeignKey("ReportId")
.HasConstraintName("fk_internships_reports_report_id");
b.OwnsOne("Internship.Core.DeanAcceptance", "DeanAcceptance", b1 =>
{
b1.Property<int>("InternshipEntityId")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b1.Property<DateTime>("AcceptanceDate")
.HasColumnName("acceptance_date")
.HasColumnType("timestamp without time zone");
b1.Property<bool>("IsDeansAcceptanceRequired")
.HasColumnName("is_deans_acceptance_required")
.HasColumnType("boolean");
b1.Property<int>("Reason")
.HasColumnName("reason")
.HasColumnType("integer");
b1.HasKey("InternshipEntityId")
.HasName("pk_internships");
b1.ToTable("internships");
b1.WithOwner()
.HasForeignKey("InternshipEntityId")
.HasConstraintName("fk_dean_acceptance_internships_internship_entity_id");
});
b.OwnsOne("Internship.Core.Insurance", "Insurance", b1 =>
{
b1.Property<int>("InternshipEntityId")
.ValueGeneratedOnAdd()
.HasColumnName("id")
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b1.Property<DateTime>("InsuranceDeliveryDate")
.HasColumnName("insurance_delivery_date")
.HasColumnType("timestamp without time zone");
b1.Property<bool>("IsInsuranceRequired")
.HasColumnName("is_insurance_required")
.HasColumnType("boolean");
b1.HasKey("InternshipEntityId")
.HasName("pk_internships");
b1.ToTable("internships");
b1.WithOwner()
.HasForeignKey("InternshipEntityId")
.HasConstraintName("fk_insurance_internships_internship_entity_id");
});
});
modelBuilder.Entity("Internship.Core.InternshipProgramSubject", b =>
{
b.HasOne("Internship.Core.Course", "Course")
.WithMany()
.HasForeignKey("CourseId")
.HasConstraintName("fk_internship_program_subject_course_course_id");
b.HasOne("Internship.Core.Edition", null)
.WithMany("Subjects")
.HasForeignKey("EditionId")
.HasConstraintName("fk_internship_program_subject_editions_edition_id");
b.HasOne("Internship.Core.InternshipEntity", null)
.WithMany("Program")
.HasForeignKey("InternshipEntityId")
.HasConstraintName("fk_internship_program_subject_internships_internship_entity_id");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -1,45 +0,0 @@
using System;
using AutoMapper;
using InternshipSystem.Api.Queries;
using InternshipSystem.Api.Result;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity;
using InternshipSystem.Core.Entity.Internship;
using InternshipSystem.Core.UglyOrmArtifacts;
namespace InternshipSystem.Api
{
public class ApiProfile : Profile
{
public ApiProfile()
{
CreateMap<DocumentPublishRequest, Document>();
CreateMap<Edition, EditionResult>()
.ForMember(
result => result.Status,
opt => opt.MapFrom(edition => edition.IsOpen ? "Open" : "Archival"));
CreateMap<Edition, EditionManagementResult>();
CreateMap<Edition, EditionDetailsResult>();
CreateMap<Edition, EditionConfigurationResult>();
CreateMap<InternshipSubject, InternshipSubject>();
CreateMap<EditionSubject, InternshipSubject>()
.IncludeMembers(es => es.Subject);
CreateMap<EditionInternshipType, InternshipType>()
.IncludeMembers(eit => eit.InternshipType);
CreateMap<ReportFieldEdition, ReportField>()
.IncludeMembers(e => e.Field);
CreateMap<ReportField, ReportField>();
CreateMap<InternshipType, InternshipType>();
}
}
}

View File

@ -1,53 +0,0 @@
using System;
using System.Collections.Generic;
using IdentityServer4.Extensions;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity.Internship;
namespace InternshipSystem.Api.Commands
{
public class UpdateRegistrationForm
{
public UpdateCompany? Company { get; set; }
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
public UpdateMentor? Mentor { get; set; }
public List<long> Subjects { get; set; }
public int? Hours { get; set; }
public long? Type { get; set; }
}
public struct UpdateMentor
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
}
public struct UpdateCompany
{
public long? Id { get; set; }
public string Nip { get; set; }
public string Name { get; set; }
public UpdateBranchOffice? BranchOffice { get; set; }
public bool IsCustomUpdate => !Nip.IsNullOrEmpty() || !Name.IsNullOrEmpty();
}
public struct UpdateBranchOffice
{
public long? Id { get; set; }
public string Street { get; set; }
public string Building { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public bool IsCustomUpdate => !string.IsNullOrEmpty(Street) ||
!string.IsNullOrEmpty(Building) ||
!string.IsNullOrEmpty(City) ||
!string.IsNullOrEmpty(PostalCode) ||
!string.IsNullOrEmpty(Country);
}
}

View File

@ -1,117 +0,0 @@
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Options;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace InternshipSystem.Api.Controllers
{
[Route("access")]
[ApiController]
public class AccessController : ControllerBase
{
private readonly InternshipDbContext _context;
private readonly JwtTokenService _tokenService;
private readonly GutCasClient _loginClient;
private readonly SecurityOptions _securityOptions;
public AccessController(
IOptions<SecurityOptions> options,
InternshipDbContext context,
JwtTokenService tokenService,
GutCasClient loginClient)
{
_context = context;
_tokenService = tokenService;
_loginClient = loginClient;
_securityOptions = options.Value;
}
[HttpPost("login")]
public async Task<ActionResult> Authenticate([FromBody] string code, CancellationToken cancellationToken)
{
var token = await _loginClient.GetCasTokenAsync(code, cancellationToken);
var casData = await _loginClient.GetProfileAsync(token, cancellationToken);
if (!long.TryParse(casData.PersonNumber, out var id))
{
return BadRequest();
}
var student = await _context.Students.FirstOrDefaultAsync(s => s.Id == id, cancellationToken: cancellationToken);
if (student == null)
{
student = CreateStudentWithCasData(casData);
await _context.Students.AddAsync(student, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
}
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, student.FirstName),
new Claim(ClaimTypes.Surname, student.LastName),
new Claim(InternshipClaims.PersonNumber, student.Id.ToString())
});
return Ok(_tokenService.generateToken(identity));
}
[HttpGet("/dev/login")]
public async Task<ActionResult> Authenticate(CancellationToken cancellationToken)
{
var identity = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, "firstname"),
new Claim(ClaimTypes.Surname, "lastname"),
new Claim(InternshipClaims.PersonNumber, "1")
});
return Ok(_tokenService.generateToken(identity));
}
[HttpPost("loginEdition")]
[Authorize]
public async Task<ActionResult> LoginIntoEdition([FromBody] Guid editionId, [FromServices] User user, CancellationToken token)
{
var edition = await _context.Editions.FindAsync(editionId);
var hasInternship = await _context.Entry(edition)
.Collection(e => e.Internships)
.Query()
.AnyAsync(i => i.Student.Id == user.PersonNumber, token);
if (!hasInternship)
{
return Unauthorized("Student isn't registered for this edition");
}
var newIdentity = User.Identities.First();
newIdentity.AddClaim(new Claim(InternshipClaims.Edition, editionId.ToString()));
return Ok(_tokenService.generateToken(newIdentity));
}
private Student CreateStudentWithCasData(CasUserData casData)
{
var id = long.Parse(casData.PersonNumber);
var firstName = casData.FirstName;
var lastName = casData.LastName;
var email = casData.Mail.First(s => s.EndsWith("@student.pg.edu.pl"));
var albumNumber = int.Parse(casData.AlbumNumber);
return Student.CreateStudent(id, firstName, lastName, email, albumNumber);
}
}
}

View File

@ -1,53 +0,0 @@
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Mvc;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("admin")]
public class AdminController : ControllerBase
{
public AdminController(DatabaseFiller fillerService)
{
FillerService = fillerService;
}
public DatabaseFiller FillerService { get; }
// [HttpPost("fill")]
// public async Task<IActionResult> FillAll()
// {
// await FillerService.FillAll();
// return Ok();
// }
//
// [HttpPost("fill/companies")]
// public async Task<IActionResult> FillCompaniesAsync()
// {
// await FillerService.FillCompanies();
// return Ok();
// }
//
// [HttpPost("fill/internshipTypes")]
// public async Task<IActionResult> FillInternshipTypesAsync()
// {
// await FillerService.FillInternshipTypes();
// return Ok();
// }
//
// [HttpPost("fill/editions")]
// public async Task<IActionResult> FillEditionsAsync()
// {
// await FillerService.FillEditions();
// return Ok();
// }
//
// [HttpPost("fill/staticPages")]
// public async Task<IActionResult> FillStaticPagesAsync()
// {
// await FillerService.FillStaticPages();
// return Ok();
// }
}
}

View File

@ -1,256 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Queries;
using InternshipSystem.Api.Queries.SearchQuery;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using static System.String;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("companies")]
public class CompaniesController : ControllerBase
{
public CompaniesController(InternshipDbContext context)
{
Context = context;
}
private InternshipDbContext Context { get; }
/// <summary>
/// Get companies matching provided paginated query
/// </summary>
/// <param name="searchQuery">Paginated query description</param>
/// <response code="200">Successfully retrieved Companies</response>
/// <response code="400">Search query was malformed</response>
/// <returns>Part of companies collection</returns>
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<IReadOnlyCollection<Company>>> SearchByNameAsync([FromQuery] CompanySearchQuery searchQuery, [FromServices] User user, CancellationToken cancellationToken) =>
await Context.Companies
.Where(c => c.Name.ToLower().Contains(searchQuery.Name.ToLower()))
.Where(c => c.Provider == 0 || c.Provider == user.PersonNumber)
.OrderBy(o => o.Name)
.Skip(searchQuery.Page * searchQuery.PerPage)
.Take(searchQuery.PerPage)
.ToListAsync(cancellationToken);
/// <summary>
/// Get company branches matching provided paginated query
/// </summary>
/// <param name="searchQuery">Paginated query description</param>
/// <param name="companyId"></param>
/// <response code="200">Successfully retrieved matching offices</response>
/// <response code="400">Search query was malformed</response>
/// <returns>Part of companies collection</returns>
[HttpGet("{companyId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize]
public async Task<ActionResult<IReadOnlyCollection<BranchOffice>>> SearchBranchesByAddress([FromQuery] BranchOfficeSearchQuery searchQuery, long companyId, [FromServices] User user, CancellationToken token)
{
var company = await Context.Companies.Where(c => c.Id == companyId).FirstAsync(token);
return await Context.Entry(company)
.Collection(c => c.Branches)
.Query()
.Where(office => office.Address.City.ToLower().Contains(searchQuery.City.ToLower()))
.Where(office => office.Provider == 0 || office.Provider == user.PersonNumber)
.Skip(searchQuery.Page * searchQuery.PerPage)
.Take(searchQuery.PerPage)
.ToListAsync(token);
}
/// <summary>
/// Updates or add new company (if not new than contains id)
/// </summary>
/// <param name="companyForm"></param>
/// <response code="200">Successfully updated company</response>
/// <response code="400">Company form was malformed</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Company not found</response>
/// <returns></returns>
[HttpPut]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult> UpsertCompany([FromBody] CompanyForm companyForm, CancellationToken cancellationToken)
{
var validator = new CompanyForm.Validator();
var validationResult = await validator.ValidateAsync(companyForm, cancellationToken);
if (!validationResult.IsValid)
{
return BadRequest(validationResult.ToString());
}
if (companyForm.Id.HasValue)
{
var companyToUpdate = await Context.Companies.FindAsync(companyForm.Id.Value);
if (companyToUpdate == null)
{
return NotFound();
}
companyToUpdate.Name = IsNullOrEmpty(companyForm.Name) ? companyToUpdate.Name : companyForm.Name;
companyToUpdate.Nip = IsNullOrEmpty(companyForm.Nip) ? companyToUpdate.Nip : companyForm.Nip;
}
else
{
var newCompany = Company.CreateCompany(companyForm.Nip, companyForm.Name);
await Context.Companies.AddAsync(newCompany, cancellationToken);
}
await Context.SaveChangesAsync(cancellationToken);
return Ok();
}
/// <summary>
/// Deletes existing company by id
/// </summary>
/// <param name="companyId"></param>
/// <response code="200">Successfully deleted company</response>
/// <response code="400">Company id is empty</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Company not found</response>
/// <returns></returns>
[HttpDelete("{companyId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult> DeleteCompany(long companyId, CancellationToken cancellationToken)
{
var companyToDelete = await Context.Companies
.Include(c => c.Branches)
.FirstOrDefaultAsync(c => c.Id == companyId, cancellationToken);
if (companyToDelete == null)
{
return NotFound();
}
Context.Companies.Remove(companyToDelete);
await Context.SaveChangesAsync(cancellationToken);
return Ok();
}
/// <summary>
/// Updates or add new branchOffice (if not new than contains id)
/// </summary>
/// <param name="branchOfficeForm"></param>
/// <param name="companyId"></param>
/// <response code="200">Successfully updated company branch office</response>
/// <response code="400">Branch office was malformed</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Company or branch office not found</response>
/// <returns></returns>
[HttpPut("{companyId}/branchOffices")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult> UpdateBranch([FromBody] BranchOfficeForm branchOfficeForm, long companyId, CancellationToken cancellationToken)
{
var validator = new BranchOfficeForm.Validator();
var validationResult = await validator.ValidateAsync(branchOfficeForm, cancellationToken);
if (!validationResult.IsValid)
{
return BadRequest(validationResult.ToString());
}
var company = await Context.Companies
.Include(c => c.Branches)
.FirstOrDefaultAsync(c => c.Id == companyId, cancellationToken);
if (company == null)
{
return NotFound();
}
if (branchOfficeForm.Id.HasValue)
{
var branchOffice = company.Branches.First(b => b.Id == branchOfficeForm.Id);
if (branchOffice == null)
{
return NotFound();
}
branchOffice.Address.Country = IsNullOrEmpty(branchOfficeForm.Country) ? branchOffice.Address.Country : branchOfficeForm.Country;
branchOffice.Address.City = IsNullOrEmpty(branchOfficeForm.City) ? branchOffice.Address.City : branchOfficeForm.City;
branchOffice.Address.PostalCode = IsNullOrEmpty(branchOfficeForm.PostalCode) ? branchOffice.Address.PostalCode : branchOfficeForm.PostalCode;
branchOffice.Address.Street = IsNullOrEmpty(branchOfficeForm.Street) ? branchOffice.Address.Street : branchOfficeForm.Street;
branchOffice.Address.Building = IsNullOrEmpty(branchOfficeForm.Building) ? branchOffice.Address.Building : branchOfficeForm.Building;
}
else
{
var newBranchOffice = new BranchOffice
{
Address = new BranchAddress
{
Country = branchOfficeForm.Country,
City = branchOfficeForm.City,
PostalCode = branchOfficeForm.PostalCode,
Street = branchOfficeForm.Street,
Building = branchOfficeForm.Building,
}
};
company.Branches.Add(newBranchOffice);
}
await Context.SaveChangesAsync(cancellationToken);
return Ok();
}
/// <summary>
/// Deletes existing branchOffice
/// </summary>
/// <param name="branchOfficeId"></param>
/// <response code="200">Successfully deleted company branch office</response>
/// <response code="400">Branch office id is empty</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Company or branch office not found</response>
[HttpDelete("{companyId}/branchOffice/{branchOfficeId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult> DeleteBranch(long companyId, long branchOfficeId, CancellationToken cancellationToken)
{
var company =
await Context.Companies
.Include(c => c.Branches)
.Where(c => c.Id == companyId)
.FirstOrDefaultAsync(cancellationToken);
if (company == null)
{
return NotFound();
}
var branchOffice = company.Branches.RemoveAll(b => b.Id == branchOfficeId);
await Context.SaveChangesAsync(cancellationToken);
return Ok();
}
}
}

View File

@ -1,127 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Queries;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("management/course")]
public class CourseController : ControllerBase
{
private InternshipDbContext Context { get; }
public CourseController(InternshipDbContext context)
{
Context = context;
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult<IReadOnlyCollection<Course>>> GetCourses(CancellationToken cancellationToken) =>
await Context.Courses
.ToListAsync(cancellationToken);
[HttpGet("{courseId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult<Course>> GetCourse(long courseId, CancellationToken cancellationToken)
{
var course = await Context.Courses
.Where(c => c.Id == courseId)
.FirstOrDefaultAsync(cancellationToken);
if (course == null)
{
return NotFound();
}
return Ok(course);
}
[HttpPut]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> UpsertCourse([FromBody] CourseForm courseForm, CancellationToken cancellationToken)
{
var validator = new CourseForm.Validator();
var validationResult = await validator.ValidateAsync(courseForm, cancellationToken);
if (!validationResult.IsValid)
{
return BadRequest(validationResult.ToString());
}
if (courseForm.Id.HasValue)
{
var course = await Context.Courses.FindAsync(courseForm.Id.Value);
if (course == null)
{
return NotFound();
}
course.UpdateCourse(courseForm.Name, courseForm.NameEng);
}
else
{
var newCourse = Course.CreateCourse(courseForm.Name, courseForm.NameEng);
await Context.Courses.AddAsync(newCourse, cancellationToken);
}
await Context.SaveChangesAsync(cancellationToken);
return Ok();
}
[HttpDelete("{courseId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> DeleteCourse(long courseId, CancellationToken cancellationToken)
{
var courseToDelete = await Context.Courses
.Where(c => c.Id == courseId)
.FirstOrDefaultAsync(cancellationToken);
if (courseToDelete == null)
{
return NotFound();
}
var referencedEditions =
await Context.Editions
.Include(e => e.Course)
.Where(e => e.Course.Id == courseToDelete.Id)
.CountAsync(cancellationToken);
if (referencedEditions > 0)
{
return Conflict();
}
Context.Courses.Remove(courseToDelete);
await Context.SaveChangesAsync(cancellationToken);
return Ok();
}
}
}

View File

@ -1,110 +0,0 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("management/document")]
public class DocumentManagementController : ControllerBase
{
private InternshipDbContext Context { get; }
public DocumentManagementController(InternshipDbContext context)
{
Context = context;
}
[HttpDelete("{documentId}/delete")]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> DeleteDocument(long documentId, CancellationToken ct)
{
var internship = await Context.Internships
.Include(i => i.Documentation)
.FirstOrDefaultAsync(i => i.Documentation.Any(d => d.Id.Equals(documentId)), ct);
if (internship == null)
{
return NotFound();
}
internship.RemoveDocument(documentId);
await Context.SaveChangesAsync(ct);
return Ok();
}
[HttpPut("{documentId}/accept")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> AcceptDocument(long documentId, [FromBody] string comment, CancellationToken token)
{
var internship = await Context.Internships
.Include(i => i.Documentation)
.FirstOrDefaultAsync(i => i.Documentation.Any(d => d.Id.Equals(documentId)), token);
if (internship == null)
{
return NotFound();
}
var document = internship.Documentation
.FirstOrDefault(d => d.Id.Equals(documentId));
if (document == null)
{
return NotFound();
}
document.State = DocumentState.Accepted;
document.ChangeStateComment = string.IsNullOrEmpty(comment) ? null : comment;
await Context.SaveChangesAsync(token);
return Ok();
}
[HttpPut("{documentId}/reject")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> RejectDocument(long documentId, [FromBody] string comment, CancellationToken token)
{
var internship = await Context.Internships
.Include(i => i.Documentation)
.FirstOrDefaultAsync(i => i.Documentation.Any(d => d.Id.Equals(documentId)), token);
if (internship == null)
{
return NotFound();
}
var document = internship.Documentation
.FirstOrDefault(d => d.Id.Equals(documentId));
if (document == null)
{
return NotFound();
}
document.State = DocumentState.Rejected;
document.ChangeStateComment = string.IsNullOrEmpty(comment) ? null : comment;
await Context.SaveChangesAsync(token);
return Ok();
}
}
}

View File

@ -1,181 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Queries;
using InternshipSystem.Api.Security;
using InternshipSystem.Api.Service;
using InternshipSystem.Core;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("document")]
public class DocumentsController : ControllerBase
{
private readonly InternshipDbContext _context;
private readonly FileValidator _fileValidator;
public DocumentsController(InternshipDbContext context, FileValidator fileValidator)
{
_context = context;
_fileValidator = fileValidator;
}
/// <summary>
/// Fill out required document,
/// </summary>
/// <param name="documentRequest">Documents Scan and description, and Id of filled document</param>
/// <response code="200">If change was successfully registered</response>
/// <response code="400">If the provided query was malformed</response>
/// <response code="404">Id doesn't match any required document</response>
/// <response code="401">This action is only available for authorized student registered for current edition</response>
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult> AddDocumentToInternship(
[FromBody] DocumentPublishRequest documentRequest,
[FromServices] User user,
CancellationToken cancellationToken)
{
var validator = new DocumentPublishRequest.Validator();
var result = await validator.ValidateAsync(documentRequest, cancellationToken);
if (!result.IsValid)
{
return BadRequest(result.ToString());
}
var edition = await _context.Editions.FirstAsync(e => e.Id == user.EditionId, cancellationToken);
var internship =
await _context.Entry(edition)
.Collection(e => e.Internships)
.Query()
.Include(i => i.Documentation)
.FirstAsync(i => i.Student.Id == user.PersonNumber, cancellationToken);
try
{
internship.AddNewDocument(documentRequest.Description, documentRequest.Type);
await _context.SaveChangesAsync(cancellationToken);
}
catch (ArgumentException e)
{
return BadRequest(e.Message);
}
return Ok(internship.Documentation.First(d => d.Type == documentRequest.Type));
}
[HttpPut("{documentId}/scan")]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult> AddDocumentScan(long documentId, IFormFile documentScan, [FromServices] User user, CancellationToken cancellationToken)
{
await using var memoryStream = new MemoryStream();
await documentScan.CopyToAsync(memoryStream, cancellationToken);
if (!_fileValidator.IsValidFile(memoryStream.ToArray()))
{
return BadRequest("error.document.scan");
}
var edition = await _context.Editions.FirstAsync(e => e.Id == user.EditionId, cancellationToken);
var internship =
await _context.Entry(edition)
.Collection(e => e.Internships)
.Query()
.Include(i => i.Documentation)
.FirstAsync(i => i.Student.Id == user.PersonNumber, cancellationToken);
var document = await _context.Entry(internship)
.Collection(i => i.Documentation)
.Query()
.Include(d => d.Scan)
.FirstAsync(d => d.Id == documentId, cancellationToken);
document.Scan ??= new DocumentScan();
document.Scan.Size = memoryStream.Length;
document.Scan.Filename = documentScan.FileName;
document.Scan.Mime = _fileValidator.GetFileMime(memoryStream.ToArray());
document.Scan.File = memoryStream.ToArray();
document.State = DocumentState.Submitted;
await _context.SaveChangesAsync(cancellationToken);
return Ok();
}
[HttpGet("{documentId}/scan/download")]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult> GetDocumentScan(long documentId, [FromQuery] string disposition, [FromServices] User user, CancellationToken cancellationToken)
{
var edition = await _context.Editions.FirstAsync(e => e.Id == user.EditionId, cancellationToken);
var internship =
await _context.Entry(edition)
.Collection(e => e.Internships)
.Query()
.FirstAsync(i => i.Student.Id == user.PersonNumber, cancellationToken);
var document =
await _context.Entry(internship)
.Collection(i => i.Documentation)
.Query()
.Include(d => d.Scan)
.FirstOrDefaultAsync(d => d.Id == documentId, cancellationToken);
var stream = new MemoryStream(document.Scan.File);
Response.Headers.Add("Content-Disposition", new ContentDisposition
{
Inline = disposition == "inline",
FileName = document.Scan.Filename,
Size = document.Scan.Size
}.ToString());
return File(stream, document.Scan.Mime);
}
[HttpGet("{documentId}/scan")]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult> GetDocumentScanData(long documentId, [FromServices] User user, CancellationToken cancellationToken)
{
var edition = await _context.Editions.FirstAsync(e => e.Id == user.EditionId, cancellationToken);
var internship =
await _context.Entry(edition)
.Collection(e => e.Internships)
.Query()
.FirstAsync(i => i.Student.Id == user.PersonNumber, cancellationToken);
var scan =
await _context.Entry(internship)
.Collection(i => i.Documentation)
.Query()
.Include(d => d.Scan)
.Select(s => new {s.Id, s.Scan.Filename, s.Scan.Mime, s.Scan.Size})
.FirstOrDefaultAsync(d => d.Id == documentId, cancellationToken);
if (scan == null)
{
return NotFound();
}
return Ok(scan);
}
}
}

View File

@ -1,117 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using IdentityServer4.Extensions;
using InternshipSystem.Api.Result;
using InternshipSystem.Api.Security;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[Route("editions")]
public class EditionController : ControllerBase
{
private InternshipDbContext Context { get; }
private IMapper Mapper { get; }
public EditionController(InternshipDbContext context, IMapper mapper)
{
Context = context;
Mapper = mapper;
}
/// <summary>
/// Get accessible editions
/// </summary>
/// <response code="200">Editions accessible by the current user</response>
/// <response code="401">This action is only available for authorized student</response>
/// <returns></returns>
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult<IEnumerable<EditionResult>>> GetAvailableEditions([FromServices] User user, CancellationToken token)
{
var editions =
await Context.Editions
.Where(edition =>
edition.Internships
.Any(internship => internship.Student.Id == user.PersonNumber))
.ProjectTo<EditionResult>(Mapper.ConfigurationProvider)
.ToListAsync(token);
if (editions.IsNullOrEmpty())
{
return NotFound();
}
return Ok(editions);
}
/// <summary>
/// Get accessible editions
/// </summary>
/// <response code="200">Editions accessible by the current user</response>
/// <response code="401">This action is only available for authorized student</response>
/// <response code="404"/>
/// <returns></returns>
[HttpGet("{id}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<EditionResult>> GetEditionInfo(Guid id, CancellationToken token)
{
var edition =
await Context.Editions
.Where(e => e.Id == id)
.ProjectTo<EditionResult>(Mapper.ConfigurationProvider)
.FirstOrDefaultAsync(token);
if (edition == null)
{
return NotFound();
}
return Ok(edition);
}
/// <summary>
/// Get current edition's configuration
/// </summary>
/// <response code="200">Parameters of edition registered for by student</response>
/// <response code="401">This action is only available for authorized student registered for this edition edition</response>
/// <response code="404">Specified edition doesn't exist</response>
/// <returns></returns>
[HttpGet("current")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult<EditionConfigurationResult>> GetEditionsConfiguration([FromServices] User user, CancellationToken token)
{
var edition =
await Context.Editions
.Include(e => e.AvailableSubjects)
.Include(e => e.ReportSchema)
.ThenInclude(e => e.Field)
.Include(e => e.Course)
.Where(e => e.Id == user.EditionId)
.ProjectTo<EditionConfigurationResult>(Mapper.ConfigurationProvider)
.FirstOrDefaultAsync(token);
if (edition == null)
{
return NotFound();
}
return Ok(edition);
}
}
}

View File

@ -1,168 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using InternshipSystem.Api.Queries;
using InternshipSystem.Api.Queries.SearchQuery;
using InternshipSystem.Api.Result;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("management/editions")]
public class EditionManagementController : ControllerBase
{
private InternshipDbContext Context { get; }
private IMapper Mapper { get; }
public EditionManagementController(IMapper mapper, InternshipDbContext context)
{
Context = context;
Mapper = mapper;
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult<IReadOnlyCollection<EditionManagementResult>>> GetEditions([FromQuery] EditionSearchQuery searchQuery, CancellationToken token) =>
await Context.Editions
.Include(e => e.Course)
.Where(p => !searchQuery.Course.HasValue || p.Course.Id == searchQuery.Course)
.ProjectTo<EditionManagementResult>(Mapper.ConfigurationProvider)
.Skip(searchQuery.Page * searchQuery.PerPage)
.Take(searchQuery.PerPage)
.ToListAsync(token);
[HttpGet("{editionId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult<EditionDetailsResult>> GetFullEdition(Guid editionId, CancellationToken token)
{
var edition = await Context.Editions
.Include(e => e.Course)
.Include(e => e.AvailableSubjects)
.ThenInclude(s => s.Subject)
.Include(e => e.AvailableInternshipTypes)
.ThenInclude(i => i.InternshipType)
.Include(e => e.ReportSchema)
.ThenInclude(er => er.Field)
.Where(e => e.Id == editionId)
.ProjectTo<EditionDetailsResult>(Mapper.ConfigurationProvider)
.FirstOrDefaultAsync(token);
if (edition == null)
{
return NotFound();
}
return Ok(edition);
}
[HttpPut]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> UpsertEdition(EditionForm editionForm, CancellationToken token)
{
var validator = new EditionForm.Validator();
var validationResult = await validator.ValidateAsync(editionForm, token);
if (!validationResult.IsValid)
{
return BadRequest(validationResult.ToString());
}
if (editionForm.Id.HasValue)
{
var editionToUpdate = await Context.Editions
.Include(e => e.AvailableSubjects)
.Include(e => e.AvailableInternshipTypes)
.Include(e => e.ReportSchema)
.FirstOrDefaultAsync(e => e.Id == editionForm.Id.Value, token);
if (editionToUpdate == null)
{
return NotFound();
}
editionToUpdate.UpdateEdition(editionForm.EditionStart, editionForm.EditionFinish, editionForm.ReportingStart,
editionForm.Course, editionForm.AvailableSubjectsIds, editionForm.AvailableInternshipTypesIds, editionForm.ReportSchema);
if (!editionToUpdate.IsValidDates)
{
return BadRequest();
}
}
else
{
var newEdition =
Edition.CreateEdition(editionForm.EditionStart.Value, editionForm.EditionFinish.Value, editionForm.ReportingStart.Value,
editionForm.Course, editionForm.AvailableSubjectsIds, editionForm.AvailableInternshipTypesIds, editionForm.ReportSchema);
if (!newEdition.IsValidDates)
{
return BadRequest();
}
await Context.Editions.AddAsync(newEdition, token);
}
await Context.SaveChangesAsync(token);
return Ok();
}
[HttpDelete("{editionId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status409Conflict)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> DeleteEdition(Guid editionId, CancellationToken token)
{
var editionToDelete = await Context.Editions
.Include(e => e.AvailableSubjects)
.Include(e => e.AvailableInternshipTypes)
.Include(e => e.ReportSchema)
.FirstOrDefaultAsync(e => e.Id.Equals(editionId), token);
if (editionToDelete == null)
{
return NotFound();
}
var referencedInternships =
await Context
.Entry(editionToDelete)
.Collection(e => e.Internships)
.Query()
.CountAsync(token);
if (referencedInternships > 0)
{
return Conflict();
}
Context.Editions.Remove(editionToDelete);
await Context.SaveChangesAsync(token);
return Ok();
}
}
}

View File

@ -1,56 +0,0 @@
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Security;
using InternshipSystem.Core.Entity.Internship;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("internship")]
public class InternshipController : ControllerBase
{
private readonly InternshipDbContext _context;
public InternshipController(InternshipDbContext context)
{
_context = context;
}
/// <summary>
/// Get internship for current edition
/// </summary>
/// <response code="200">If current internship returned successfully</response>
/// <response code="401">This action is only available for authorized student registered for current edition</response>
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult<Internship>> GetCurrentEditionInternship([FromServices] User user, CancellationToken cancellationToken)
{
var edition = await _context.Editions
.FindAsync(user.EditionId);
var internship = await _context.Entry(edition)
.Collection(e => e.Internships)
.Query()
.Include(i => i.Student)
.Include(i => i.InternshipRegistration)
.Include(i => i.InternshipRegistration.Company)
.Include(i => i.InternshipRegistration.BranchAddress)
.Include(i => i.InternshipRegistration.Type)
.Include(i => i.InternshipRegistration.Subjects)
.ThenInclude(subject => subject.Subject)
.Include(i => i.Report)
.Include(i => i.Documentation)
.SingleAsync(i => i.Student.Id == user.PersonNumber, cancellationToken);
return Ok(internship);
}
}
}

View File

@ -1,190 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Queries.SearchQuery;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity.Internship;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("management/internship")]
public class InternshipManagementController : ControllerBase
{
private InternshipDbContext Context { get; }
public InternshipManagementController(InternshipDbContext context)
{
Context = context;
}
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult<IReadOnlyCollection<Internship>>> GetInternships([FromQuery] InternshipSearchQuery searchQuery, CancellationToken token)
{
var query =
Context.Internships
.Include(i => i.Edition)
.Include(i => i.InternshipRegistration)
.Include(i => i.InternshipRegistration.Type)
.Include(i => i.Student)
.Include(i => i.Documentation)
.Include(i => i.Report)
.Where(i => !searchQuery.EditionId.HasValue || i.Edition.Id == searchQuery.EditionId)
.Where(i => !searchQuery.InternshipState.HasValue || i.InternshipRegistration.State == searchQuery.InternshipState)
.Where(i => !searchQuery.InternshipState.HasValue || i.Report.State == searchQuery.ReportState)
.Where(i => !searchQuery.StudentAlbumNumber.HasValue || i.Student.AlbumNumber == searchQuery.StudentAlbumNumber)
.Where(i => string.IsNullOrEmpty(searchQuery.StudentFirstName) || i.Student.FirstName.ToLower().Contains(searchQuery.StudentFirstName.ToLower()))
.Where(i => string.IsNullOrEmpty(searchQuery.StudentLastName) || i.Student.LastName.ToLower().Contains(searchQuery.StudentLastName.ToLower()))
.Where(i => !searchQuery.DocumentWithState.HasValue || i.Documentation.Any(d => d.State == searchQuery.DocumentWithState))
.Skip(searchQuery.Page * searchQuery.PerPage)
.Take(searchQuery.PerPage);
if (searchQuery.OrderByField.ToLower().Equals("date"))
{
query = searchQuery.SortOrder.Equals(SortOrder.Desc) ?
query.OrderByDescending(i => i.InternshipRegistration.SubmissionDate) :
query.OrderBy(i => i.InternshipRegistration.SubmissionDate);
}
else if (searchQuery.OrderByField.ToLower().Equals("internshipstate"))
{
query = searchQuery.SortOrder.Equals(SortOrder.Desc) ?
query.OrderByDescending(i => i.InternshipRegistration.State) :
query.OrderBy(i => i.InternshipRegistration.State);
}
var result = await query.ToListAsync(token);
return Ok(result);
}
[HttpGet("{internshipId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult<Internship>> GetInternship(long internshipId, CancellationToken token)
{
var internship = await Context.Internships
.Include(i => i.Student)
.Include(i => i.InternshipRegistration)
.Include(i => i.InternshipRegistration.Company)
.Include(i => i.InternshipRegistration.BranchAddress)
.Include(i => i.InternshipRegistration.Type)
.Include(i => i.InternshipRegistration.Subjects)
.ThenInclude(subject => subject.Subject)
.Include(i => i.InternshipRegistration.Mentor)
.Include(i => i.Report)
.Include(i => i.Documentation)
.Include(i => i.Edition)
.Where(i => i.Id.Equals(internshipId))
.FirstOrDefaultAsync(token);
if (internship == null)
{
return NotFound();
}
return Ok(internship);
}
[HttpGet("{internshipId}/status")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> GetInternshipStatus(long internshipId, CancellationToken token)
{
var internship = await Context.Internships
.Include(i => i.InternshipRegistration)
.Include(i => i.Report)
.Include(i => i.Documentation)
.FirstOrDefaultAsync(i => i.Id.Equals(internshipId), token);
if (internship == null)
{
return NotFound();
}
return new JsonResult(new { Errors = internship.ValidateStatus() });
}
[HttpPut("{internshipId}/grade")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> GradeInternship(long internshipId, [FromBody] float grade, CancellationToken token)
{
var internship = await Context.Internships
.FirstOrDefaultAsync(i => i.Id.Equals(internshipId), token);
if (internship == null)
{
return NotFound();
}
internship.Grade = grade;
await Context.SaveChangesAsync(token);
return new JsonResult(new { Errors = internship.ValidateStatus() });
}
[HttpPut("{internshipId}/registration/accept")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> AcceptInternshipRegistration(long internshipId, [FromBody] string comment, CancellationToken token)
{
var internship = await Context.Internships
.Include(i => i.InternshipRegistration)
.FirstOrDefaultAsync(i => i.Id.Equals(internshipId), token);
if (internship == null)
{
return NotFound();
}
internship.InternshipRegistration.State = DocumentState.Accepted;
internship.InternshipRegistration.ChangeStateComment = string.IsNullOrEmpty(comment) ? null : comment;
await Context.SaveChangesAsync(token);
return Ok();
}
[HttpPut("{internshipId}/registration/reject")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> RejectInternshipRegistration(long internshipId, [FromBody] string comment, CancellationToken token)
{
var internship = await Context.Internships
.Include(i => i.InternshipRegistration)
.FirstOrDefaultAsync(i => i.Id.Equals(internshipId), token);
if (internship == null)
{
return NotFound();
}
internship.InternshipRegistration.State = DocumentState.Rejected;
internship.InternshipRegistration.ChangeStateComment = string.IsNullOrEmpty(comment) ? null : comment;
await Context.SaveChangesAsync(token);
return Ok();
}
}
}

View File

@ -1,85 +0,0 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Commands;
using InternshipSystem.Api.Security;
using InternshipSystem.Api.UseCases;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("internshipRegistration")]
public class InternshipRegistrationController : ControllerBase
{
private readonly InternshipDbContext _context;
public InternshipRegistrationController(InternshipDbContext dbContext)
{
_context = dbContext;
}
/// <summary>
/// Validate and add filled internship registration form
/// </summary>
/// <response code="200">If registration form was successfully added</response>
/// <response code="400">If the provided registration query was malformed</response>
/// <response code="401">This action is only available for authorized student registered for current edition</response>
[HttpPut]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult> SubmitRegistrationForm(
[FromBody] UpdateRegistrationForm registrationCommand,
[FromServices] User user,
CancellationToken cancellationToken)
{
var edition = await _context.Editions
.Include(e => e.AvailableInternshipTypes)
.ThenInclude(t => t.InternshipType)
.Include(e => e.AvailableSubjects)
.ThenInclude(t => t.Subject)
.FirstAsync(e => e.Id == user.EditionId, cancellationToken);
var internship =
await _context
.Entry(edition)
.Collection(e => e.Internships)
.Query()
.Include(i => i.InternshipRegistration)
.ThenInclude(r => r.BranchAddress)
.Include(i => i.InternshipRegistration)
.ThenInclude(r => r.Company)
.Include(i => i.InternshipRegistration)
.ThenInclude(c => c.Company.Branches)
.Include(i => i.InternshipRegistration)
.ThenInclude(c => c.Type)
.Include(i => i.InternshipRegistration)
.ThenInclude(c => c.Subjects)
.Include(i => i.Documentation)
.Where(i => i.Student.Id == user.PersonNumber)
.FirstAsync(cancellationToken);
var useCase = new UpdateInternshipRegistrationUseCase(_context, internship, edition, user);
try
{
var (status, result) = await useCase.UpdateInternshipRegistration(registrationCommand, cancellationToken);
await _context.SaveChangesAsync(cancellationToken);
return new JsonResult(new {Status = status, Errors = result});
}
catch (ArgumentException e)
{
return BadRequest(e.Message);
}
}
}
}

View File

@ -1,171 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Queries;
using InternshipSystem.Api.Security;
using InternshipSystem.Core.Entity.Internship;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("internshipTypes")]
public class InternshipTypesController : ControllerBase
{
private InternshipDbContext Context { get; }
public InternshipTypesController(InternshipDbContext context)
{
Context = context;
}
/// <summary>
/// Get internship types available for current edition
/// </summary>
/// <returns>List of internship types for current edition</returns>
[HttpGet("current")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult<IEnumerable<InternshipType>>> GetInternshipTypesForEdition([FromServices] User user, CancellationToken cancellationToken)
{
var edition =
await Context.Editions
.Include(e => e.AvailableInternshipTypes)
.ThenInclude(e => e.InternshipType)
.Where(e => e.Id.Equals(user.EditionId))
.FirstOrDefaultAsync(cancellationToken: cancellationToken);
if (edition == null)
{
return NotFound();
}
return Ok(edition.AvailableInternshipTypes.Select(e => e.InternshipType));
}
/// <summary>
/// Get internship type by id
/// </summary>
/// <returns>Internship type</returns>
/// <response code="200">Internship type returned successfully</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Internship type not found</response>
[HttpGet("{internshipTypeId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult<InternshipType>> GetInternshipType(long internshipTypeId, CancellationToken cancellationToken)
{
return await Context.InternshipTypes.FindAsync(internshipTypeId);
}
/// <summary>
/// Get internship type list
/// </summary>
/// <returns>Internship type</returns>
/// <response code="200">Internship type list returned successfully</response>
/// <response code="401">This action is only available for authorized internship admin</response>
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize]
public async Task<ActionResult<IEnumerable<InternshipType>>> SearchInternshipTypes([FromQuery] InternshipTypeSearchQuery searchQuery, CancellationToken cancellationToken)
{
return await Context.InternshipTypes
.Where(t => string.IsNullOrEmpty(searchQuery.Label) || t.Label.Contains(searchQuery.Label))
.Where(t => string.IsNullOrEmpty(searchQuery.LabelEng) || t.Label.Contains(searchQuery.LabelEng))
.OrderBy(t => t.Label)
.Skip(searchQuery.Page * searchQuery.PerPage)
.Take(searchQuery.PerPage)
.ToListAsync(cancellationToken);
}
/// <summary>
/// Add or update internship type, only available for coordinator
/// </summary>
/// <response code="200">Internship type updated successfully</response>
/// <response code="400">Invalid internship type form</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Internship type with selected id do not exist</response>
[HttpPut]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult> UpsertInternshipType([FromBody] InternshipTypeFrom internshipTypeFrom, CancellationToken cancellationToken)
{
var validator = new InternshipTypeFrom.Validator();
var validationResult = await validator.ValidateAsync(internshipTypeFrom, cancellationToken);
if (!validationResult.IsValid)
{
return BadRequest(validationResult.ToString());
}
if (internshipTypeFrom.Id.HasValue)
{
var internshipType = await Context.InternshipTypes.FindAsync(internshipTypeFrom.Id.Value);
if (internshipType == null)
{
return NotFound($"Internship type with id {internshipTypeFrom.Id} not found");
}
internshipType.Label = string.IsNullOrEmpty(internshipTypeFrom.Label) ? internshipType.Label : internshipTypeFrom.Label;
internshipType.LabelEng = string.IsNullOrEmpty(internshipTypeFrom.LabelEng) ? internshipType.LabelEng : internshipTypeFrom.LabelEng;
internshipType.Description = string.IsNullOrEmpty(internshipTypeFrom.Description) ? internshipType.Description : internshipTypeFrom.Description;
internshipType.DescriptionEng = string.IsNullOrEmpty(internshipTypeFrom.DescriptionEng) ? internshipType.DescriptionEng : internshipTypeFrom.DescriptionEng;
}
else
{
var newInternshipType = new InternshipType
{
Label = internshipTypeFrom.Label,
LabelEng = internshipTypeFrom.LabelEng,
Description = internshipTypeFrom.Description,
DescriptionEng = internshipTypeFrom.DescriptionEng,
};
await Context.InternshipTypes.AddAsync(newInternshipType, cancellationToken);
}
await Context.SaveChangesAsync(cancellationToken);
return Ok();
}
/// <summary>
/// Add or update internship type
/// </summary>
/// <response code="200">Internship type deleted successfully</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Internship type with selected id do not exist</response>
[HttpDelete("{internshipTypeId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult> DeleteInternshipType(long internshipTypeId, CancellationToken cancellationToken)
{
var internshipTypeToDelete = await Context.InternshipTypes
.FirstOrDefaultAsync(t => t.Id.Equals(internshipTypeId), cancellationToken: cancellationToken);
if (internshipTypeToDelete == null)
{
return NotFound($"Internship type with id: {internshipTypeId} does not exist");
}
Context.InternshipTypes.Remove(internshipTypeToDelete);
await Context.SaveChangesAsync(cancellationToken);
return Ok($"Internship type with id: {internshipTypeId} deleted successfully");
}
}
}

View File

@ -1,64 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Security;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("register")]
public class RegistrationController : ControllerBase
{
private readonly InternshipDbContext _context;
public RegistrationController(InternshipDbContext context)
{
_context = context;
}
/// <summary>
/// Register student for edition using provided registration code
/// </summary>
/// <param name="registrationCode">GUID of edition </param>
/// <returns></returns>
/// <response code="200">If the student was successfully registered</response>
/// <response code="400">If the provided registration code was malformed</response>
/// <response code="404">The registration code doesn't match any open edition</response>
[HttpPost]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<IActionResult> RegisterStudentForEdition([FromBody] Guid registrationCode, [FromServices] User user, CancellationToken token)
{
var edition = await _context.Editions
.Include(e => e.Internships)
.ThenInclude(i => i.Student)
.FirstOrDefaultAsync(e => e.Id.Equals(registrationCode), cancellationToken: token);
if (edition == null)
{
return NotFound();
}
var student = await _context.Students.FindAsync(user.PersonNumber);
try
{
edition.RegisterInternship(student);
await _context.SaveChangesAsync(token);
}
catch (ArgumentException e)
{
return BadRequest(e.Message);
}
return Ok();
}
}
}

View File

@ -1,62 +0,0 @@
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Security;
using InternshipSystem.Core.ValueObject;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace InternshipSystem.Api.Controllers
{
[Route("internship/report")]
public class ReportController : ControllerBase
{
private readonly InternshipDbContext _context;
public ReportController(InternshipDbContext context)
{
_context = context;
}
[HttpPost]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult> PostReport([FromBody] JObject reportValue, [FromServices] User user, CancellationToken ct)
{
var edition = await _context.Editions
.FindAsync(user.EditionId);
var internship = await _context.Entry(edition)
.Collection(e => e.Internships)
.Query()
.Include(i => i.Report)
.Include(i => i.Documentation)
.SingleAsync(i => i.Student.Id == user.PersonNumber, ct);
internship.Report.UpdateReport(reportValue.ToString(Formatting.None));
internship.AddNewDocument("", DocumentType.InternshipEvaluation);
await _context.SaveChangesAsync(ct);
return Ok();
}
[HttpGet]
[Authorize(Policy = Policies.RegisteredOnly)]
public async Task<ActionResult> GetReport([FromServices] User user, CancellationToken ct)
{
var edition = await _context.Editions
.FindAsync(user.EditionId);
var internship = await _context.Entry(edition)
.Collection(e => e.Internships)
.Query()
.Include(i => i.Report)
.SingleAsync(i => i.Student.Id == user.PersonNumber, ct);
return Ok(JsonConvert.DeserializeObject(internship.Report.Value));
}
}
}

View File

@ -1,90 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using InternshipSystem.Api.Queries.SearchQuery;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[Route("management/report")]
public class ReportFieldsController : ControllerBase
{
private readonly InternshipDbContext _context;
private readonly IMapper _mapper;
public ReportFieldsController(InternshipDbContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
[HttpGet("fields")]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<IEnumerable<ReportField>> GetFields(FieldSearchQuery searchQuery, CancellationToken ct) =>
await _context.ReportFields
.Where(c => c.Label.ToLower().Contains(searchQuery.Label.ToLower()))
.OrderBy(o => o.Label)
.Skip(searchQuery.Page * searchQuery.PerPage)
.Take(searchQuery.PerPage)
.ToListAsync(ct);
[HttpPost("fields")]
[Authorize(Policy = Policies.IsOverseer)]
public async Task<ActionResult> CreateField([FromBody] FieldCreateRequest request, CancellationToken ct)
{
ReportField field;
switch (request.FieldType)
{
case FieldType.LongText:
case FieldType.ShortText:
field = new ReportField(request.Label, request.LabelEng, request.Description, request.DescriptionEng, request.FieldType);
break;
case FieldType.Select:
case FieldType.Radial:
case FieldType.Checkbox:
field = new ReportChoiceField(request.Label, request.LabelEng, request.Description, request.DescriptionEng, request.FieldType, request.Choices);
break;
default:
return BadRequest("Unknown field type");
}
try
{
await _context.ReportFields.AddAsync(field, ct);
await _context.SaveChangesAsync(ct);
}
catch (Exception e)
{
return BadRequest("Failed");
}
return Ok();
}
}
public class FieldSearchQuery : SearchQuery
{
public string Label { get; set; } = "";
}
public class FieldCreateRequest
{
public long? Id { get; set; }
public string Label { get; set; }
public string LabelEng { get; set; }
public string Description { get; set; }
public string DescriptionEng { get; set; }
public FieldType FieldType { get; set; }
public string[] Choices { get; set; }
}
}

View File

@ -1,163 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Queries;
using InternshipSystem.Core;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[ApiController]
[Route("staticPage")]
public class StaticPagesController : ControllerBase
{
public StaticPagesController(InternshipDbContext context)
{
Context = context;
}
private InternshipDbContext Context { get; }
/// <summary>
/// Get all static pages, only available for coordinator
/// </summary>
/// <returns>List of static pages with titles and content</returns>
/// <response code="200">Static pages list returned successfully</response>
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task<ActionResult<IList<StaticPage>>> GetStaticPages(CancellationToken cancellationToken) =>
await Context.StaticPages
.ToListAsync(cancellationToken);
/// <summary>
/// Get static page, only available for coordinator
/// </summary>
/// <param name="accessName">Name of page</param>
/// <returns>Static page title and content</returns>
/// <response code="200">Static page returned successfully</response>
/// <response code="404">Static page with given access name do not exist</response>
[HttpGet("{accessName}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<StaticPage>> GetStaticPage(string accessName, CancellationToken cancellationToken)
{
var page =
await Context.StaticPages
.Where(p => p.AccessName.Trim().ToLower().Equals(accessName.Trim().ToLower()))
.FirstOrDefaultAsync(cancellationToken);
if (page == null)
{
return NotFound();
}
return Ok(page);
}
/// <summary>
/// Add or update static page, only available for coordinator
/// </summary>
/// <response code="200">Static page updated successfully</response>
/// <response code="400">Static page form is not valid</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Static page with given id do not exist</response>
[HttpPut]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult> UpdateStaticPage([FromBody] StaticPageForm staticPageForm, CancellationToken cancellationToken)
{
var validator = new StaticPageForm.Validator();
var validationResult = await validator.ValidateAsync(staticPageForm, cancellationToken);
if (!validationResult.IsValid)
{
return BadRequest(validationResult.ToString());
}
if (staticPageForm.Id.HasValue)
{
var pageToUpdate = await Context.StaticPages.FindAsync(staticPageForm.Id);
if (pageToUpdate == null)
{
return NotFound($"Static page with id: {staticPageForm.Id} does not exist");
}
if (!string.IsNullOrEmpty(staticPageForm.AccessName))
{
var pageWithSameAccessName = await Context.StaticPages
.FirstOrDefaultAsync(sp => sp.AccessName.ToLower().Trim().Equals(staticPageForm.AccessName.ToLower().Trim()), cancellationToken: cancellationToken);
if (pageWithSameAccessName != null && !pageWithSameAccessName.Id.Equals(pageToUpdate.Id))
{
return BadRequest($"Static page with access name: {staticPageForm.AccessName} already exist");
}
}
pageToUpdate.AccessName = string.IsNullOrEmpty(staticPageForm.AccessName) ? pageToUpdate.AccessName : staticPageForm.AccessName;
pageToUpdate.Title = string.IsNullOrEmpty(staticPageForm.Title) ? pageToUpdate.Title : staticPageForm.Title;
pageToUpdate.TitleEng = string.IsNullOrEmpty(staticPageForm.TitleEng) ? pageToUpdate.TitleEng : staticPageForm.TitleEng;
pageToUpdate.Content = string.IsNullOrEmpty(staticPageForm.Content) ? pageToUpdate.Content : staticPageForm.Content;
pageToUpdate.ContentEng = string.IsNullOrEmpty(staticPageForm.ContentEng) ? pageToUpdate.ContentEng : staticPageForm.ContentEng;
}
else
{
var pageWithSameAccessName = await Context.StaticPages
.FirstOrDefaultAsync(sp => sp.AccessName.ToLower().Trim().Equals(staticPageForm.AccessName.ToLower().Trim()), cancellationToken: cancellationToken);
if (pageWithSameAccessName != null)
{
return BadRequest($"Static page with access name: {staticPageForm.AccessName} already exist");
}
var newStaticPage = new StaticPage
{
AccessName = staticPageForm.AccessName.ToLower().Trim(),
Title = staticPageForm.Title,
TitleEng = staticPageForm.TitleEng,
Content = staticPageForm.Content,
ContentEng = staticPageForm.ContentEng,
};
await Context.StaticPages.AddAsync(newStaticPage, cancellationToken);
}
await Context.SaveChangesAsync(cancellationToken);
return Ok($"Static page updated successfully");
}
/// <summary>
/// Delete static page, only available for coordinator
/// </summary>
/// <response code="200">Static page deleted successfully</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Static page with given access name do not exist</response>
[HttpDelete("{accessName}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult> DeleteStaticPage(string accessName, CancellationToken cancellationToken)
{
var pageToDelete = await Context.StaticPages
.FirstOrDefaultAsync(sp => sp.AccessName.ToLower().Trim().Equals(accessName.ToLower().Trim()), cancellationToken: cancellationToken);
if (pageToDelete == null)
{
return NotFound($"Static page with access name: {accessName} does not exist");
}
Context.StaticPages.Remove(pageToDelete);
await Context.SaveChangesAsync(cancellationToken);
return Ok($"Static page with access name: {accessName} deleted successfully");
}
}
}

View File

@ -1,143 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Queries;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.Controllers
{
[Route("students")]
[ApiController]
public class StudentsController : ControllerBase
{
private readonly InternshipDbContext _context;
public StudentsController(InternshipDbContext context)
{
_context = context;
}
/// <summary>
/// Get current student personal data
/// </summary>
/// <returns>Current student data</returns>
/// <response code="200">Current student data returned successfully</response>
/// <response code="401">his action is only available for authorized student</response>
[HttpGet("current")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize]
public async Task<ActionResult<Student>> GetCurrentStudentData([FromServices] User user, CancellationToken cancellationToken)
{
return await _context.Students.FindAsync(user.PersonNumber);
}
/// <summary>
/// Update current student personal data
/// </summary>
/// <response code="200">Current student data updated successfully</response>
/// <response code="401">his action is only available for authorized student</response>
[HttpPut("current")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize]
public async Task<ActionResult> UpdateCurrentStudentData([FromBody] CurrentStudentForm studentNewData, [FromServices] User user, CancellationToken cancellationToken)
{
var currentStudent = await _context.Students.FindAsync(user.PersonNumber);
currentStudent.AlbumNumber = studentNewData.AlbumNumber ?? currentStudent.AlbumNumber;
currentStudent.FirstName = string.IsNullOrEmpty(studentNewData.FirstName) ? currentStudent.FirstName : studentNewData.FirstName;
currentStudent.LastName = string.IsNullOrEmpty(studentNewData.LastName) ? currentStudent.LastName : studentNewData.LastName;
currentStudent.Email = string.IsNullOrEmpty(studentNewData.Email) ? currentStudent.Email : studentNewData.Email;
currentStudent.Course = string.IsNullOrEmpty(studentNewData.Course) ? currentStudent.Course : studentNewData.Course;
currentStudent.Semester = studentNewData.Semester ?? currentStudent.Semester;
await _context.SaveChangesAsync(cancellationToken);
return Ok();
}
/// <summary>
/// Get student personal data, only available for coordinator
/// </summary>
/// <returns>Student personal data</returns>
/// <response code="200">Student data returned successfully</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Student with given id do not exist</response>
[HttpGet("{studentPersonNumber}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult<Student>> GetStudentByPersonNumber(long studentPersonNumber, CancellationToken cancellationToken) =>
await _context.Students.FindAsync(studentPersonNumber);
/// <summary>
/// Search students personal data, only available for coordinator
/// </summary>
/// <returns>List of students personal data</returns>
/// <response code="200">List of student data</response>
/// <response code="401">This action is only available for authorized internship admin</response>
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[Authorize]
public async Task<ActionResult<IReadOnlyCollection<Student>>> SearchStudents([FromQuery] StudentSearchQuery searchQuery, CancellationToken cancellationToken) =>
await _context.Students
.Where(s => !searchQuery.AlbumNumber.HasValue || s.AlbumNumber.Equals(searchQuery.AlbumNumber))
.Where(s => string.IsNullOrEmpty(searchQuery.FirstName) || s.FirstName.ToLower().Contains(searchQuery.FirstName.ToLower()))
.Where(s => string.IsNullOrEmpty(searchQuery.LastName) || s.LastName.ToLower().Contains(searchQuery.LastName.ToLower()))
.OrderBy(s => s.AlbumNumber)
.Skip(searchQuery.Page * searchQuery.PerPage)
.Take(searchQuery.PerPage)
.ToListAsync(cancellationToken);
/// <summary>
/// Updates student personal data, only available for coordinator
/// </summary>
/// <response code="200">Student data updated successfully</response>
/// <response code="401">This action is only available for authorized internship admin</response>
/// <response code="404">Student with given id do not exist</response>
[HttpPut("{studentId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Authorize]
public async Task<ActionResult> UpdateStudentData(long studentId, [FromBody] StudentForm studentNewData, CancellationToken cancellationToken)
{
var validator = new StudentForm.Validator();
var validationResult = await validator.ValidateAsync(studentNewData, cancellationToken);
if (!validationResult.IsValid)
{
return BadRequest(validationResult.ToString());
}
var currentStudent = await _context.Students.FindAsync(studentId);
if (currentStudent == null)
{
return NotFound();
}
currentStudent.AlbumNumber = studentNewData.AlbumNumber ?? currentStudent.AlbumNumber;
currentStudent.FirstName = string.IsNullOrEmpty(studentNewData.FirstName) ? currentStudent.FirstName : studentNewData.FirstName;
currentStudent.LastName = string.IsNullOrEmpty(studentNewData.LastName) ? currentStudent.LastName : studentNewData.LastName;
currentStudent.Email = string.IsNullOrEmpty(studentNewData.Email) ? currentStudent.Email : studentNewData.Email;
currentStudent.Course = string.IsNullOrEmpty(studentNewData.Course) ? currentStudent.Course : studentNewData.Course;
currentStudent.Semester = studentNewData.Semester ?? currentStudent.Semester;
await _context.SaveChangesAsync(cancellationToken);
return Ok();
}
}
}

View File

@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace InternshipSystem.Api.Converters
{
public class StringArrayConverter<TItem> : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
if (token.Type == JTokenType.Array)
{
return token.ToObject<List<TItem>>();
}
return new List<TItem>
{
token.ToObject<TItem>()
};
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(List<TItem>);
}
public override bool CanWrite => false;
}
}

View File

@ -1,20 +0,0 @@
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS prep-env
COPY . ./
RUN mkdir /proj && cp --parents */*.csproj /proj
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-alpine AS build-env
WORKDIR /app
# Copy csproj and restore as distinct layers
COPY --from=prep-env ./proj .
RUN dotnet restore ./InternshipSystem.Api
# Copy everything else and build
COPY . ./
RUN dotnet publish ./InternshipSystem.Api -c Release -o out
# Build runtime image
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
RUN curl -sSL https://aka.ms/getvsdbgsh | /bin/sh /dev/stdin -v latest -l /vsdbg
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "./InternshipSystem.Api.dll"]

View File

@ -1,50 +0,0 @@
using System;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Internal;
using Microsoft.Extensions.DependencyInjection;
namespace InternshipSystem.Api.Extensions
{
public static class ApplicationBuilderExtensions
{
public static IApplicationBuilder UseMigration(this IApplicationBuilder app)
{
bool done = false;
while (!done)
{
try
{
using var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope();
using var context = serviceScope.ServiceProvider.GetService<InternshipDbContext>();
context.Database.Migrate();
done = true;
}
catch (Exception)
{
// ignored
}
}
return app;
}
public static IApplicationBuilder UseDefaultData(this IApplicationBuilder app, bool useDefaultData)
{
using var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope();
using var context = serviceScope.ServiceProvider.GetService<InternshipDbContext>();
var filler = serviceScope.ServiceProvider.GetService<DatabaseFiller>();
context.Database.Migrate();
if (useDefaultData && !context.Editions.Any())
{
filler.FillAll().Wait();
}
return app;
}
}
}

View File

@ -1,35 +0,0 @@
using System.Text;
using InternshipSystem.Api.Options;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
namespace InternshipSystem.Api.Extensions
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddStudentAuthentication(this IServiceCollection services)
{
var options = services.BuildServiceProvider().GetService<IOptions<SecurityOptions>>().Value;
services
.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(options.Secret)),
ValidateAudience = false,
ValidateIssuer = false
};
});
return services;
}
}
}

View File

@ -1,72 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using InternshipSystem.Api.Options;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using JsonConverter = System.Text.Json.Serialization.JsonConverter;
namespace InternshipSystem.Api.Controllers
{
public class GutCasClient
{
private readonly HttpClient _client;
private readonly SecurityOptions _securityOptions;
public GutCasClient(HttpClient client, IOptions<SecurityOptions> options)
{
_securityOptions = options.Value;
client.BaseAddress = _securityOptions.BaseUrl;
_client = client;
}
public async Task<string> GetCasTokenAsync(string code, CancellationToken cancellationToken)
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Post,
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "authorization_code" },
{ "client_id", _securityOptions.ClientId },
{ "client_secret", _securityOptions.Secret },
{ "redirect_uri", _securityOptions.RedirectUrl.ToString() },
{ "code", code }
}),
RequestUri = _securityOptions.TokenPath
};
var response = await _client.SendAsync(request, cancellationToken);
var content = await response.Content.ReadAsStringAsync();
var value = JsonConvert.DeserializeObject<Dictionary<string, object>>(content);
return value["access_token"].ToString();
}
public async Task<CasUserData> GetProfileAsync(string token, CancellationToken cancellationToken)
{
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
Content = new StringContent(string.Empty),
RequestUri = _securityOptions.ProfilePath
};
request.Headers.Authorization = AuthenticationHeaderValue.Parse($"Bearer {token}");
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var response = await _client.SendAsync(request, cancellationToken);
var content = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<CasUserProfile>(content);
return result.Attributes;
}
}
}

View File

@ -1,30 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<LangVersion>latest</LangVersion>
<NoWarn>$(NoWarn);1591;1573</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="10.0.0" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.0.1" />
<PackageReference Include="FluentValidation" Version="9.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.1.6" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.8" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
<PackageReference Include="Serilog" Version="2.9.0" />
<PackageReference Include="Serilog.AspNetCore" Version="3.2.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="5.6.3" />
<PackageReference Include="IdentityServer4" Version="3.1.4" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="../InternshipSystem.Core/InternshipSystem.Core.csproj" />
<ProjectReference Include="../InternshipSystem.Repository/InternshipSystem.Repository.csproj" />
</ItemGroup>
</Project>

View File

@ -1,44 +0,0 @@
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using InternshipSystem.Api.Security;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace InternshipSystem.Api.ModelBinders
{
public class UserBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
var principal = bindingContext.HttpContext.User;
if (principal == null)
{
return Task.CompletedTask;
}
Guid? editionGuid = null;
if (principal.FindFirst(InternshipClaims.Edition) != null
&& Guid.TryParse(principal.FindFirst(InternshipClaims.Edition).Value, out var edition))
{
editionGuid = edition;
}
var user = new User
{
Name = principal.FindFirst(ClaimTypes.Name).Value,
PersonNumber = long.Parse(principal.FindFirst(InternshipClaims.PersonNumber).Value),
EditionId = editionGuid
};
bindingContext.Result = ModelBindingResult.Success(user);
return Task.CompletedTask;
}
}
}

View File

@ -1,25 +0,0 @@
using System;
using InternshipSystem.Api.Security;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
namespace InternshipSystem.Api.ModelBinders
{
public class UserBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (context.Metadata.ModelType == typeof(User))
{
return new BinderTypeModelBinder(typeof(UserBinder));
}
return null;
}
}
}

View File

@ -1,21 +0,0 @@
using System;
using System.Security.Policy;
namespace InternshipSystem.Api.Options
{
public class SecurityOptions
{
public string Secret { get; set; }
public double Expiration { get; set; }
public Uri BaseUrl { get; set; }
public Uri TokenPath { get; set; }
public Uri ProfilePath { get; set; }
public Uri RedirectUrl { get; set; }
public string ClientId { get; set; }
}
}

View File

@ -1,36 +0,0 @@
using FluentValidation;
namespace InternshipSystem.Api.Queries
{
public class BranchOfficeForm
{
public long? Id { get; set; }
public string Street { get; set; }
public string Building { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public class Validator : AbstractValidator<BranchOfficeForm>
{
public Validator()
{
RuleFor(b => b.Id).NotNull()
.When(c =>
string.IsNullOrEmpty(c.Country) || string.IsNullOrEmpty(c.City) ||
string.IsNullOrEmpty(c.PostalCode) || string.IsNullOrEmpty(c.Street) ||
string.IsNullOrEmpty(c.Building));
RuleFor(b => b.Country).NotEmpty()
.When(b => !b.Id.HasValue);
RuleFor(b => b.City).NotEmpty()
.When(b => !b.Id.HasValue);
RuleFor(b => b.PostalCode).NotEmpty()
.When(b => !b.Id.HasValue);
RuleFor(b => b.Street).NotEmpty()
.When(b => !b.Id.HasValue);
RuleFor(b => b.Building).NotEmpty()
.When(b => !b.Id.HasValue);
}
}
}
}

View File

@ -1,24 +0,0 @@
using FluentValidation;
namespace InternshipSystem.Api.Queries
{
public class CompanyForm
{
public long? Id { get; set; }
public string Nip { get; set; }
public string Name { get; set; }
public class Validator : AbstractValidator<CompanyForm>
{
public Validator()
{
RuleFor(c => c.Id).NotNull()
.When(c => string.IsNullOrEmpty(c.Nip) || string.IsNullOrEmpty(c.Name));
RuleFor(c => c.Nip).NotEmpty()
.When(c => !c.Id.HasValue);
RuleFor(c => c.Name).NotEmpty()
.When(c => !c.Id.HasValue);
}
}
}
}

View File

@ -1,23 +0,0 @@
using FluentValidation;
namespace InternshipSystem.Api.Queries
{
public class CourseForm
{
public long? Id { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public class Validator : AbstractValidator<CourseForm>
{
public Validator()
{
RuleFor(c => c.Id).NotNull()
.When(c => string.IsNullOrWhiteSpace(c.Name));
RuleFor(c => c.Name).NotEmpty()
.When(c => !c.Id.HasValue);
}
}
}
}

View File

@ -1,12 +0,0 @@
namespace InternshipSystem.Api.Queries
{
public class CurrentStudentForm
{
public int? AlbumNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Course { get; set; }
public int? Semester { get; set; }
}
}

View File

@ -1,16 +0,0 @@
using FluentValidation;
using InternshipSystem.Core.ValueObject;
using Microsoft.AspNetCore.Http;
namespace InternshipSystem.Api.Queries
{
public class DocumentPublishRequest
{
public string Description { get; set; }
public DocumentType Type { get; set; }
public class Validator : AbstractValidator<DocumentPublishRequest>
{
}
}
}

View File

@ -1,40 +0,0 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity;
using InternshipSystem.Core.Entity.Internship;
namespace InternshipSystem.Api.Queries
{
public class EditionForm
{
public Guid? Id { get; set; }
public DateTime? EditionStart { get; set; }
public DateTime? EditionFinish { get; set; }
public DateTime? ReportingStart { get; set; }
public Course Course { get; set; }
public List<long> AvailableSubjectsIds { get; set; } = new List<long>();
public List<long> AvailableInternshipTypesIds { get; set; } = new List<long>();
public List<long> ReportSchema { get; set; } = new List<long>();
public class Validator : AbstractValidator<EditionForm>
{
public Validator()
{
RuleFor(e => e.Id).NotNull()
.When(e => !e.EditionStart.HasValue || !e.EditionFinish.HasValue
|| !e.ReportingStart.HasValue || e.Course == null);
RuleFor(e => e.EditionStart).NotEmpty()
.When(e => !e.Id.HasValue);
RuleFor(e => e.EditionFinish).NotEmpty()
.When(e => !e.Id.HasValue);
RuleFor(e => e.ReportingStart).NotEmpty()
.When(e => !e.Id.HasValue);
RuleFor(e => e.Course).NotNull()
.When(e => !e.Id.HasValue);
}
}
}
}

View File

@ -1,27 +0,0 @@
using FluentValidation;
namespace InternshipSystem.Api.Queries
{
public class InternshipTypeFrom
{
public long? Id { get; set; }
public string Label { get; set; }
public string LabelEng { get; set; }
public string Description { get; set; }
public string DescriptionEng { get; set; }
public class Validator : AbstractValidator<InternshipTypeFrom>
{
public Validator()
{
RuleFor(t => t.Id).NotNull()
.When(t =>
string.IsNullOrEmpty(t.Label) || string.IsNullOrEmpty(t.LabelEng));
RuleFor(t => t.Label).NotEmpty()
.When(t => !t.Id.HasValue);
RuleFor(t => t.LabelEng).NotEmpty()
.When(t => !t.Id.HasValue);
}
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using FluentValidation;
using InternshipSystem.Core.Entity.Internship;
namespace InternshipSystem.Api.Queries
{
public class RegistrationFormQuery
{
public CompanyForm Company { get; set; }
public BranchOfficeForm BranchOffice { get; set; }
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
public InternshipType Type { get; set; }
public class Validator : AbstractValidator<RegistrationFormQuery>
{
public Validator()
{
RuleFor(rfq => rfq.Company)
.SetValidator(new CompanyForm.Validator());
RuleFor(rfq => rfq.BranchOffice)
.SetValidator(new BranchOfficeForm.Validator());
RuleFor(rfq => rfq.BranchOffice).NotNull()
.When(rfq => rfq.Company != null);
}
}
}
}

View File

@ -1,9 +0,0 @@
using InternshipSystem.Api.Queries.SearchQuery;
namespace InternshipSystem.Api.Controllers
{
public class BranchOfficeSearchQuery : SearchQuery
{
public string City { get; set; } = "";
}
}

View File

@ -1,10 +0,0 @@
namespace InternshipSystem.Api.Queries.SearchQuery
{
public class CompanySearchQuery : SearchQuery
{
/// <summary>
/// Value against which collection will be queried
/// </summary>
public string Name { get; set; } = "";
}
}

View File

@ -1,7 +0,0 @@
namespace InternshipSystem.Api.Queries.SearchQuery
{
public class EditionSearchQuery : SearchQuery
{
public long? Course { get; set; }
}
}

View File

@ -1,22 +0,0 @@
using System;
using InternshipSystem.Core;
namespace InternshipSystem.Api.Queries.SearchQuery
{
public class InternshipSearchQuery : SearchQuery
{
public Guid? EditionId { get; set; } = null;
public DocumentState? InternshipState { get; set; } = null;
public DocumentState? ReportState { get; set; }
public int? StudentAlbumNumber { get; set; } = null;
public string StudentFirstName { get; set; } = "";
public string StudentLastName { get; set; } = "";
/// <summary>
/// SortValue: Date, InternshipState
/// </summary>
public string OrderByField { get; set; } = "";
public SortOrder SortOrder { get; set; } = SortOrder.None;
public DocumentState? DocumentWithState { get; set; }
}
}

View File

@ -1,10 +0,0 @@
using InternshipSystem.Api.Queries.SearchQuery;
namespace InternshipSystem.Api.Controllers
{
public class InternshipTypeSearchQuery : SearchQuery
{
public string Label { get; set; } = "";
public string LabelEng { get; set; } = "";
}
}

View File

@ -1,15 +0,0 @@
namespace InternshipSystem.Api.Queries.SearchQuery
{
public class SearchQuery
{
/// <summary>
/// Which part of the collections to retrieve
/// </summary>
public int Page { get; set; } = 0;
/// <summary>
/// Size of the retrieved part
/// </summary>
public int PerPage { get; set; } = 30;
}
}

View File

@ -1,9 +0,0 @@
namespace InternshipSystem.Api.Queries.SearchQuery
{
public enum SortOrder
{
Asc,
Desc,
None
}
}

View File

@ -1,11 +0,0 @@
using InternshipSystem.Api.Queries.SearchQuery;
namespace InternshipSystem.Api.Controllers
{
public class StudentSearchQuery : SearchQuery
{
public int? AlbumNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
}

View File

@ -1,36 +0,0 @@
using FluentValidation;
namespace InternshipSystem.Api.Queries
{
public class StaticPageForm
{
public long? Id { get; set; }
public string AccessName { get; set; }
public string Title { get; set; }
public string TitleEng { get; set; }
public string Content { get; set; }
public string ContentEng { get; set; }
public class Validator : AbstractValidator<StaticPageForm>
{
public Validator()
{
RuleFor(sp => sp.Id).NotNull()
.When(sp =>
string.IsNullOrEmpty(sp.AccessName) || string.IsNullOrEmpty(sp.Title) ||
string.IsNullOrEmpty(sp.TitleEng) || string.IsNullOrEmpty(sp.Content) ||
string.IsNullOrEmpty(sp.ContentEng));
RuleFor(sp => sp.AccessName).NotEmpty()
.When(sp => !sp.Id.HasValue);
RuleFor(sp => sp.Title).NotEmpty()
.When(sp => !sp.Id.HasValue);
RuleFor(sp => sp.TitleEng).NotEmpty()
.When(sp => !sp.Id.HasValue);
RuleFor(sp => sp.Content).NotEmpty()
.When(sp => !sp.Id.HasValue);
RuleFor(sp => sp.ContentEng).NotEmpty()
.When(sp => !sp.Id.HasValue);
}
}
}
}

View File

@ -1,21 +0,0 @@
using FluentValidation;
namespace InternshipSystem.Api.Queries
{
public class StudentForm
{
public int? AlbumNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Course { get; set; }
public int? Semester { get; set; }
public class Validator : AbstractValidator<StudentForm>
{
public Validator()
{
}
}
}
}

View File

@ -1,20 +0,0 @@
using System.Collections.Generic;
using InternshipSystem.Api.Converters;
using Newtonsoft.Json;
namespace InternshipSystem.Api.Controllers
{
public class CasUserData
{
public string AlbumNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[JsonConverter(typeof(StringArrayConverter<string>))]
public List<string> Mail { get; set; }
public string PersonNumber { get; set; }
[JsonConverter(typeof(StringArrayConverter<string>))]
public List<string> Pg_Cui_Portalroles { get; set; }
}
}

View File

@ -1,10 +0,0 @@
namespace InternshipSystem.Api.Controllers
{
public class CasUserProfile
{
public string Service { get; set; }
public CasUserData Attributes { get; set; }
public string Id { get; set; }
public string Client_Id { get; set; }
}
}

View File

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity;
using InternshipSystem.Core.Entity.Internship;
using InternshipSystem.Core.UglyOrmArtifacts;
namespace InternshipSystem.Api.Result
{
public class EditionConfigurationResult
{
public List<InternshipSubject> AvailableSubjects { get; set; }
public List<ReportField> ReportSchema { get; set; }
public Course Course { get; set; }
public DateTime EditionStart { get; set; }
public DateTime EditionFinish { get; set; }
public DateTime ReportingStart { get; set; }
}
}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity;
using InternshipSystem.Core.Entity.Internship;
namespace InternshipSystem.Api.Result
{
public class EditionDetailsResult
{
public Guid Id { get; set; }
public DateTime EditionStart { get; set; }
public DateTime EditionFinish { get; set; }
public DateTime ReportingStart { get; set; }
public Course Course { get; set; }
public List<InternshipSubject> AvailableSubjects { get; set; }
public List<InternshipType> AvailableInternshipTypes { get; set; }
public List<ReportField> ReportSchema { get; set; }
}
}

View File

@ -1,15 +0,0 @@
using System;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity;
namespace InternshipSystem.Api.Result
{
public class EditionManagementResult
{
public Guid Id { get; set; }
public DateTime EditionStart { get; set; }
public DateTime EditionFinish { get; set; }
public DateTime ReportingStart { get; set; }
public Course Course { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using System;
namespace InternshipSystem.Api.Result
{
public class EditionResult
{
public Guid Id { get; set; }
public DateTime EditionStart { get; set; }
public DateTime EditionFinish { get; set; }
public string CourseName { get; set; }
public string Status { get; set; }
}
}

View File

@ -1,9 +0,0 @@
namespace InternshipSystem.Api.Security
{
public static class InternshipClaims
{
public static string Edition = "Edition";
public static string PersonNumber = "PersonNumber";
}
}

View File

@ -1,37 +0,0 @@
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using InternshipSystem.Api.Options;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
namespace InternshipSystem.Api.Security
{
public class JwtTokenService
{
private SecurityOptions _securityOptions;
public JwtTokenService(IOptions<SecurityOptions> securityOptions)
{
_securityOptions = securityOptions.Value;
}
public string generateToken(ClaimsIdentity identity)
{
var handler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_securityOptions.Secret);
var descriptor = new SecurityTokenDescriptor
{
Subject = identity,
Expires = DateTime.UtcNow.AddMinutes(_securityOptions.Expiration),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var jwtToken = handler.CreateJwtSecurityToken(descriptor);
return handler.WriteToken(jwtToken);
}
}
}

View File

@ -1,8 +0,0 @@
namespace InternshipSystem.Api.Security
{
public static class Policies
{
public const string RegisteredOnly = "RegisteredForEditionOnly";
public const string IsOverseer = "IsOverseer";
}
}

View File

@ -1,11 +0,0 @@
using System;
namespace InternshipSystem.Api.Security
{
public class User
{
public long PersonNumber { get; set; }
public string Name { get; set; }
public Guid? EditionId { get; set; }
}
}

View File

@ -1,37 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace InternshipSystem.Api.Service
{
public class FileValidator
{
private readonly List<(string Mime, byte[] Signature)> validFileTypes;
public FileValidator()
{
validFileTypes = new List<(string, byte[])> {
("application/pdf", new byte[] { 0x25, 0x50, 0x44, 0x46 }),
("image/jpeg", new byte[] { 0xFF, 0xD8, 0xFF, 0xDB }),
("image/jpeg", new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 }),
("image/jpeg", new byte[] { 0xFF, 0xD8, 0xFF, 0xE1 })
};
}
public bool IsValidFile(byte[] scan)
{
return IsFileValidType(scan);
}
private bool IsFileValidType(byte[] scan)
{
return GetFileMime(scan) != null;
}
public string GetFileMime(byte[] scan)
{
var header = scan[..4];
return validFileTypes.FirstOrDefault(sig => sig.Signature.SequenceEqual(header)).Mime;
}
}
}

View File

@ -1,96 +0,0 @@
using System;
using System.IO;
using System.Reflection;
using AutoMapper;
using InternshipSystem.Api.Controllers;
using InternshipSystem.Api.Extensions;
using InternshipSystem.Api.ModelBinders;
using InternshipSystem.Api.Options;
using InternshipSystem.Api.Security;
using InternshipSystem.Api.Service;
using InternshipSystem.Repository;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace InternshipSystem.Api
{
public class Startup
{
private IConfiguration Configuration { get; }
public Startup(IConfiguration configuration) =>
Configuration = configuration;
public void ConfigureServices(IServiceCollection services)
{
services
.Configure<SecurityOptions>(Configuration.GetSection("SecurityOptions"));
services
.AddStudentAuthentication()
.AddAuthorization(o =>
{
o.AddPolicy(Policies.RegisteredOnly, policy => policy.RequireClaim("Edition"));
//TODO: change to claim for InternshipRepresentative
o.AddPolicy(Policies.IsOverseer, policy => policy.RequireClaim("PersonNumber"));
})
.AddHttpClient<GutCasClient>();
services
.AddDbContext<InternshipDbContext>(o =>
o.UseNpgsql(Configuration.GetConnectionString("InternshipDatabase")))
.AddScoped<DatabaseFiller>()
.AddScoped<FileValidator>()
.AddScoped<JwtTokenService>()
.AddAutoMapper(cfg => cfg.AddProfile<ApiProfile>());
services
.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new OpenApiInfo {Title = "InternshipSystem Api - TEST", Version = "v1"});
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath);
})
.AddSwaggerGenNewtonsoftSupport()
.AddControllers(o => { o.ModelBinderProviders.Insert(0, new UserBinderProvider()); })
.AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.SerializerSettings.Converters.Add(new StringEnumConverter());
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMigration();
if (env.IsDevelopment())
{
app
.UseDefaultData("true".Equals(Environment.GetEnvironmentVariable("FILLER__USE_DEFAULT_DATA")))
.UseDeveloperExceptionPage();
}
app
.UseHttpsRedirection()
.UseRouting()
.UseAuthentication()
.UseAuthorization()
.UseCors()
.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
})
.UseSwagger()
.UseSwaggerUI(options => options.SwaggerEndpoint(Path.Join(Configuration.GetValue<string>("ApiPrefix"), "/swagger/v1/swagger.json"), "InternshipSystem Api"));
}
}
}

View File

@ -1,189 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using IdentityServer4.Extensions;
using InternshipSystem.Api.Commands;
using InternshipSystem.Api.Security;
using InternshipSystem.Core;
using InternshipSystem.Core.Entity.Internship;
using InternshipSystem.Core.UglyOrmArtifacts;
using InternshipSystem.Core.ValueObject;
using InternshipSystem.Repository;
using Microsoft.EntityFrameworkCore;
namespace InternshipSystem.Api.UseCases
{
public class UpdateInternshipRegistrationUseCase
{
private readonly InternshipDbContext _dbContext;
private readonly Internship _internship;
private readonly Edition _edition;
private readonly User _user;
private readonly InternshipRegistration subjectRegistration;
public UpdateInternshipRegistrationUseCase(InternshipDbContext dbContext,
Internship internship, Edition edition, User user)
{
_dbContext = dbContext;
_internship = internship;
_edition = edition;
_user = user;
_internship = internship;
subjectRegistration = internship.InternshipRegistration;
}
public async Task<(DocumentState State, IEnumerable<ErrorDescription>)> UpdateInternshipRegistration(
UpdateRegistrationForm registrationCommand,
CancellationToken cancellationToken)
{
UpdateTimeFrame(registrationCommand);
subjectRegistration.DeclaredHours = registrationCommand.Hours ?? subjectRegistration.DeclaredHours;
if (registrationCommand.Type.HasValue)
{
UpdateInternshipType(registrationCommand.Type.Value);
}
if (registrationCommand.Mentor.HasValue)
{
UpdateMentor(registrationCommand.Mentor.Value);
}
if (!registrationCommand.Subjects.IsNullOrEmpty())
{
UpdateSubjects(registrationCommand.Subjects);
}
if (registrationCommand.Company.HasValue)
{
await UpdateCompanyAndBranch(registrationCommand.Company.Value, cancellationToken);
}
return subjectRegistration.ValidateStatus(_edition);
}
private void UpdateTimeFrame(UpdateRegistrationForm registrationCommand)
{
subjectRegistration.Start = registrationCommand.Start ?? subjectRegistration.Start;
subjectRegistration.End = registrationCommand.End ?? subjectRegistration.End;
if (!_edition.IsDateDuringEdition(subjectRegistration.Start, subjectRegistration.End))
{
_internship.AddNewDocument("", DocumentType.OutsideTermApproval);
}
else
{
_internship.RemoveDocument(DocumentType.OutsideTermApproval);
}
}
private void UpdateInternshipType(long typeId)
{
var editionInternshipType = _edition.AvailableInternshipTypes.FirstOrDefault(i => i.InternshipTypeId == typeId);
if (editionInternshipType?.InternshipType.RequireDeansApproval == true)
{
_internship.AddNewDocument("", DocumentType.InternshipTypeApproval);
}
else
{
_internship.RemoveDocument(DocumentType.InternshipTypeApproval);
}
if (editionInternshipType?.InternshipType.RequireInsurance == true)
{
_internship.AddNewDocument("", DocumentType.NnwInsurance);
}
else
{
_internship.RemoveDocument(DocumentType.NnwInsurance);
}
subjectRegistration.Type = editionInternshipType?.InternshipType ?? subjectRegistration.Type;
}
private async Task UpdateCompanyAndBranch(UpdateCompany companyUpdate, CancellationToken cancellationToken)
{
var company = subjectRegistration.Company;
if (companyUpdate.Id.HasValue)
{
company = await _dbContext.Companies
.Include(c => c.Branches)
.FirstAsync(c => c.Id == companyUpdate.Id.Value, cancellationToken);
}
else if (companyUpdate.IsCustomUpdate)
{
company = await _dbContext.Companies
.Include(c => c.Branches)
.SingleOrDefaultAsync(c => c.Provider == _user.PersonNumber, cancellationToken)
?? Company.CreateCompany(companyUpdate.Nip, companyUpdate.Name, _user.PersonNumber);
company.Name = companyUpdate.Name ?? company.Name;
company.Nip = companyUpdate.Nip ?? company.Nip;
subjectRegistration.BranchAddress = null;
}
if (companyUpdate.BranchOffice.HasValue)
{
var branchUpdate = companyUpdate.BranchOffice.Value;
var branch = subjectRegistration.BranchAddress;
if (branchUpdate.Id.HasValue)
{
branch = company.Branches.First(b => b.Id == branchUpdate.Id.Value);
}
else if (branchUpdate.IsCustomUpdate)
{
branch = company.Branches.FirstOrDefault(b => b.Provider == _user.PersonNumber);
if (branch == null)
{
branch = BranchOffice.CreateBranch(branchUpdate.Country, branchUpdate.City, branchUpdate.PostalCode,
branchUpdate.Street, branchUpdate.Building, _user.PersonNumber);
company.AddBranchOffice(branch);
}
branch.Address.Country = branchUpdate.Country ?? branch.Address.Country;
branch.Address.City = branchUpdate.City ?? branch.Address.City;
branch.Address.PostalCode = branchUpdate.PostalCode ?? branch.Address.PostalCode;
branch.Address.Street = branchUpdate.Country ?? branch.Address.Street;
branch.Address.Building = branchUpdate.Building ?? branch.Address.Building;
}
subjectRegistration.BranchAddress = branch;
}
subjectRegistration.Company = company;
}
private void UpdateSubjects(IEnumerable<long> subjects)
{
if (!_edition.AreSubjectsAvailable(subjects))
{
throw new ArgumentException("subjects chosen are not available in this edition");
}
subjectRegistration.Subjects =
subjects
.Select(i => new ProgramSubject
{
Registration = subjectRegistration,
InternshipSubjectId = i
})
.ToList();
}
private void UpdateMentor(UpdateMentor mentorUpdate)
{
subjectRegistration.Mentor ??= new Mentor();
subjectRegistration.Mentor.UpdateInformation(mentorUpdate.FirstName, mentorUpdate.LastName, mentorUpdate.Email, mentorUpdate.PhoneNumber);
}
}
}

View File

@ -1,48 +0,0 @@
using FluentValidation;
using FluentValidation.Validators;
namespace InternshipSystem.Core
{
public class BranchOffice
{
public BranchOffice()
{
}
private BranchOffice(BranchAddress address, long provider)
{
Address = address;
Provider = provider;
}
public long Id { get; set; }
public BranchAddress Address { get; set; }
public long Provider { get; set; }
public static BranchOffice CreateBranch(string country, string city, string postalCode, string street,
string building, long provider = 0)
{
var address = new BranchAddress
{
Building = building,
City = city,
Country = country,
Street = street,
PostalCode = postalCode
};
return new BranchOffice(address, provider);
}
public class Validator : AbstractValidator<BranchOffice>
{
public Validator()
{
RuleFor(x => x.Address)
.SetValidator(new BranchAddress.Validator());
}
}
}
}

View File

@ -1,44 +0,0 @@
using System;
using System.Collections.Generic;
using FluentValidation;
using FluentValidation.Validators;
namespace InternshipSystem.Core
{
public class Company
{
public long Id { get; set; }
public string Nip { get; set; }
public string Name { get; set; }
public List<BranchOffice> Branches { get; set; }
public long Provider { get; set; }
public static Company CreateCompany(string nip, string name, long provider = 0) =>
new Company
{
Nip = nip,
Name = name,
Provider = provider,
Branches = new List<BranchOffice>()
};
public void AddBranchOffice(BranchOffice createBranch)
{
Branches.Add(createBranch);
}
public class Validator : AbstractValidator<Company>
{
public Validator()
{
RuleFor(x => x.Nip)
.NotEmpty()
.WithMessage("error.company.nip.empty");
RuleFor(x => x.Name)
.NotEmpty()
.WithMessage("error.company.name.empty");
}
}
}
}

View File

@ -1,24 +0,0 @@
using System.Collections.Generic;
namespace InternshipSystem.Core.Entity
{
public class Course
{
public long Id { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public static Course CreateCourse(string name, string nameEng) =>
new Course
{
Name = name,
NameEng = nameEng,
};
public void UpdateCourse(string name, string nameEng)
{
Name = name;
NameEng = nameEng;
}
}
}

View File

@ -1,24 +0,0 @@
using InternshipSystem.Core.ValueObject;
namespace InternshipSystem.Core
{
public class Document
{
public long Id { get; set; }
public string Description { get; set; }
public DocumentScan Scan { get; set; }
public DocumentType Type { get; set; }
public DocumentState State { get; set; }
public string ChangeStateComment { get; set; }
}
public class DocumentScan
{
public long DocumentId { get; set; }
public Document Document { get; set; }
public long Size { get; set; }
public string Filename { get; set; }
public string Mime { get; set; }
public byte[] File { get; set; }
}
}

View File

@ -1,144 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using InternshipSystem.Core.Entity;
using InternshipSystem.Core.Entity.Internship;
using InternshipSystem.Core.UglyOrmArtifacts;
namespace InternshipSystem.Core
{
public class Edition
{
public Guid Id { get; set; }
public DateTime EditionStart { get; set; }
public DateTime EditionFinish { get; set; }
public DateTime ReportingStart { get; set; }
public Course Course { get; set; }
public List<Internship> Internships { get; set; }
public List<EditionSubject> AvailableSubjects { get; set; }
public List<EditionInternshipType> AvailableInternshipTypes { get; set; }
public List<ReportFieldEdition> ReportSchema { get; set; }
public bool IsOpen => EditionFinish < DateTime.Today;
public static Edition CreateEdition(DateTime start, DateTime end, DateTime reportingStart, Course course,
IEnumerable<long> subjectsIds, IEnumerable<long> internshipTypesIds, IEnumerable<long> reportFieldIds)
{
var newEdition = CreateEdition(start, end, reportingStart, course);
newEdition.AvailableSubjects =
subjectsIds
.Select(s => new EditionSubject
{
Edition = newEdition,
InternshipSubjectId = s,
})
.ToList();
newEdition.AvailableInternshipTypes =
internshipTypesIds
.Select(i => new EditionInternshipType
{
Edition = newEdition,
InternshipTypeId = i,
})
.ToList();
newEdition.ReportSchema =
reportFieldIds
.Select(i => new ReportFieldEdition
{
Edition = newEdition,
ReportFieldId = i,
})
.ToList();
return newEdition;
}
public static Edition CreateEdition(DateTime start, DateTime end, DateTime reportingStart, Course course)
{
return new Edition
{
EditionStart = start,
EditionFinish = end,
ReportingStart = reportingStart,
Course = course,
AvailableSubjects = new List<EditionSubject>(),
AvailableInternshipTypes = new List<EditionInternshipType>(),
ReportSchema = new List<ReportFieldEdition>()
};
}
public void UpdateEdition(DateTime? start, DateTime? end, DateTime? reportingStart, Course course,
IEnumerable<long> subjectsIds, IEnumerable<long> internshipTypesIds, IEnumerable<long> reportFieldIds)
{
EditionStart = start ?? EditionStart;
EditionFinish = end ?? EditionFinish;
ReportingStart = reportingStart ?? ReportingStart;
Course = course;
if (subjectsIds != null)
{
AvailableSubjects =
subjectsIds
.Select(s => new EditionSubject
{
InternshipSubjectId = s,
})
.ToList();
}
if (internshipTypesIds != null)
{
AvailableInternshipTypes =
internshipTypesIds
.Select(i => new EditionInternshipType
{
InternshipTypeId = i,
})
.ToList();
}
if (reportFieldIds != null)
{
ReportSchema =
reportFieldIds
.Select(i => new ReportFieldEdition
{
ReportFieldId = i,
})
.ToList();
}
}
public void RegisterInternship(Student student)
{
if (Internships.Any(i => i.Student.Id == student.Id))
{
throw new ArgumentException("error.registration.already_registered");
}
var internship = Internship.CreateStudentsInternship(student);
Internships.Add(internship);
}
public bool IsDateDuringEdition(DateTime start, DateTime end)
{
return start >= EditionStart && end <= EditionFinish;
}
public bool IsTypeAvailable(InternshipType internshipType)
{
return AvailableInternshipTypes.Any(e => e.InternshipType == internshipType);
}
public bool AreSubjectsAvailable(IEnumerable<long> internshipSubjects)
{
return internshipSubjects.All(s => AvailableSubjects.Any(su => su.InternshipSubjectId == s));
}
public bool IsValidDates => EditionStart <= EditionFinish;
}
}

View File

@ -1,15 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using FluentValidation.Results;
using InternshipSystem.Core.Entity.Internship;
namespace InternshipSystem.Core
{
static internal class Extensions
{
public static IEnumerable<ErrorDescription> ToErrorDescription(this ValidationResult result)
{
return result.Errors.Select(failure => new ErrorDescription { Key = failure.ErrorCode, Parameters = failure.FormattedMessagePlaceholderValues });
}
}
}

Some files were not shown because too many files have changed in this diff Show More