initial commit from an older template
This commit is contained in:
650
.gitignore
vendored
Normal file
650
.gitignore
vendored
Normal file
@@ -0,0 +1,650 @@
|
|||||||
|
# Created by https://www.toptal.com/developers/gitignore/api/visualstudio,visualstudiocode,rider,vim,aspnetcore,dotnetcore
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudio,visualstudiocode,rider,vim,aspnetcore,dotnetcore
|
||||||
|
|
||||||
|
### ASPNETCore ###
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# Visual Studio 2015 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# DNX
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/packages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/packages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/packages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignoreable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
node_modules/
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# CodeRush
|
||||||
|
.cr/
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/
|
||||||
|
|
||||||
|
### DotnetCore ###
|
||||||
|
# .NET Core build folders
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
|
||||||
|
# Common node modules locations
|
||||||
|
/node_modules
|
||||||
|
/wwwroot/node_modules
|
||||||
|
|
||||||
|
### Rider ###
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### Vim ###
|
||||||
|
# Swap
|
||||||
|
[._]*.s[a-v][a-z]
|
||||||
|
!*.svg # comment out if you don't need vector files
|
||||||
|
[._]*.sw[a-p]
|
||||||
|
[._]s[a-rt-v][a-z]
|
||||||
|
[._]ss[a-gi-z]
|
||||||
|
[._]sw[a-p]
|
||||||
|
|
||||||
|
# Session
|
||||||
|
Session.vim
|
||||||
|
Sessionx.vim
|
||||||
|
|
||||||
|
# Temporary
|
||||||
|
.netrwhist
|
||||||
|
# Auto-generated tag files
|
||||||
|
tags
|
||||||
|
# Persistent undo
|
||||||
|
[._]*.un~
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/*.code-snippets
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Built Visual Studio Code Extensions
|
||||||
|
*.vsix
|
||||||
|
|
||||||
|
### VisualStudioCode Patch ###
|
||||||
|
# Ignore all local history of files
|
||||||
|
.history
|
||||||
|
.ionide
|
||||||
|
|
||||||
|
### VisualStudio ###
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_h.h
|
||||||
|
*.iobj
|
||||||
|
*.ipdb
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.tlog
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
|
||||||
|
### VisualStudio Patch ###
|
||||||
|
# Additional files built by Visual Studio
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/visualstudio,visualstudiocode,rider,vim,aspnetcore,dotnetcore
|
||||||
486
Controllers/AuthController.cs
Executable file
486
Controllers/AuthController.cs
Executable file
@@ -0,0 +1,486 @@
|
|||||||
|
using GamificationService.Models.BasicResponses;
|
||||||
|
using GamificationService.Models.Database;
|
||||||
|
using GamificationService.Models.DTO;
|
||||||
|
using GamificationService.Services.JWT;
|
||||||
|
using GamificationService.Services.NotificationService;
|
||||||
|
using GamificationService.Utils;
|
||||||
|
using GamificationService.Utils.Factory;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace GamificationService.Controllers;
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class AuthController : ControllerBase
|
||||||
|
{
|
||||||
|
#region Services
|
||||||
|
|
||||||
|
private readonly ILogger<AuthController> _logger;
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
|
private readonly IJwtService _jwtService;
|
||||||
|
private readonly INotificationService _notificationService;
|
||||||
|
private readonly MailNotificationsFactory _mailNotificationsFactory;
|
||||||
|
private readonly PushNotificationsFactory _pushNotificationsFactory;
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
|
||||||
|
public AuthController(ILogger<AuthController> logger, UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, IJwtService jwtService, INotificationService notificationService, MailNotificationsFactory mailNotificationsFactory, PushNotificationsFactory pushNotificationsFactory)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_userManager = userManager;
|
||||||
|
_signInManager = signInManager;
|
||||||
|
_jwtService = jwtService;
|
||||||
|
_notificationService = notificationService;
|
||||||
|
_mailNotificationsFactory = mailNotificationsFactory;
|
||||||
|
_pushNotificationsFactory = pushNotificationsFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Actions
|
||||||
|
|
||||||
|
#region Auth
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles user registration.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The registration model.</param>
|
||||||
|
/// <returns>A response indicating the result of the registration.</returns>
|
||||||
|
[HttpPost("register")]
|
||||||
|
public async Task<IActionResult> Register([FromBody] AuthDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = new ApplicationUser()
|
||||||
|
{
|
||||||
|
UserName = model.Username,
|
||||||
|
Email = model.Email,
|
||||||
|
TwoFactorEnabled = false,
|
||||||
|
TwoFactorProviders = new List<TwoFactorProvider>() { TwoFactorProvider.NONE }
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await _userManager.CreateAsync(user, model.Password);
|
||||||
|
|
||||||
|
if (!result.Succeeded)
|
||||||
|
{
|
||||||
|
_logger.LogError("User registration failed: {Errors}", result.Errors);
|
||||||
|
return BadRequest(new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 400,
|
||||||
|
Message = "User registration failed"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation("User registered successfully: {Username}", model.Username);
|
||||||
|
return Ok(new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "User created successfully"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "An error occurred during user registration: {Message}", ex.Message);
|
||||||
|
return StatusCode(500, new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "An error occurred during user registration"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles user login.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The login model.</param>
|
||||||
|
/// <returns>A response indicating the result of the login.</returns>
|
||||||
|
[HttpPost("login")]
|
||||||
|
public async Task<IActionResult> Login([FromBody] AuthDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByNameAsync(model.Username);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Invalid username or password");
|
||||||
|
return NotFound(new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Invalid username or password"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var result = await _signInManager.PasswordSignInAsync( user, model.Password, false, model.RememberMe);
|
||||||
|
|
||||||
|
if (result.Succeeded & !result.RequiresTwoFactor)
|
||||||
|
{
|
||||||
|
var refreshToken = await _jwtService.GenerateRefreshTokenAsync(user);
|
||||||
|
var accessToken = _jwtService.GenerateAccessToken(user);
|
||||||
|
_logger.LogInformation("User logged in successfully: {Username}", model.Username);
|
||||||
|
|
||||||
|
return Ok(new LoginResultResponse()
|
||||||
|
{
|
||||||
|
RequiresTwoFactorAuth = false,
|
||||||
|
Success = true,
|
||||||
|
Token = new RefreshTokenDTO()
|
||||||
|
{
|
||||||
|
AccessToken = accessToken,
|
||||||
|
RefreshToken = refreshToken.Token
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if(result.RequiresTwoFactor)
|
||||||
|
{
|
||||||
|
var providerWithMaxWeight = user.TwoFactorProviders
|
||||||
|
.OrderByDescending(p => (int)p)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (providerWithMaxWeight == TwoFactorProvider.NONE)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("User {Username} does not have any two-factor authentication enabled", model.Username);
|
||||||
|
return StatusCode(418, new LoginResultResponse()
|
||||||
|
{
|
||||||
|
RequiresTwoFactorAuth = false,
|
||||||
|
Success = true,
|
||||||
|
TwoFactorProvider = (int)providerWithMaxWeight
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var code = await _userManager.GenerateTwoFactorTokenAsync(user, providerWithMaxWeight.ToString());
|
||||||
|
await SendNotificationAsync(user, "Two-factor authentication code", code, NotificationInformationType.AUTH,providerWithMaxWeight);
|
||||||
|
_logger.LogInformation("Two-factor authentication required for user {Username}", model.Username);
|
||||||
|
return Ok(new LoginResultResponse()
|
||||||
|
{
|
||||||
|
RequiresTwoFactorAuth = true,
|
||||||
|
Success = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogError("Invalid username or password");
|
||||||
|
return BadRequest(new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 400,
|
||||||
|
Message = "Invalid username or password"
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "An error occurred during user login: {Message}", ex.Message);
|
||||||
|
return StatusCode(500, new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "An error occurred during user login"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[HttpPost("logout")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> Logout()
|
||||||
|
{
|
||||||
|
await _signInManager.SignOutAsync();
|
||||||
|
return Ok("Logged out successfully");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("revoke-token")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> RevokeToken()
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
await _jwtService.RevokeRefreshTokenAsync(user.Id, HttpContext.Request.Cookies["refresh_token"],GetRemoteIpAddress());
|
||||||
|
return Ok("Token revoked successfully");
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Email
|
||||||
|
|
||||||
|
[HttpGet("{username}/init-email-verification")]
|
||||||
|
public async Task<IActionResult> VerifyEmail(string username)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByNameAsync(username);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Invalid username or password");
|
||||||
|
return NotFound(new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Invalid username or password"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||||
|
await SendNotificationAsync(user, "Email verification code", code, NotificationInformationType.AUTH, TwoFactorProvider.EMAIL);
|
||||||
|
_logger.LogInformation("Email verification code sent to user {Username}", username);
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Email verification code sent"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "An error occurred during email verification: {Message}", e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "An error occurred during email verification"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{username}/verify-email/{code}")]
|
||||||
|
public async Task<IActionResult> VerifyEmail(string username, string code)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByNameAsync(username);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Invalid username or password");
|
||||||
|
return NotFound(new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Invalid username or password"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await _userManager.ConfirmEmailAsync(user,code);
|
||||||
|
if (result.Succeeded)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Email verified for user {Username}", username);
|
||||||
|
user.EmailConfirmed = true;
|
||||||
|
await _userManager.UpdateAsync(user);
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Email verified"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return BadRequest(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 400,
|
||||||
|
Message = "Email verification failed"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "An error occurred during email verification: {Message}", e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "An error occurred during email verification"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 2FA
|
||||||
|
|
||||||
|
[HttpPost("get-2fa-code")]
|
||||||
|
public async Task<IActionResult> GetTwoFactorCode([FromBody] GetTwoFactorDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByNameAsync(model.Username);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
_logger.LogError("Invalid username or password");
|
||||||
|
return NotFound(new BasicResponse
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Invalid username or password"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var providerWithRequiredWeight = user.TwoFactorProviders
|
||||||
|
.FirstOrDefault(p => (int)p == model.TwoFactorProvider);
|
||||||
|
var code = await _userManager.GenerateTwoFactorTokenAsync(user, providerWithRequiredWeight.ToString());
|
||||||
|
await SendNotificationAsync(user, "Two-factor authentication code", code, NotificationInformationType.AUTH,providerWithRequiredWeight);
|
||||||
|
_logger.LogInformation("Two-factor authentication code sent to user {Username}", model.Username);
|
||||||
|
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Code sent successfully"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to send code"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("verify-2fa")]
|
||||||
|
public async Task<IActionResult> VerifyTwoFactorCode([FromBody] TwoFactorDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (model.Username != null)
|
||||||
|
{
|
||||||
|
var user = await _userManager.FindByNameAsync(model.Username);
|
||||||
|
var providerWithRequiredWeight = user.TwoFactorProviders
|
||||||
|
.FirstOrDefault(p => (int)p == model.TwoFactorProvider);
|
||||||
|
var signInResult = _signInManager.TwoFactorSignInAsync(providerWithRequiredWeight.ToString(),
|
||||||
|
model.Code, false, model.RememberMe);
|
||||||
|
|
||||||
|
|
||||||
|
if (!signInResult.Result.Succeeded)
|
||||||
|
{
|
||||||
|
return BadRequest(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 400,
|
||||||
|
Message = "Invalid code"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = _jwtService.GenerateAccessToken(user);
|
||||||
|
var refreshToken = await _jwtService.GenerateRefreshTokenAsync(user);
|
||||||
|
|
||||||
|
_logger.LogInformation("User logged in successfully: {Username}", model.Username);
|
||||||
|
await SendNotificationAsync(user, "Login successful", "You have successfully logged in", NotificationInformationType.WARNING,TwoFactorProvider.EMAIL);
|
||||||
|
|
||||||
|
return Ok( new LoginResultResponse()
|
||||||
|
{
|
||||||
|
RequiresTwoFactorAuth = false,
|
||||||
|
Success = true,
|
||||||
|
Token = new RefreshTokenDTO()
|
||||||
|
{
|
||||||
|
AccessToken = token,
|
||||||
|
RefreshToken = refreshToken.Token
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_logger.LogError("Username can't be empty");
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Username can't be empty"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "An error occurred during user verification: {Message}", ex.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "An error occurred during user verification"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("enable-2fa")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> EnableTwoFactor([FromBody]EnableTwoFactorDTO model)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "User not found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
user.TwoFactorProviders.Add((TwoFactorProvider)model.TwoFactorProvider);
|
||||||
|
user.TwoFactorEnabled = true;
|
||||||
|
await _userManager.UpdateAsync(user);
|
||||||
|
var secretKey = await _userManager.GenerateTwoFactorTokenAsync(user, TwoFactorProvider.AUTHENTICATOR.ToString());
|
||||||
|
_logger.LogInformation("User logged in successfully: {Username}", User);
|
||||||
|
await SendNotificationAsync(user, "Login successful", "You have successfully logged in", NotificationInformationType.WARNING,(TwoFactorProvider)model.TwoFactorProvider);
|
||||||
|
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Two-factor authentication enabled successfully"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("disable-2fa")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<IActionResult> DisableTwoFactor([FromBody] DisableTwoFactorDTO model)
|
||||||
|
{
|
||||||
|
var user = await _userManager.GetUserAsync(User);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound("User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!await _userManager.VerifyTwoFactorTokenAsync(user,model.TwoFactorProvider.ToString(),model.Code))
|
||||||
|
{
|
||||||
|
return BadRequest("Invalid verification code");
|
||||||
|
}
|
||||||
|
|
||||||
|
user.TwoFactorEnabled = false;
|
||||||
|
await _userManager.UpdateAsync(user);
|
||||||
|
|
||||||
|
return Ok("Two-factor authentication disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Helpers
|
||||||
|
|
||||||
|
private async Task SendNotificationAsync(ApplicationUser user,
|
||||||
|
string title,
|
||||||
|
string message,
|
||||||
|
NotificationInformationType notificationInformationType,
|
||||||
|
TwoFactorProvider provider)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
switch (provider)
|
||||||
|
{
|
||||||
|
case TwoFactorProvider.EMAIL:
|
||||||
|
await _notificationService.SendMailNotificationAsync(user, _mailNotificationsFactory.CreateNotification(notificationInformationType, title, message));
|
||||||
|
break;
|
||||||
|
case TwoFactorProvider.PHONE:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
break;
|
||||||
|
case TwoFactorProvider.PUSH:
|
||||||
|
await _notificationService.SendPushNotificationAsync(user, _pushNotificationsFactory.CreateNotification(notificationInformationType, title, message));
|
||||||
|
break;
|
||||||
|
case TwoFactorProvider.AUTHENTICATOR:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "An error occurred during notification: {Message}", ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetRemoteIpAddress()
|
||||||
|
{
|
||||||
|
if (HttpContext.Connection.RemoteIpAddress != null)
|
||||||
|
{
|
||||||
|
return HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
166
Controllers/InstructionController.cs
Normal file
166
Controllers/InstructionController.cs
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
using GamificationService.Exceptions.Services.Instruction;
|
||||||
|
using GamificationService.Models.Database;
|
||||||
|
using GamificationService.Models.DTO;
|
||||||
|
using GamificationService.Models.Messages.Instructions;
|
||||||
|
using GamificationService.Services.Instructions;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GamificationService.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize(Policy = "User")]
|
||||||
|
public class InstructionController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IInstructionService _instructionService;
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly ILogger<InstructionController> _logger;
|
||||||
|
|
||||||
|
public InstructionController(IInstructionService instructionService, UserManager<ApplicationUser> userManager, ILogger<InstructionController> logger)
|
||||||
|
{
|
||||||
|
_instructionService = instructionService;
|
||||||
|
_userManager = userManager;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new instruction.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The instruction model.</param>
|
||||||
|
/// <returns><see cref="InstructionDTO"/> which was created</returns>
|
||||||
|
/// <response code="200">Returns the created instruction</response>
|
||||||
|
[HttpPost]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public async Task<IActionResult> CreateInstruction([FromBody] CreateInstructionRequest model)
|
||||||
|
{
|
||||||
|
var instruction = await _instructionService.CreateInstruction(model);
|
||||||
|
return Ok(instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update an existing instruction.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The instruction model. Id must match the object which is being updated.</param>
|
||||||
|
/// <returns><see cref="bool"/></returns>
|
||||||
|
/// <response code="200"></response>
|
||||||
|
/// <response code="404">If the instruction is not found</response>
|
||||||
|
[HttpPut]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public async Task<IActionResult> UpdateInstruction([FromBody] UpdateInstructionRequest model)
|
||||||
|
{
|
||||||
|
var instruction = await _instructionService.UpdateInstructionById(model);
|
||||||
|
return Ok(instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete an existing instruction.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the instruction to delete.</param>
|
||||||
|
/// <returns><see cref="bool"/></returns>
|
||||||
|
/// <response code="200"></response>
|
||||||
|
/// <response code="404">If the instruction is not found</response>
|
||||||
|
[HttpDelete]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public async Task<IActionResult> DeleteInstruction(long id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Ok(await _instructionService.DeleteInstructionById(id));
|
||||||
|
}
|
||||||
|
catch (InstructionNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve all instructions for the authenticated user.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of <see cref="InstructionDTO"/> for the user.</returns>
|
||||||
|
/// <response code="200">Returns the list of all instructions</response>
|
||||||
|
[HttpGet("all")]
|
||||||
|
public async Task<IActionResult> GetAllInstructions()
|
||||||
|
{
|
||||||
|
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||||
|
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||||
|
|
||||||
|
return Ok(_instructionService.GetAllInstructions(userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve all completed instructions for the authenticated user.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of <see cref="InstructionDTO"/> that are completed for the user.</returns>
|
||||||
|
/// <response code="200">Returns the list of completed instructions</response>
|
||||||
|
[HttpGet("completed")]
|
||||||
|
public async Task<IActionResult> GetCompletedInstructions()
|
||||||
|
{
|
||||||
|
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||||
|
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||||
|
|
||||||
|
return Ok(_instructionService.GetCompletedInstructions(userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve all unfinished instructions for the authenticated user.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of <see cref="InstructionDTO"/> that are unfinished for the user.</returns>
|
||||||
|
/// <response code="200">Returns the list of unfinished instructions</response>
|
||||||
|
[HttpGet("unfinished")]
|
||||||
|
public async Task<IActionResult> GetUnfinishedInstructions()
|
||||||
|
{
|
||||||
|
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||||
|
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||||
|
|
||||||
|
return Ok(_instructionService.GetUnfinishedInstructions(userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve instructions by category ID for the authenticated user.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the category to filter instructions.</param>
|
||||||
|
/// <returns>A list of <see cref="InstructionDTO"/> for the specified category.</returns>
|
||||||
|
/// <response code="200">Returns the list of instructions for the specified category</response>
|
||||||
|
/// <response code="404">If the category is not found</response>
|
||||||
|
[HttpGet("category/{id}")]
|
||||||
|
public async Task<IActionResult> GetInstructionsByCategoryId(long id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||||
|
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||||
|
|
||||||
|
return Ok(_instructionService.GetInstructionsByCategoryId(userId, id));
|
||||||
|
}
|
||||||
|
catch (CategoryNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve a specific instruction by its ID for the authenticated user.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the instruction to retrieve.</param>
|
||||||
|
/// <returns><see cref="InstructionDTO"/> for the specified instruction.</returns>
|
||||||
|
/// <response code="200">Returns the instruction with the specified ID</response>
|
||||||
|
/// <response code="404">If the instruction is not found</response>
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public async Task<IActionResult> GetInstructionById(long id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||||
|
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||||
|
|
||||||
|
return Ok(_instructionService.GetInstructionById(userId, id));
|
||||||
|
}
|
||||||
|
catch(InstructionNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
278
Controllers/InstructionTestController.cs
Normal file
278
Controllers/InstructionTestController.cs
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using GamificationService.Exceptions.Services.Instruction;
|
||||||
|
using GamificationService.Exceptions.Services.InstructionTest;
|
||||||
|
using GamificationService.Models.BasicResponses;
|
||||||
|
using GamificationService.Models.Database;
|
||||||
|
using GamificationService.Models.DTO;
|
||||||
|
using GamificationService.Services.InstructionTests;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GamificationService.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize(Policy = "User")]
|
||||||
|
public class InstructionTestController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IInstructionTestsService _instructionTestsService;
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly ILogger<InstructionTestController> _logger;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public InstructionTestController(IInstructionTestsService instructionTestsService, UserManager<ApplicationUser> userManager, ILogger<InstructionTestController> logger, IMapper mapper)
|
||||||
|
{
|
||||||
|
_instructionTestsService = instructionTestsService;
|
||||||
|
_userManager = userManager;
|
||||||
|
_logger = logger;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instruction test by its ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the instruction test.</param>
|
||||||
|
/// <returns>An <see cref="InstructionTestDTO"/> containing the instruction test DTO if found, or a 404 Not Found if not found.</returns>
|
||||||
|
/// <response code="200">Returns the instruction test DTO</response>
|
||||||
|
/// <response code="404">If the instruction test is not found</response>
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public IActionResult GetInstructionTestById(long id)
|
||||||
|
{
|
||||||
|
// TODO: verify admin access / user ownership
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var instructionTest = _instructionTestsService.GetInstructionTestById(id);
|
||||||
|
return Ok(_mapper.Map<InstructionTestDTO>(instructionTest));
|
||||||
|
}
|
||||||
|
catch (InstructionTestNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instruction test by its instruction ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the instruction.</param>
|
||||||
|
/// <returns>An <see cref="InstructionTestDTO"/> containing the instruction test DTO if found, or a 404 Not Found if not found.</returns>
|
||||||
|
/// <response code="200">Returns the instruction test DTO</response>
|
||||||
|
/// <response code="404">If the instruction is not found</response>
|
||||||
|
[HttpGet("instruction/{id}")]
|
||||||
|
public IActionResult GetInstructionTestsByInstructionId(long id)
|
||||||
|
{
|
||||||
|
// TODO: verify admin access / user ownership
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var instructionTest = _instructionTestsService.GetInstructionTestsByInstructionId(id);
|
||||||
|
return Ok(_mapper.Map<InstructionTestDTO>(instructionTest));
|
||||||
|
}
|
||||||
|
catch (InstructionTestNotFoundException)
|
||||||
|
{
|
||||||
|
return Ok(new List<InstructionTestDTO>());
|
||||||
|
}
|
||||||
|
catch (InstructionNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Instruction not found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all instruction test questions by instruction test ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instructionTestId">The ID of the instruction test.</param>
|
||||||
|
/// <returns>A list of <see cref="InstructionTestQuestionDTO"/> containing the instruction test questions if found, or a 404 Not Found if not found.</returns>
|
||||||
|
/// <response code="200">Returns the instruction test questions</response>
|
||||||
|
/// <response code="404">If the instruction test questions are not found</response>
|
||||||
|
[HttpGet("{instructionTestId}/questions")]
|
||||||
|
public IActionResult GetInstructionTestQuestionsByInstructionTestId(long instructionTestId)
|
||||||
|
{
|
||||||
|
// TODO: verify admin access / user ownership
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var instructionTestQuestions = _instructionTestsService.GetInstructionTestQuestionsByInstructionTestId(instructionTestId);
|
||||||
|
return Ok(instructionTestQuestions);
|
||||||
|
}
|
||||||
|
catch (InstructionTestNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all instruction test results for authorized user by instruction ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="instructionTestId">The ID of the instruction.</param>
|
||||||
|
/// <returns>A list of <see cref="InstructionTestResultDTO"/> containing the instruction test results if found, or a 404 Not Found if not found.</returns>
|
||||||
|
/// <response code="200">Returns the instruction test results</response>
|
||||||
|
/// <response code="404">If the instruction test results are not found</response>
|
||||||
|
[HttpGet("/{instructionTestId}/results")]
|
||||||
|
public async Task<IActionResult> GetUserInstructionTestResultsByInstructionTestId(long instructionTestId)
|
||||||
|
{
|
||||||
|
// TODO: verify user ownership
|
||||||
|
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||||
|
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var instructionTestResults = _instructionTestsService.GetUserInstructionTestResultsByInstructionTestId(userId, instructionTestId);
|
||||||
|
return Ok(instructionTestResults);
|
||||||
|
}
|
||||||
|
catch (InstructionTestNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all instruction test results for a specific user by instruction test ID (admin access).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId">The ID of the user whose results are being requested.</param>
|
||||||
|
/// <param name="instructionTestId">The ID of the instruction.</param>
|
||||||
|
/// <returns>A list of <see cref="InstructionTestResultDTO"/> containing the instruction test results if found, or a 404 Not Found if not found.</returns>
|
||||||
|
/// <response code="200">Returns the instruction test results</response>
|
||||||
|
/// <response code="404">If the instruction test results are not found</response>
|
||||||
|
/// <response code="403">If the user is not an admin</response>
|
||||||
|
[HttpGet("{instructionTestId}/user/{userId}/results")]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
public IActionResult GetInstructionTestResultsForUserByInstructionTestId(long userId, long instructionTestId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var instructionTestResults = _instructionTestsService.GetUserInstructionTestResultsByInstructionTestId(userId, instructionTestId);
|
||||||
|
return Ok(instructionTestResults);
|
||||||
|
}
|
||||||
|
catch (InstructionTestNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all instruction test results for a user by user ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the user.</param>
|
||||||
|
/// <returns>A list of <see cref="InstructionTestResultDTO"/> containing the instruction test results if found, or a 404 Not Found if not found.</returns>
|
||||||
|
/// <response code="200">Returns the instruction test results</response>
|
||||||
|
/// <response code="404">If the instruction test results are not found</response>
|
||||||
|
[HttpGet("user/{id}/results")]
|
||||||
|
public IActionResult GetInstructionTestResultsByUserId(long id)
|
||||||
|
{
|
||||||
|
// TODO: verify admin access / user ownership
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var instructionTestResults = _instructionTestsService.GetInstructionTestResultsByUserId(id);
|
||||||
|
return Ok(instructionTestResults);
|
||||||
|
}
|
||||||
|
catch (InstructionTestNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all completed instruction test results for a user by user ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the user.</param>
|
||||||
|
/// <returns>A list of <see cref="InstructionTestResultDTO"/> containing the instruction test results if found, or a 404 Not Found if not found.</returns>
|
||||||
|
/// <response code="200">Returns the instruction test results</response>
|
||||||
|
/// <response code="404">If the instruction test results are not found</response>
|
||||||
|
[HttpGet("user/{id}/completed")]
|
||||||
|
public IActionResult GetCompletedInstructionTestsByUserId(long id)
|
||||||
|
{
|
||||||
|
// TODO: verify admin access / user ownership
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var instructionTestResults = _instructionTestsService.GetCompletedInstructionTestsByUserId(id);
|
||||||
|
return Ok(instructionTestResults);
|
||||||
|
}
|
||||||
|
catch (InstructionTestNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instruction test.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The instruction test model.</param>
|
||||||
|
/// <returns>A <see cref="InstructionTestDTO"/> containing the created instruction test if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||||
|
/// <response code="200">Returns the created instruction test</response>
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> CreateInstructionTest([FromBody] InstructionTestCreateDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var instructionTest = await _instructionTestsService.CreateInstructionTest(model);
|
||||||
|
return Ok(instructionTest);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return StatusCode(500, "Failed to create instruction test");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates an existing instruction test.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The instruction test model.</param>
|
||||||
|
/// <returns>A <see cref="InstructionTestDTO"/> containing the updated instruction test if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||||
|
/// <response code="200">Returns the updated instruction test</response>
|
||||||
|
[HttpPut]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public async Task<IActionResult> UpdateInstructionTest([FromBody] InstructionTestCreateDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var instructionTest = await _instructionTestsService.UpdateInstructionTest(model);
|
||||||
|
return Ok(instructionTest);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return StatusCode(500, "Failed to update instruction test");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes an existing instruction test.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the instruction test to delete.</param>
|
||||||
|
/// <returns>A <see cref="bool"/></returns>
|
||||||
|
/// <response code="200">Returns the deletion status.</response>
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public async Task<IActionResult> DeleteInstructionTest(long id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _instructionTestsService.DeleteInstructionTestByIdAsync(id);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return StatusCode(500, "Failed to delete instruction test");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("submit")]
|
||||||
|
public async Task<IActionResult> SubmitInstructionTest([FromBody] InstructionTestSubmissionDTO model)
|
||||||
|
{
|
||||||
|
// TODO: verify user access
|
||||||
|
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||||
|
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _instructionTestsService.SubmitInstructionTestAsync(userId, model);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return StatusCode(500, "Failed to submit instruction test");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
186
Controllers/RightsController.cs
Normal file
186
Controllers/RightsController.cs
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
using GamificationService.Models.BasicResponses;
|
||||||
|
using GamificationService.Models.DTO;
|
||||||
|
using GamificationService.Services.Rights;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GamificationService.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public class RightsController : ControllerBase
|
||||||
|
{
|
||||||
|
#region Services
|
||||||
|
|
||||||
|
private readonly IRightsService _rightsService;
|
||||||
|
private readonly ILogger<RightsController> _logger;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
|
||||||
|
public RightsController(IRightsService rightsService, ILogger<RightsController> logger)
|
||||||
|
{
|
||||||
|
_rightsService = rightsService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetAllRightsAsync([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var (rights, totalCount) = await _rightsService.GetAllRightsAsync(pageNumber, pageSize);
|
||||||
|
|
||||||
|
_logger.LogInformation($"Retrieved {rights.Count} rights");
|
||||||
|
|
||||||
|
var response = new GetAllRightsResponse()
|
||||||
|
{
|
||||||
|
Rights = rights,
|
||||||
|
TotalCount = totalCount,
|
||||||
|
PageNumber = pageNumber,
|
||||||
|
PageSize = pageSize
|
||||||
|
};
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to get rights.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public async Task<IActionResult> GetRightByIdAsync(long id)
|
||||||
|
{
|
||||||
|
var right = await _rightsService.GetRightByIdAsync(id);
|
||||||
|
_logger.LogInformation($"Retrieved right with id: {id}");
|
||||||
|
if (right == null)
|
||||||
|
{
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
|
||||||
|
Code = 404,
|
||||||
|
Message = "Right not found"
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Ok(right);
|
||||||
|
}
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> CreateRightAsync([FromBody] RightDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var right = await _rightsService.CreateRightAsync(model.Name, model.Description);
|
||||||
|
|
||||||
|
_logger.LogInformation($"Created right: {right}");
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(CreateRightAsync), new { id = right.Id }, right);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to create right.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
public async Task<IActionResult> UpdateRightAsync(long id, [FromBody] RightDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (await _rightsService.UpdateRightAsync(id, model.Name, model.Description))
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Updated right: {id}");
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Rights updated",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_logger.LogError($"Unknown with right updating, {id}");
|
||||||
|
return StatusCode(418,
|
||||||
|
new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 418,
|
||||||
|
Message = "Failed to update right."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (KeyNotFoundException)
|
||||||
|
{
|
||||||
|
_logger.LogError($"Right not found, {id} ");
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Right not found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to update right"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
public async Task<IActionResult> DeleteRightAsync(long id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if( await _rightsService.DeleteRightAsync(id))
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Deleted right: {id}");
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Rights deleted",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_logger.LogError($"Unknown error with right deleting, {id} ");
|
||||||
|
return StatusCode(418, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 418,
|
||||||
|
Message = "Failed to delete right"
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (KeyNotFoundException)
|
||||||
|
{
|
||||||
|
_logger.LogError($"Role not found, {id} ");
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Right not found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to delete right"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
283
Controllers/RoleController.cs
Normal file
283
Controllers/RoleController.cs
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
using GamificationService.Models.BasicResponses;
|
||||||
|
using GamificationService.Models.DTO;
|
||||||
|
using GamificationService.Services.Roles;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http.HttpResults;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GamificationService.Controllers;
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public class RoleController : ControllerBase
|
||||||
|
{
|
||||||
|
#region Services
|
||||||
|
|
||||||
|
private readonly IRolesService _rolesService;
|
||||||
|
private readonly ILogger<RoleController> _logger;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
|
||||||
|
public RoleController(ILogger<RoleController> logger, IRolesService rolesService)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_rolesService = rolesService;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ControllerMethods
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> GetAllRolesAsync([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var (roles, totalCount) = await _rolesService.GetAllRolesAsync(pageNumber, pageSize);
|
||||||
|
_logger.LogInformation($"Roles found successfully, {roles.Count}");
|
||||||
|
var response = new GetAllRolesResponse()
|
||||||
|
{
|
||||||
|
Roles = roles,
|
||||||
|
TotalCount = totalCount,
|
||||||
|
PageNumber = pageNumber,
|
||||||
|
PageSize = pageSize
|
||||||
|
};
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex,ex.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to get roles"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public async Task<IActionResult> GetRoleByIdAsync(long id)
|
||||||
|
{
|
||||||
|
var role = await _rolesService.GetRoleByIdAsync(id);
|
||||||
|
_logger.LogInformation($"Role found successfully, {role.Id}");
|
||||||
|
if (role == null)
|
||||||
|
{
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
|
||||||
|
Code = 404,
|
||||||
|
Message = "Role not found"
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Ok(role);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IActionResult> CreateRoleAsync([FromBody] RoleDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
var role = await _rolesService.CreateRoleAsync(model.Name, model.Description);
|
||||||
|
_logger.LogInformation($"Role created successfully, {role.Id}");
|
||||||
|
return CreatedAtAction(nameof(CreateRoleAsync), new { id = role.Id }, role);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to create role"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpPut("{id}")]
|
||||||
|
public async Task<IActionResult> UpdateRoleAsync(long id, [FromBody] RoleDTO model)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (await _rolesService.UpdateRoleAsync(id, model.Name, model.Description))
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Role updated successfully, {id}");
|
||||||
|
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Role updated successfully"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogCritical($"Unknown error with role updating, {id}");
|
||||||
|
return StatusCode(418,new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 418,
|
||||||
|
Message = "Role not found"
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (KeyNotFoundException)
|
||||||
|
{
|
||||||
|
_logger.LogError($"Role not found, {id} ");
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Role not found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to update role"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
public async Task<IActionResult> DeleteRoleAsync(long id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (await _rolesService.DeleteRoleAsync(id))
|
||||||
|
{
|
||||||
|
|
||||||
|
_logger.LogInformation($"Role updated successfully, {id}");
|
||||||
|
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Role updated successfully"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogCritical($"Unknown error with role deleting, RoleId {id}");
|
||||||
|
return StatusCode(418,new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 418,
|
||||||
|
Message = "Role not found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (KeyNotFoundException)
|
||||||
|
{
|
||||||
|
_logger.LogError($"Role not found, {id} ");
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Role not found"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to delete role"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpPost("{roleId}/rights/{rightId}")]
|
||||||
|
public async Task<IActionResult> AddRightToRoleAsync(long roleId, long rightId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (await _rolesService.AddRightToRoleAsync(roleId, rightId))
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Right added to role successfully, RoleId: {roleId}, RightId: {rightId}");
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Right added to role successfully"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogCritical($"Unknown error with adding right to role, RoleId: {roleId}, RightId: {rightId}");
|
||||||
|
return StatusCode(418,new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 418,
|
||||||
|
Message = "Right not found for role"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch(KeyNotFoundException e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Right not found for role"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to add right to role"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{roleId}/rights/{rightId}")]
|
||||||
|
public async Task<IActionResult> RemoveRightFromRoleAsync(long roleId, long rightId)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
if (await _rolesService.RemoveRightFromRoleAsync(roleId, rightId))
|
||||||
|
{
|
||||||
|
_logger.LogInformation($"Right removed from role successfully, RoleId: {roleId}, RightId: {rightId}");
|
||||||
|
|
||||||
|
return Ok(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 200,
|
||||||
|
Message = "Right removed from role successfully"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogCritical($"Unknown error with removing right from role, RoleId: {roleId}, RightId: {rightId}");
|
||||||
|
return StatusCode(418, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 418,
|
||||||
|
Message = "Right not found right for role"
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (KeyNotFoundException e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return NotFound(new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 404,
|
||||||
|
Message = "Right not found for role"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, e.Message);
|
||||||
|
return StatusCode(500, new BasicResponse()
|
||||||
|
{
|
||||||
|
Code = 500,
|
||||||
|
Message = "Failed to remove right from role"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
184
Controllers/UserProfileController.cs
Normal file
184
Controllers/UserProfileController.cs
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using GamificationService.Exceptions.Services.ProfileService;
|
||||||
|
using GamificationService.Models.Database;
|
||||||
|
using GamificationService.Models.DTO;
|
||||||
|
using GamificationService.Services.UsersProfile;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace GamificationService.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Authorize(Policy = "User")]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
public class UserProfileController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IUserProfileService _userProfilesService;
|
||||||
|
private readonly UserManager<ApplicationUser> _userManager;
|
||||||
|
private readonly ILogger<UserProfileController> _logger;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public UserProfileController(IUserProfileService userProfilesService, UserManager<ApplicationUser> userManager, ILogger<UserProfileController> logger, IMapper mapper)
|
||||||
|
{
|
||||||
|
_userProfilesService = userProfilesService;
|
||||||
|
_userManager = userManager;
|
||||||
|
_logger = logger;
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a user profile by its ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username">The username of the user profile's owner.</param>
|
||||||
|
/// <returns>An <see cref="UserProfileDTO"/> containing the user profile DTO if found, or a 404 Not Found if not found.</returns>
|
||||||
|
/// <response code="200">Returns the user profile DTO</response>
|
||||||
|
/// <response code="404">If the user profile is not found</response>
|
||||||
|
[HttpGet("user/{username}")]
|
||||||
|
public async Task<IActionResult> GetUserProfileByUsername(string username)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var user = (await _userManager.FindByNameAsync(username));
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
var userProfile = _userProfilesService.GetUserProfileByUserId(user.Id);
|
||||||
|
return Ok(_mapper.Map<UserProfileDTO>(userProfile));
|
||||||
|
}
|
||||||
|
catch (ProfileNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a user profile by its ID.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the user profile.</param>
|
||||||
|
/// <returns>An <see cref="UserProfileDTO"/> containing the user profile DTO if found, or a 404 Not Found if not found.</returns>
|
||||||
|
/// <response code="200">Returns the user profile DTO</response>
|
||||||
|
/// <response code="404">If the user profile is not found</response>
|
||||||
|
[HttpGet("{id}")]
|
||||||
|
public IActionResult GetUserProfileById(long id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var userProfile = _userProfilesService.GetUserProfileById(id);
|
||||||
|
return Ok(_mapper.Map<UserProfileDTO>(userProfile));
|
||||||
|
}
|
||||||
|
catch (ProfileNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a new user profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username">The username of the user.</param>
|
||||||
|
/// <param name="model">The user profile model.</param>
|
||||||
|
/// <returns>A <see cref="UserProfileDTO"/> containing the created user profile if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||||
|
/// <response code="200">Returns the created user profile</response>
|
||||||
|
/// <response code="404">If the user is not found</response>
|
||||||
|
[HttpPost("user/{username}")]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public async Task<IActionResult> AddUserProfile(string username, [FromBody] UserProfileCreateDTO model)
|
||||||
|
{
|
||||||
|
var user = (await _userManager.FindByNameAsync(username));
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var userProfile = await _userProfilesService.AddUserProfile(user.Id, model);
|
||||||
|
return Ok(_mapper.Map<UserProfileDTO>(userProfile));
|
||||||
|
}
|
||||||
|
catch (ProfileNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update user profile for the logged in user.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="model">The user profile model.</param>
|
||||||
|
/// <returns>A <see cref="UserProfileDTO"/> containing the updated user profile if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||||
|
/// <response code="200">Returns the updated user profile</response>
|
||||||
|
/// <response code="404">If the user profile is not found</response>
|
||||||
|
[HttpPut]
|
||||||
|
public async Task<IActionResult> UpdateUserProfile([FromBody] UserProfileCreateDTO model)
|
||||||
|
{
|
||||||
|
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||||
|
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool result = await _userProfilesService.UpdateUserProfileByUserId(userId, model);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (ProfileNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates an existing user profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="username">The username of the user.</param>
|
||||||
|
/// <param name="model">The user profile model.</param>
|
||||||
|
/// <returns>A <see cref="UserProfileDTO"/> containing the updated user profile if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||||
|
/// <response code="200">Returns the updated user profile</response>
|
||||||
|
/// <response code="404">If the user profile is not found</response>
|
||||||
|
[HttpPut]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
[Route("user/{userId}")]
|
||||||
|
public async Task<IActionResult> UpdateUserProfileByUsername(string username, [FromBody] UserProfileCreateDTO model)
|
||||||
|
{
|
||||||
|
var user = (await _userManager.FindByNameAsync(username));
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool result = await _userProfilesService.UpdateUserProfileByUserId(user.Id, model);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
catch (ProfileNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes an existing user profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The ID of the user profile to delete.</param>
|
||||||
|
/// <returns>A <see cref="bool"/></returns>
|
||||||
|
/// <response code="200">Returns true.</response>
|
||||||
|
/// <response code="404">If the user profile is not found</response>
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public IActionResult DeleteUserProfile(long id)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_userProfilesService.DeleteUserProfile(id);
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
catch (ProfileNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
50
Database/ApplicationContext.cs
Executable file
50
Database/ApplicationContext.cs
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
using GamificationService.Models.Database;
|
||||||
|
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace GamificationService.Database;
|
||||||
|
|
||||||
|
|
||||||
|
public class ApplicationContext : IdentityDbContext<ApplicationUser, ApplicationRole, long>
|
||||||
|
{
|
||||||
|
public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<Right> Rights { get; set; }
|
||||||
|
public DbSet<RefreshToken> RefreshTokens { get; set; }
|
||||||
|
public DbSet<ApplicationUser> Users { get; set; }
|
||||||
|
public DbSet<ApplicationRole> Roles { get; set; }
|
||||||
|
public DbSet<UserRole> UserRoles { get; set; }
|
||||||
|
public DbSet<RoleRight> RoleRights { get; set; }
|
||||||
|
public DbSet<UserProfile> UserProfiles { get; set; }
|
||||||
|
public DbSet<Instruction> Instructions { get; set; }
|
||||||
|
public DbSet<InstructionCategory> InstructionCategories { get; set; }
|
||||||
|
public DbSet<InstructionParagraph> InstructionParagraphs { get; set; }
|
||||||
|
public DbSet<InstructionTest> InstructionTests { get; set; }
|
||||||
|
public DbSet<InstructionTestQuestion> InstructionTestQuestions { get; set; }
|
||||||
|
public DbSet<InstructionTestResult> InstructionTestResults { get; set; }
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity<UserRole>()
|
||||||
|
.HasKey(ur => new { ur.UserId, ur.RoleId });
|
||||||
|
|
||||||
|
modelBuilder.Entity<RoleRight>()
|
||||||
|
.HasKey(rr => new { rr.RoleId, rr.RightId });
|
||||||
|
|
||||||
|
modelBuilder.Entity<InstructionTest>()
|
||||||
|
.HasMany(itq => itq.Questions);
|
||||||
|
|
||||||
|
modelBuilder.Entity<InstructionTestResult>()
|
||||||
|
.HasOne(itr => itr.InstructionTest);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Instruction>()
|
||||||
|
.HasOne(i => i.Category);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Instruction>()
|
||||||
|
.HasMany(i => i.Paragraphs);
|
||||||
|
}
|
||||||
|
}
|
||||||
54
Database/Extensions/ChangeTrackerExtensions.cs
Executable file
54
Database/Extensions/ChangeTrackerExtensions.cs
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
using GamificationService.Models.Database;
|
||||||
|
using GamificationService.Services.CurrentUsers;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
|
|
||||||
|
namespace GamificationService.Database.Extensions;
|
||||||
|
|
||||||
|
public static class ChangeTrackerExtensions
|
||||||
|
{
|
||||||
|
public static void SetAuditProperties(this ChangeTracker changeTracker, ICurrentUserService currentUserService)
|
||||||
|
{
|
||||||
|
changeTracker.DetectChanges();
|
||||||
|
IEnumerable<EntityEntry> entities =
|
||||||
|
changeTracker
|
||||||
|
.Entries()
|
||||||
|
.Where(t => t.Entity is AuditableEntity &&
|
||||||
|
(
|
||||||
|
t.State == EntityState.Deleted
|
||||||
|
|| t.State == EntityState.Added
|
||||||
|
|| t.State == EntityState.Modified
|
||||||
|
));
|
||||||
|
|
||||||
|
if (entities.Any())
|
||||||
|
{
|
||||||
|
DateTimeOffset timestamp = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
|
string user = currentUserService.GetCurrentUser().Login ?? "Unknown";
|
||||||
|
|
||||||
|
foreach (EntityEntry entry in entities)
|
||||||
|
{
|
||||||
|
AuditableEntity entity = (AuditableEntity)entry.Entity;
|
||||||
|
|
||||||
|
switch (entry.State)
|
||||||
|
{
|
||||||
|
case EntityState.Added:
|
||||||
|
entity.CreatedOn = timestamp;
|
||||||
|
entity.CreatedBy = user;
|
||||||
|
entity.UpdatedOn = timestamp;
|
||||||
|
entity.UpdatedBy = user;
|
||||||
|
break;
|
||||||
|
case EntityState.Modified:
|
||||||
|
entity.UpdatedOn = timestamp;
|
||||||
|
entity.UpdatedBy = user;
|
||||||
|
break;
|
||||||
|
case EntityState.Deleted:
|
||||||
|
entity.UpdatedOn = timestamp;
|
||||||
|
entity.UpdatedBy = user;
|
||||||
|
entry.State = EntityState.Deleted;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
98
Database/Repositories/GenericRepository.cs
Executable file
98
Database/Repositories/GenericRepository.cs
Executable file
@@ -0,0 +1,98 @@
|
|||||||
|
using System.Linq.Expressions;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||||
|
|
||||||
|
namespace GamificationService.Database.Repositories;
|
||||||
|
|
||||||
|
public class GenericRepository<TEntity> where TEntity : class
|
||||||
|
{
|
||||||
|
internal ApplicationContext context;
|
||||||
|
internal DbSet<TEntity> dbSet;
|
||||||
|
|
||||||
|
public GenericRepository(ApplicationContext context)
|
||||||
|
{
|
||||||
|
this.context = context;
|
||||||
|
this.dbSet = context.Set<TEntity>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual IQueryable<TEntity> Get(
|
||||||
|
Expression<Func<TEntity, bool>> filter = null,
|
||||||
|
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
|
||||||
|
string includeProperties = "")
|
||||||
|
{
|
||||||
|
IQueryable<TEntity> query = dbSet;
|
||||||
|
|
||||||
|
if (filter != null)
|
||||||
|
{
|
||||||
|
query = query.Where(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var includeProperty in includeProperties.Split
|
||||||
|
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
query = query.Include(includeProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orderBy != null)
|
||||||
|
{
|
||||||
|
return orderBy(query);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual TEntity? GetByID(object id)
|
||||||
|
{
|
||||||
|
return dbSet.Find(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async virtual Task<TEntity?> GetByIDAsync(object id)
|
||||||
|
{
|
||||||
|
return await dbSet.FindAsync(id);
|
||||||
|
}
|
||||||
|
public virtual void Insert(TEntity entity)
|
||||||
|
{
|
||||||
|
dbSet.Add(entity);
|
||||||
|
}
|
||||||
|
public virtual void InsertRange(IEnumerable<TEntity> entities)
|
||||||
|
{
|
||||||
|
dbSet.AddRange(entities);
|
||||||
|
}
|
||||||
|
public async virtual Task InsertAsync(TEntity entity)
|
||||||
|
{
|
||||||
|
await dbSet.AddAsync(entity);
|
||||||
|
}
|
||||||
|
public virtual void Delete(object id)
|
||||||
|
{
|
||||||
|
TEntity? entityToDelete = dbSet.Find(id);
|
||||||
|
|
||||||
|
if (entityToDelete == null)
|
||||||
|
{
|
||||||
|
// It's probably a good idea to throw an error here
|
||||||
|
// but I'm leaving it as is for now
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Delete(entityToDelete);
|
||||||
|
}
|
||||||
|
public virtual void DeleteRange(IEnumerable<TEntity> entities)
|
||||||
|
{
|
||||||
|
dbSet.RemoveRange(entities);
|
||||||
|
}
|
||||||
|
public virtual void Delete(TEntity entityToDelete)
|
||||||
|
{
|
||||||
|
if (context.Entry(entityToDelete).State == EntityState.Detached)
|
||||||
|
{
|
||||||
|
dbSet.Attach(entityToDelete);
|
||||||
|
}
|
||||||
|
dbSet.Remove(entityToDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Update(TEntity entityToUpdate)
|
||||||
|
{
|
||||||
|
dbSet.Attach(entityToUpdate);
|
||||||
|
context.Entry(entityToUpdate).State = EntityState.Modified;
|
||||||
|
}
|
||||||
|
}
|
||||||
239
Database/Repositories/UnitOfWork.cs
Executable file
239
Database/Repositories/UnitOfWork.cs
Executable file
@@ -0,0 +1,239 @@
|
|||||||
|
using GamificationService.Models.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
|
||||||
|
namespace GamificationService.Database.Repositories;
|
||||||
|
|
||||||
|
public class UnitOfWork : IDisposable
|
||||||
|
{
|
||||||
|
#region fields
|
||||||
|
|
||||||
|
private ApplicationContext _context;
|
||||||
|
private GenericRepository<UserProfile> _userProfileRepository;
|
||||||
|
private GenericRepository<ApplicationRole> _roleRepository;
|
||||||
|
private GenericRepository<Right?> _rightRepository;
|
||||||
|
private GenericRepository<RefreshToken> _refreshTokenRepository;
|
||||||
|
private GenericRepository<RoleRight> _roleRightRepository;
|
||||||
|
private GenericRepository<UserRole> _userRoleRepository;
|
||||||
|
private GenericRepository<Instruction> _instructionRepository;
|
||||||
|
private GenericRepository<InstructionParagraph> _instructionParagraphRepository;
|
||||||
|
private GenericRepository<InstructionCategory> _instructionCategoryRepository;
|
||||||
|
private GenericRepository<InstructionTest> _instructionTestRepository;
|
||||||
|
private GenericRepository<InstructionTestQuestion> _instructionTestQuestionRepository;
|
||||||
|
private GenericRepository<InstructionTestResult> _instructionTestResultRepository;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
private IDbContextTransaction _transaction;
|
||||||
|
|
||||||
|
public UnitOfWork(ApplicationContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
public GenericRepository<UserProfile> UserProfileRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._userProfileRepository == null)
|
||||||
|
{
|
||||||
|
this._userProfileRepository = new GenericRepository<UserProfile>(_context);
|
||||||
|
}
|
||||||
|
return _userProfileRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<ApplicationRole> RoleRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._roleRepository == null)
|
||||||
|
{
|
||||||
|
this._roleRepository = new GenericRepository<ApplicationRole>(_context);
|
||||||
|
}
|
||||||
|
return _roleRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<Right?> RightRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._rightRepository == null)
|
||||||
|
{
|
||||||
|
this._rightRepository = new GenericRepository<Right?>(_context);
|
||||||
|
}
|
||||||
|
return _rightRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<RefreshToken> RefreshTokenRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._refreshTokenRepository == null)
|
||||||
|
{
|
||||||
|
this._refreshTokenRepository = new GenericRepository<RefreshToken>(_context);
|
||||||
|
}
|
||||||
|
return _refreshTokenRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<RoleRight> RoleRightRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._roleRightRepository == null)
|
||||||
|
{
|
||||||
|
this._roleRightRepository = new GenericRepository<RoleRight>(_context);
|
||||||
|
}
|
||||||
|
return _roleRightRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<UserRole> UserRoleRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._userRoleRepository == null)
|
||||||
|
{
|
||||||
|
this._userRoleRepository = new GenericRepository<UserRole>(_context);
|
||||||
|
}
|
||||||
|
return _userRoleRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<Instruction> InstructionRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._instructionRepository == null)
|
||||||
|
{
|
||||||
|
this._instructionRepository = new GenericRepository<Instruction>(_context);
|
||||||
|
}
|
||||||
|
return _instructionRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<InstructionParagraph> InstructionParagraphRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._instructionParagraphRepository == null)
|
||||||
|
{
|
||||||
|
this._instructionParagraphRepository = new GenericRepository<InstructionParagraph>(_context);
|
||||||
|
}
|
||||||
|
return _instructionParagraphRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<InstructionCategory> InstructionCategoryRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._instructionCategoryRepository == null)
|
||||||
|
{
|
||||||
|
this._instructionCategoryRepository = new GenericRepository<InstructionCategory>(_context);
|
||||||
|
}
|
||||||
|
return _instructionCategoryRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<InstructionTest> InstructionTestRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._instructionTestRepository == null)
|
||||||
|
{
|
||||||
|
this._instructionTestRepository = new GenericRepository<InstructionTest>(_context);
|
||||||
|
}
|
||||||
|
return _instructionTestRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<InstructionTestQuestion> InstructionTestQuestionRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._instructionTestQuestionRepository == null)
|
||||||
|
{
|
||||||
|
this._instructionTestQuestionRepository = new GenericRepository<InstructionTestQuestion>(_context);
|
||||||
|
}
|
||||||
|
return _instructionTestQuestionRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GenericRepository<InstructionTestResult> InstructionTestResultRepository
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this._instructionTestResultRepository == null)
|
||||||
|
{
|
||||||
|
this._instructionTestResultRepository = new GenericRepository<InstructionTestResult>(_context);
|
||||||
|
}
|
||||||
|
return _instructionTestResultRepository;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public bool Save()
|
||||||
|
{
|
||||||
|
return _context.SaveChanges() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> SaveAsync()
|
||||||
|
{
|
||||||
|
return await _context.SaveChangesAsync() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private bool disposed = false;
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!this.disposed)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_context.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.disposed = true;
|
||||||
|
}
|
||||||
|
public async Task BeginTransactionAsync()
|
||||||
|
{
|
||||||
|
if (_transaction is not null)
|
||||||
|
throw new InvalidOperationException("A transaction has already been started.");
|
||||||
|
_transaction = await _context.Database.BeginTransactionAsync();
|
||||||
|
}
|
||||||
|
public async Task CommitAsync()
|
||||||
|
{
|
||||||
|
if (_transaction is null)
|
||||||
|
throw new InvalidOperationException("A transaction has not been started.");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _transaction.CommitAsync();
|
||||||
|
_transaction.Dispose();
|
||||||
|
_transaction = null;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
if (_transaction is not null)
|
||||||
|
await _transaction.RollbackAsync();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Dockerfile
Executable file
23
Dockerfile
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
||||||
|
USER $APP_UID
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 8080
|
||||||
|
EXPOSE 8081
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["PurpleHackBackend/PurpleHackBackend.csproj", "PurpleHackBackend/"]
|
||||||
|
RUN dotnet restore "PurpleHackBackend/PurpleHackBackend.csproj"
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/PurpleHackBackend"
|
||||||
|
RUN dotnet build "PurpleHackBackend.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
ARG BUILD_CONFIGURATION=Release
|
||||||
|
RUN dotnet publish "PurpleHackBackend.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "PurpleHackBackend.dll"]
|
||||||
26
Exceptions/Services/AuthService/AuthServiceException.cs
Executable file
26
Exceptions/Services/AuthService/AuthServiceException.cs
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.AuthService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to authentication service operations.
|
||||||
|
/// </summary>
|
||||||
|
public class AuthServiceException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AuthServiceException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public AuthServiceException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AuthServiceException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public AuthServiceException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AuthServiceException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public AuthServiceException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
25
Exceptions/Services/Instruction/CategoryNotFoundException.cs
Normal file
25
Exceptions/Services/Instruction/CategoryNotFoundException.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
namespace GamificationService.Exceptions.Services.Instruction;
|
||||||
|
|
||||||
|
public class CategoryNotFoundException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CategoryNotFoundException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public CategoryNotFoundException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CategoryNotFoundException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public CategoryNotFoundException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CategoryNotFoundException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public CategoryNotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.Instruction;
|
||||||
|
|
||||||
|
public class InstructionAccessException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionAccessException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionAccessException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionAccessException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionAccessException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionAccessException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionAccessException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.Instruction;
|
||||||
|
|
||||||
|
public class InstructionCreationException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionCreationException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionCreationException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionCreationException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionCreationException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionCreationException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionCreationException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.Instruction;
|
||||||
|
|
||||||
|
public class InstructionDeletionException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionDeletionException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionDeletionException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionDeletionException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionDeletionException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionDeletionException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionDeletionException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.Instruction;
|
||||||
|
|
||||||
|
public class InstructionNotFoundException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionNotFoundException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionNotFoundException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionNotFoundException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionNotFoundException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionNotFoundException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionNotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.Instruction;
|
||||||
|
|
||||||
|
public class InstructionUpdateException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionUpdateException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionUpdateException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionUpdateException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionUpdateException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionUpdateException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionUpdateException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs when there is a conflict in instruction test operations.
|
||||||
|
/// </summary>
|
||||||
|
public class InstructionTestConflictException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestConflictException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionTestConflictException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestConflictException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionTestConflictException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestConflictException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionTestConflictException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs during the creation of an instruction test.
|
||||||
|
/// </summary>
|
||||||
|
public class InstructionTestCreationException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestCreationException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionTestCreationException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestCreationException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionTestCreationException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestCreationException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionTestCreationException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs during the deletion of an instruction test.
|
||||||
|
/// </summary>
|
||||||
|
public class InstructionTestDeletionException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestDeletionException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionTestDeletionException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestDeletionException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionTestDeletionException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestDeletionException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionTestDeletionException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs when an instruction test is not found.
|
||||||
|
/// </summary>
|
||||||
|
public class InstructionTestNotFoundException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestNotFoundException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionTestNotFoundException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestNotFoundException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionTestNotFoundException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestNotFoundException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionTestNotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.InstructionTest;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs when an instruction test submission is failed.
|
||||||
|
/// </summary>
|
||||||
|
public class InstructionTestSubmissionException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestSubmissionException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public InstructionTestSubmissionException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestSubmissionException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InstructionTestSubmissionException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InstructionTestSubmissionException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public InstructionTestSubmissionException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
26
Exceptions/Services/JwtService/GenerateRefreshTokenException.cs
Executable file
26
Exceptions/Services/JwtService/GenerateRefreshTokenException.cs
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.JwtService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to jwt token service operations.
|
||||||
|
/// </summary>
|
||||||
|
public class GenerateRefreshTokenException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="enerateRefreshTokenException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public GenerateRefreshTokenException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GenerateRefreshTokenException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public GenerateRefreshTokenException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GenerateRefreshTokenException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public GenerateRefreshTokenException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
26
Exceptions/Services/JwtService/JwtServiceException.cs
Executable file
26
Exceptions/Services/JwtService/JwtServiceException.cs
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.JwtService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to jwt token service operations.
|
||||||
|
/// </summary>
|
||||||
|
public class JwtServiceException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JwtServiceException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JwtServiceException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JwtServiceException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public JwtServiceException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JwtServiceException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public JwtServiceException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
25
Exceptions/Services/User/UserNotFoundException.cs
Executable file
25
Exceptions/Services/User/UserNotFoundException.cs
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.User;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs when a user is not found.
|
||||||
|
/// </summary>
|
||||||
|
public class UserNotFoundException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UserNotFoundException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public UserNotFoundException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UserNotFoundException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public UserNotFoundException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UserNotFoundException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public UserNotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
25
Exceptions/Services/User/UserServiceException.cs
Executable file
25
Exceptions/Services/User/UserServiceException.cs
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.User;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to user service operations.
|
||||||
|
/// </summary>
|
||||||
|
public class UserServiceException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UserServiceException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public UserServiceException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UserServiceException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public UserServiceException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="UserServiceException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public UserServiceException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
26
Exceptions/UserProfileService/ProfileCreationException.cs
Normal file
26
Exceptions/UserProfileService/ProfileCreationException.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs during profile creation operations.
|
||||||
|
/// </summary>
|
||||||
|
public class ProfileCreationException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileCreationException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ProfileCreationException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileCreationException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public ProfileCreationException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileCreationException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public ProfileCreationException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
26
Exceptions/UserProfileService/ProfileDeletionException.cs
Normal file
26
Exceptions/UserProfileService/ProfileDeletionException.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs during profile deletion operations.
|
||||||
|
/// </summary>
|
||||||
|
public class ProfileDeletionException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileDeletionException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ProfileDeletionException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileDeletionException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public ProfileDeletionException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileDeletionException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public ProfileDeletionException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
26
Exceptions/UserProfileService/ProfileExistsException.cs
Normal file
26
Exceptions/UserProfileService/ProfileExistsException.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs when a profile already exists.
|
||||||
|
/// </summary>
|
||||||
|
public class ProfileExistsException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileExistsException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ProfileExistsException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileExistsException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public ProfileExistsException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileExistsException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public ProfileExistsException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
26
Exceptions/UserProfileService/ProfileNotFoundException.cs
Normal file
26
Exceptions/UserProfileService/ProfileNotFoundException.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs when a profile is not found.
|
||||||
|
/// </summary>
|
||||||
|
public class ProfileNotFoundException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileNotFoundException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ProfileNotFoundException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileNotFoundException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public ProfileNotFoundException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileNotFoundException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public ProfileNotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
26
Exceptions/UserProfileService/ProfileUpdateException.cs
Normal file
26
Exceptions/UserProfileService/ProfileUpdateException.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs during profile update operations.
|
||||||
|
/// </summary>
|
||||||
|
public class ProfileUpdateException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileUpdateException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ProfileUpdateException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileUpdateException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public ProfileUpdateException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProfileUpdateException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public ProfileUpdateException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
|
|
||||||
26
Exceptions/UtilServices/Api/ApiException.cs
Executable file
26
Exceptions/UtilServices/Api/ApiException.cs
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.Api;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to api operations.
|
||||||
|
/// </summary>
|
||||||
|
public class ApiException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ApiException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ApiException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ApiException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public ApiException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ApiException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public ApiException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
25
Exceptions/UtilServices/Api/BadRequestException.cs
Executable file
25
Exceptions/UtilServices/Api/BadRequestException.cs
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.Api;
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to api operations.
|
||||||
|
/// </summary>
|
||||||
|
public class BadRequestException : ApiException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BadRequestException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public BadRequestException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BadRequestException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public BadRequestException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="BadRequestException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public BadRequestException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
26
Exceptions/UtilServices/Api/ForbiddenException.cs
Executable file
26
Exceptions/UtilServices/Api/ForbiddenException.cs
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.Api;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to api operations.
|
||||||
|
/// </summary>
|
||||||
|
public class ForbiddenException : ApiException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ForbiddenException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public ForbiddenException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ForbiddenException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public ForbiddenException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ForbiddenException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public ForbiddenException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
26
Exceptions/UtilServices/Cookies/CookiesException.cs
Executable file
26
Exceptions/UtilServices/Cookies/CookiesException.cs
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.Cookies;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to cookie operations.
|
||||||
|
/// </summary>
|
||||||
|
public class CookiesException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CookiesException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public CookiesException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CookiesException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public CookiesException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="CookiesException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public CookiesException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
26
Exceptions/UtilServices/Cookies/DeleteCookiesException.cs
Executable file
26
Exceptions/UtilServices/Cookies/DeleteCookiesException.cs
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.Cookies;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to deleting cookies.
|
||||||
|
/// </summary>
|
||||||
|
public class DeleteCookiesException : CookiesException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DeleteCookiesException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public DeleteCookiesException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DeleteCookiesException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public DeleteCookiesException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="DeleteCookiesException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public DeleteCookiesException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
26
Exceptions/UtilServices/Cookies/SetCookiesException.cs
Executable file
26
Exceptions/UtilServices/Cookies/SetCookiesException.cs
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.Cookies;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to setting cookies.
|
||||||
|
/// </summary>
|
||||||
|
public class SetCookiesException : CookiesException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SetCookiesException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public SetCookiesException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SetCookiesException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public SetCookiesException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SetCookiesException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public SetCookiesException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
25
Exceptions/UtilServices/Email/EmailException.cs
Executable file
25
Exceptions/UtilServices/Email/EmailException.cs
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.Email;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to email operations.
|
||||||
|
/// </summary>
|
||||||
|
public class EmailException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EmailException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public EmailException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EmailException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public EmailException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EmailException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public EmailException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
25
Exceptions/UtilServices/Email/SendEmailException.cs
Executable file
25
Exceptions/UtilServices/Email/SendEmailException.cs
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.Email;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs during the process of sending an email.
|
||||||
|
/// </summary>
|
||||||
|
public class SendEmailException : EmailException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SendEmailException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public SendEmailException() : base("An error occurred while sending the email.") { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SendEmailException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public SendEmailException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="SendEmailException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public SendEmailException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
25
Exceptions/UtilServices/JWT/GenerateJWTTokenException.cs
Executable file
25
Exceptions/UtilServices/JWT/GenerateJWTTokenException.cs
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.JWT;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception that occurs while generating a JWT token.
|
||||||
|
/// </summary>
|
||||||
|
public class GenerateJWTTokenException : JWTException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GenerateJWTTokenException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public GenerateJWTTokenException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GenerateJWTTokenException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public GenerateJWTTokenException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="GenerateJWTTokenException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public GenerateJWTTokenException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
25
Exceptions/UtilServices/JWT/JWTException.cs
Executable file
25
Exceptions/UtilServices/JWT/JWTException.cs
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
namespace GamificationService.Exceptions.UtilServices.JWT;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an exception related to JWT (JSON Web Token) operations.
|
||||||
|
/// </summary>
|
||||||
|
public class JWTException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JWTException"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public JWTException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JWTException"/> class with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public JWTException(string message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="JWTException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||||
|
public JWTException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
204
Extensions/DependencyInjectionExtensions.cs
Executable file
204
Extensions/DependencyInjectionExtensions.cs
Executable file
@@ -0,0 +1,204 @@
|
|||||||
|
using System.Net;
|
||||||
|
using System.Net.Mail;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using GamificationService.Database;
|
||||||
|
using GamificationService.Database.Repositories;
|
||||||
|
using GamificationService.Logs;
|
||||||
|
using GamificationService.Mapper;
|
||||||
|
using GamificationService.Services.Cookies;
|
||||||
|
using GamificationService.Services.CurrentUsers;
|
||||||
|
using GamificationService.Services.InstructionTests;
|
||||||
|
using GamificationService.Services.JWT;
|
||||||
|
using GamificationService.Services.NotificationService;
|
||||||
|
using GamificationService.Services.Rights;
|
||||||
|
using GamificationService.Services.Roles;
|
||||||
|
using GamificationService.Services.UsersProfile;
|
||||||
|
using GamificationService.Utils;
|
||||||
|
using GamificationService.Utils.Factory;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace GamificationService.Extensions;
|
||||||
|
|
||||||
|
public static class MappingExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddMapping(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddAutoMapper(typeof(MappingProfile));
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CachingExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddRedisCaching(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddStackExchangeRedisCache(options =>
|
||||||
|
{
|
||||||
|
options.Configuration = configuration["Redis:ConnectionString"] ?? "localhost:6379";
|
||||||
|
options.InstanceName = configuration["Redis:InstanceName"] ?? "default";
|
||||||
|
});
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LoggingExtensions
|
||||||
|
{
|
||||||
|
public static IHostBuilder UseCustomSerilog(this IHostBuilder hostBuilder)
|
||||||
|
{
|
||||||
|
LoggingConfigurator.ConfigureLogging();
|
||||||
|
return hostBuilder.UseSerilog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DatabaseExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddDatabase(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
services.AddDbContext<ApplicationContext>(x =>
|
||||||
|
{
|
||||||
|
var dbSettings = configuration.GetSection("DatabaseSettings");
|
||||||
|
var hostname = dbSettings["Hostname"] ?? "localhost";
|
||||||
|
var port = dbSettings["Port"] ?? "5432";
|
||||||
|
var name = dbSettings["Name"] ?? "postgres";
|
||||||
|
var username = dbSettings["Username"] ?? "postgres";
|
||||||
|
var password = dbSettings["Password"] ?? "postgres";
|
||||||
|
x.UseNpgsql($"Server={hostname}:{port};Database={name};Uid={username};Pwd={password};");
|
||||||
|
});
|
||||||
|
services.AddScoped<UnitOfWork>(sp => new UnitOfWork(sp.GetRequiredService<ApplicationContext>()));
|
||||||
|
services.AddScoped(typeof(GenericRepository<>));
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SwaggerExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddSwagger(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
string projectName = Assembly.GetExecutingAssembly().GetName().Name;
|
||||||
|
services.AddOpenApi();
|
||||||
|
services.AddEndpointsApiExplorer();
|
||||||
|
services.AddSwaggerGen(c =>
|
||||||
|
{
|
||||||
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = projectName, Version = "v1" });
|
||||||
|
|
||||||
|
// Set the comments path for the Swagger JSON and UI
|
||||||
|
var xmlFile = $"{projectName}.xml";
|
||||||
|
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||||
|
c.IncludeXmlComments(xmlPath);
|
||||||
|
});
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class JwtAuthExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddJwtAuth(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var jwtSettings = configuration.GetSection("JwtSettings");
|
||||||
|
var secretKey = jwtSettings["SecretKey"] ?? throw new SystemException("JwtSettings:SecretKey not found");
|
||||||
|
var key = Encoding.ASCII.GetBytes(secretKey);
|
||||||
|
|
||||||
|
services.AddAuthentication(x =>
|
||||||
|
{
|
||||||
|
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
})
|
||||||
|
.AddJwtBearer(x =>
|
||||||
|
{
|
||||||
|
x.RequireHttpsMetadata = false;
|
||||||
|
x.SaveToken = true;
|
||||||
|
x.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(key),
|
||||||
|
ValidateIssuer = false,
|
||||||
|
ValidateAudience = false
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BackendServicesExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddBackendServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddScoped<IUserProfileService, UserProfileService>();
|
||||||
|
services.AddScoped<IInstructionTestsService, InstructionTestsService>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class UtilServicesExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddUtilServices(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddScoped<IJwtService, JwtService>();
|
||||||
|
services.AddScoped<ICookieService, CookieService>();
|
||||||
|
services.AddScoped<INotificationService,NotificationService>();
|
||||||
|
services.AddScoped<IRightsService,RightsService>();
|
||||||
|
services.AddScoped<IRolesService, RolesService>();
|
||||||
|
services.AddScoped<ICurrentUserService, CurrentUserService>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NotificationSettings
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddPushNotifications(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var notificationSettings = configuration.GetSection("NotificationSettings");
|
||||||
|
var apiKey = notificationSettings["ApiKey"];
|
||||||
|
var token = notificationSettings["Token"];
|
||||||
|
var baseUrl = notificationSettings["Url"];
|
||||||
|
var projectId = notificationSettings["ProjectId"];
|
||||||
|
|
||||||
|
HttpClient client = new HttpClient();
|
||||||
|
client.BaseAddress = new Uri(baseUrl);
|
||||||
|
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
|
||||||
|
|
||||||
|
services.AddSingleton(provider =>
|
||||||
|
{
|
||||||
|
var logger = provider.GetRequiredService<ILogger<PushNotificationsClient>>();
|
||||||
|
return new PushNotificationsClient(client, logger, token, projectId);
|
||||||
|
});
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static class EmailExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddEmail(this IServiceCollection services, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
var smtpSettings = configuration.GetSection("EmailSettings");
|
||||||
|
var host = smtpSettings["Host"] ?? "localhost";
|
||||||
|
var port = Convert.ToInt32(smtpSettings["Port"] ?? "25");
|
||||||
|
var username = smtpSettings["Username"] ?? "username";
|
||||||
|
var password = smtpSettings["Password"] ?? "password";
|
||||||
|
var email = smtpSettings["EmailFrom"] ?? "email";
|
||||||
|
services.AddScoped<SmtpClient>(sp => new SmtpClient(host)
|
||||||
|
{
|
||||||
|
Port = port,
|
||||||
|
Credentials = new NetworkCredential(username, password),
|
||||||
|
EnableSsl = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddSingleton<EmailClient>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FactoryExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddFactories(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSingleton<MailNotificationsFactory>();
|
||||||
|
services.AddSingleton<PushNotificationsFactory>();
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
53
MDSBackend.csproj
Executable file
53
MDSBackend.csproj
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<DocumentationFile>bin\Debug\net9.0\GamificationService.xml</DocumentationFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<NoWarn>1591</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AutoMapper" Version="14.0.0" />
|
||||||
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
|
<PackageReference Include="DavisSoftwareConsulting.Otp.NETCore" Version="1.3.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="9.0.2"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="9.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="9.0.3" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||||
|
<PackageReference Include="Otp.NET" Version="1.4.0" />
|
||||||
|
<PackageReference Include="OtpCore" Version="1.2.0-dev-78" />
|
||||||
|
<PackageReference Include="Serilog" Version="4.2.1-dev-02340" />
|
||||||
|
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||||
|
<PackageReference Include="Serilog.Enrichers.Environment" Version="3.0.1" />
|
||||||
|
<PackageReference Include="Serilog.Exceptions" Version="8.4.0" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.1-dev-00953" />
|
||||||
|
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="..\.dockerignore">
|
||||||
|
<Link>.dockerignore</Link>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Exceptions\UtilServices\Notifications\" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
169
Mapper/MappingProfile.cs
Executable file
169
Mapper/MappingProfile.cs
Executable file
@@ -0,0 +1,169 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using GamificationService.Models.Database;
|
||||||
|
using GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
namespace GamificationService.Mapper;
|
||||||
|
|
||||||
|
|
||||||
|
public class MappingProfile : Profile
|
||||||
|
{
|
||||||
|
public MappingProfile()
|
||||||
|
{
|
||||||
|
#region UserProfileMapping
|
||||||
|
|
||||||
|
CreateMap<UserProfile, UserProfileDTO>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.UserId, opt => opt.MapFrom(src => src.UserId))
|
||||||
|
.ForMember(x => x.Name, opt => opt.MapFrom(src => src.Name))
|
||||||
|
.ForMember(x => x.Surname, opt => opt.MapFrom(src => src.Surname))
|
||||||
|
.ForMember(x => x.Patronymic, opt => opt.MapFrom(src => src.Patronymic))
|
||||||
|
.ForMember(x => x.Birthdate, opt => opt.MapFrom(src => src.Birthdate))
|
||||||
|
.ForMember(x => x.Gender, opt => opt.MapFrom(src => src.Gender))
|
||||||
|
.ForMember(x => x.ContactEmail, opt => opt.MapFrom(src => src.ContactEmail))
|
||||||
|
.ForMember(x => x.ContactPhone, opt => opt.MapFrom(src => src.ContactPhone))
|
||||||
|
.ForMember(x => x.ProfilePicture, opt => opt.MapFrom(src => src.ProfilePicture));
|
||||||
|
|
||||||
|
CreateMap<UserProfileDTO, UserProfile>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.UserId, opt => opt.MapFrom(src => src.UserId))
|
||||||
|
.ForMember(x => x.Name, opt => opt.MapFrom(src => src.Name))
|
||||||
|
.ForMember(x => x.Surname, opt => opt.MapFrom(src => src.Surname))
|
||||||
|
.ForMember(x => x.Patronymic, opt => opt.MapFrom(src => src.Patronymic))
|
||||||
|
.ForMember(x => x.Birthdate, opt => opt.MapFrom(src => src.Birthdate))
|
||||||
|
.ForMember(x => x.Gender, opt => opt.MapFrom(src => src.Gender))
|
||||||
|
.ForMember(x => x.ContactEmail, opt => opt.MapFrom(src => src.ContactEmail))
|
||||||
|
.ForMember(x => x.ContactPhone, opt => opt.MapFrom(src => src.ContactPhone))
|
||||||
|
.ForMember(x => x.ProfilePicture, opt => opt.MapFrom(src => src.ProfilePicture));
|
||||||
|
|
||||||
|
CreateMap<UserProfileCreateDTO, UserProfile>()
|
||||||
|
.ForMember(x => x.Name, opt => opt.MapFrom(src => src.Name))
|
||||||
|
.ForMember(x => x.Surname, opt => opt.MapFrom(src => src.Surname))
|
||||||
|
.ForMember(x => x.Patronymic, opt => opt.MapFrom(src => src.Patronymic))
|
||||||
|
.ForMember(x => x.Birthdate, opt => opt.MapFrom(src => src.Birthdate))
|
||||||
|
.ForMember(x => x.Gender, opt => opt.MapFrom(src => src.Gender))
|
||||||
|
.ForMember(x => x.ContactEmail, opt => opt.MapFrom(src => src.ContactEmail))
|
||||||
|
.ForMember(x => x.ContactPhone, opt => opt.MapFrom(src => src.ContactPhone))
|
||||||
|
.ForMember(x => x.ProfilePicture, opt => opt.MapFrom(src => src.ProfilePicture));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionParagraphMapping
|
||||||
|
|
||||||
|
CreateMap<InstructionParagraph, InstructionParagraphDTO>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.Text, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.InstructionId, opt => opt.MapFrom(src => src.InstructionId))
|
||||||
|
.ForMember(x => x.Order, opt => opt.MapFrom(src => src.Order))
|
||||||
|
.ForMember(x => x.ImageUrl, opt => opt.MapFrom(src => src.ImageUrl))
|
||||||
|
.ForMember(x => x.VideoUrl, opt => opt.MapFrom(src => src.VideoUrl));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionMapping
|
||||||
|
|
||||||
|
CreateMap<Instruction, InstructionDTO>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title))
|
||||||
|
.ForMember(x => x.Description, opt => opt.MapFrom(src => src.Description))
|
||||||
|
.ForMember(x => x.CategoryId, opt => opt.MapFrom(src => src.CategoryId))
|
||||||
|
.ForMember(x => x.AssignDate, opt => opt.MapFrom(src => src.AssignDate))
|
||||||
|
.ForMember(x => x.AssignDate, opt => opt.MapFrom(src => src.DeadlineDate))
|
||||||
|
.ForMember(x => x.IsEnabled, opt => opt.MapFrom(src => src.IsEnabled))
|
||||||
|
.ForMember(x => x.Paragraphs, opt => opt.MapFrom(src => src.Paragraphs));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionCreateMapping
|
||||||
|
|
||||||
|
CreateMap<InstructionCreateDTO, Instruction>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title))
|
||||||
|
.ForMember(x => x.Description, opt => opt.MapFrom(src => src.Description))
|
||||||
|
.ForMember(x => x.Paragraphs, opt => opt.MapFrom(src => src.Paragraphs))
|
||||||
|
.ForMember(x => x.CategoryId, opt => opt.MapFrom(src => src.CategoryId))
|
||||||
|
.ForMember(x => x.AssignDate, opt => opt.MapFrom(src => src.AssignDate))
|
||||||
|
.ForMember(x => x.DeadlineDate, opt => opt.MapFrom(src => src.DeadlineDate))
|
||||||
|
.ForMember(x => x.IsEnabled, opt => opt.MapFrom(src => src.IsEnabled));
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionParagraphCreateMapping
|
||||||
|
|
||||||
|
CreateMap<InstructionParagraphCreateDTO, InstructionParagraph>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.Text, opt => opt.MapFrom(src => src.Text))
|
||||||
|
.ForMember(x => x.InstructionId, opt => opt.MapFrom(src => src.InstructionId))
|
||||||
|
.ForMember(x => x.Order, opt => opt.MapFrom(src => src.Order))
|
||||||
|
.ForMember(x => x.ImageUrl, opt => opt.MapFrom(src => src.ImageUrl))
|
||||||
|
.ForMember(x => x.VideoUrl, opt => opt.MapFrom(src => src.VideoUrl));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionCategoryMapping
|
||||||
|
|
||||||
|
CreateMap<InstructionCategory, InstructionCategoryDTO>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionCategoryCreateMapping
|
||||||
|
|
||||||
|
CreateMap<InstructionCategoryCreateDTO, InstructionCategory>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionTestMapping
|
||||||
|
|
||||||
|
CreateMap<InstructionTestCreateDTO, InstructionTest>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title))
|
||||||
|
.ForMember(x => x.Questions, opt => opt.MapFrom(src => src.Questions))
|
||||||
|
.ForMember(x => x.ScoreCalcMethod, opt => opt.MapFrom(src => src.ScoreCalcMethod))
|
||||||
|
.ForMember(x => x.MinScore, opt => opt.MapFrom(src => src.MinScore))
|
||||||
|
.ForMember(x => x.MaxAttempts, opt => opt.MapFrom(src => src.MaxAttempts));
|
||||||
|
|
||||||
|
CreateMap<InstructionTest, InstructionTestDTO>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Title))
|
||||||
|
.ForMember(x => x.ScoreCalcMethod, opt => opt.MapFrom(src => src.ScoreCalcMethod))
|
||||||
|
.ForMember(x => x.MinScore, opt => opt.MapFrom(src => src.MinScore))
|
||||||
|
.ForMember(x => x.MaxAttempts, opt => opt.MapFrom(src => src.MaxAttempts))
|
||||||
|
.ForMember(x => x.Questions, opt => opt.MapFrom(src => src.Questions));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionTestQuestionCreateMapping
|
||||||
|
|
||||||
|
CreateMap<InstructionTestQuestionCreateDTO, InstructionTestQuestion>()
|
||||||
|
.ForMember(x => x.Question, opt => opt.MapFrom(src => src.Question))
|
||||||
|
.ForMember(x => x.Answers, opt => opt.MapFrom(src => src.Answers))
|
||||||
|
.ForMember(x => x.Order, opt => opt.MapFrom(src => src.Order))
|
||||||
|
.ForMember(x => x.IsMultipleAnswer, opt => opt.MapFrom(src => src.IsMultipleAnswer))
|
||||||
|
.ForMember(x => x.CorrectAnswers, opt => opt.MapFrom(src => src.CorrectAnswers));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionTestQuestionMapping
|
||||||
|
|
||||||
|
CreateMap<InstructionTestQuestion, InstructionTestQuestionDTO>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.Question, opt => opt.MapFrom(src => src.Question))
|
||||||
|
.ForMember(x => x.Answers, opt => opt.MapFrom(src => src.Answers))
|
||||||
|
.ForMember(x => x.Order, opt => opt.MapFrom(src => src.Order))
|
||||||
|
.ForMember(x => x.IsMultipleAnswer, opt => opt.MapFrom(src => src.IsMultipleAnswer));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InstructionTestResultMapping
|
||||||
|
|
||||||
|
CreateMap<InstructionTestResult, InstructionTestResultDTO>()
|
||||||
|
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||||
|
.ForMember(x => x.UserId, opt => opt.MapFrom(src => src.UserId))
|
||||||
|
.ForMember(x => x.InstructionTestId, opt => opt.MapFrom(src => src.InstructionTestId))
|
||||||
|
.ForMember(x => x.Score, opt => opt.MapFrom(src => src.Score));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
7
Models/BasicResponses/BasicResponse.cs
Executable file
7
Models/BasicResponses/BasicResponse.cs
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GamificationService.Models.BasicResponses;
|
||||||
|
|
||||||
|
public class BasicResponse
|
||||||
|
{
|
||||||
|
public short Code { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
21
Models/DTO/AuthDTO.cs
Executable file
21
Models/DTO/AuthDTO.cs
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class AuthDTO
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
[StringLength(50, MinimumLength = 3, ErrorMessage = "Username must be between 3 and 50 characters")]
|
||||||
|
public string Username { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[EmailAddress(ErrorMessage = "Invalid email address")]
|
||||||
|
public string Email { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(100, MinimumLength = 8, ErrorMessage = "Password must be between 8 and 100 characters")]
|
||||||
|
public string Password { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public bool RememberMe { get; set; }
|
||||||
|
}
|
||||||
7
Models/DTO/DisableTwoFactorDTO.cs
Normal file
7
Models/DTO/DisableTwoFactorDTO.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class DisableTwoFactorDTO
|
||||||
|
{
|
||||||
|
public int TwoFactorProvider { get; set; }
|
||||||
|
public string Code { get; set; }
|
||||||
|
}
|
||||||
6
Models/DTO/EnableTwoFactorDTO.cs
Normal file
6
Models/DTO/EnableTwoFactorDTO.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class EnableTwoFactorDTO
|
||||||
|
{
|
||||||
|
public int TwoFactorProvider { get; set; }
|
||||||
|
}
|
||||||
11
Models/DTO/GetAllRightsResponse.cs
Normal file
11
Models/DTO/GetAllRightsResponse.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using GamificationService.Models.Database;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class GetAllRightsResponse
|
||||||
|
{
|
||||||
|
public List<Right> Rights { get; set; }
|
||||||
|
public int TotalCount { get; set; }
|
||||||
|
public int PageNumber { get; set; }
|
||||||
|
public int PageSize { get; set; }
|
||||||
|
}
|
||||||
11
Models/DTO/GetAllRolesResponse.cs
Normal file
11
Models/DTO/GetAllRolesResponse.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using GamificationService.Models.Database;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class GetAllRolesResponse
|
||||||
|
{
|
||||||
|
public List<ApplicationRole> Roles { get; set; }
|
||||||
|
public int TotalCount { get; set; }
|
||||||
|
public int PageNumber { get; set; }
|
||||||
|
public int PageSize { get; set; }
|
||||||
|
}
|
||||||
11
Models/DTO/GetTwoFactorDTO.cs
Normal file
11
Models/DTO/GetTwoFactorDTO.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class GetTwoFactorDTO
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public int TwoFactorProvider { get; set; }
|
||||||
|
[StringLength(50, MinimumLength = 3, ErrorMessage = "Username must be between 3 and 50 characters")]
|
||||||
|
public string? Username { get; set; } = null!;
|
||||||
|
}
|
||||||
14
Models/DTO/InstructionCategoryCreateDTO.cs
Normal file
14
Models/DTO/InstructionCategoryCreateDTO.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionCategoryCreateDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Title is required")]
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
10
Models/DTO/InstructionCategoryDTO.cs
Normal file
10
Models/DTO/InstructionCategoryDTO.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionCategoryDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
public string? Title { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
38
Models/DTO/InstructionCreateDTO.cs
Normal file
38
Models/DTO/InstructionCreateDTO.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionCreateDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Title is required")]
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Paragraphs are required")]
|
||||||
|
public List<InstructionParagraphCreateDTO> Paragraphs { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Category id is required")]
|
||||||
|
public long CategoryId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If AssignDate is set, the instruction will be automatically enabled
|
||||||
|
/// when the date is reached. If it's not set, the test will automatically
|
||||||
|
/// obtain the current date as its AssignDate as soon as the instruction
|
||||||
|
/// will be enabled by the IsEnabled parameter.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? AssignDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When deadline is reached, no more submissions are allowed for this instruction.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? DeadlineDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disabled instructions cannot be seen by users.
|
||||||
|
/// Tests for such instructions cannot be submitted either.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnabled { get; set; } = false;
|
||||||
|
}
|
||||||
21
Models/DTO/InstructionDTO.cs
Normal file
21
Models/DTO/InstructionDTO.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
public string? Title { get; set; }
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
public List<InstructionParagraphDTO> Paragraphs { get; set; } = new List<InstructionParagraphDTO>();
|
||||||
|
|
||||||
|
public long? CategoryId { get; set; }
|
||||||
|
|
||||||
|
public DateTime? AssignDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime? DeadlineDate { get; set; }
|
||||||
|
|
||||||
|
public bool IsEnabled { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
25
Models/DTO/InstructionParagraphCreateDTO.cs
Normal file
25
Models/DTO/InstructionParagraphCreateDTO.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionParagraphCreateDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
public long? InstructionId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order defines the order of the paragraphs inside the instruction.
|
||||||
|
/// There must not be two paragraphs with the same order.
|
||||||
|
/// </summary>
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Text is required")]
|
||||||
|
public string Text { get; set; } = null!;
|
||||||
|
|
||||||
|
public string? ImageUrl { get; set; }
|
||||||
|
|
||||||
|
public string? VideoUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
21
Models/DTO/InstructionParagraphDTO.cs
Normal file
21
Models/DTO/InstructionParagraphDTO.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionParagraphDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
public long? InstructionId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Order defines the order of the paragraphs inside the instruction.
|
||||||
|
/// There must not be two paragraphs with the same order.
|
||||||
|
/// </summary>
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
public string? Text { get; set; } = null!;
|
||||||
|
|
||||||
|
public string? ImageUrl { get; set; }
|
||||||
|
|
||||||
|
public string? VideoUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
20
Models/DTO/InstructionTestCreateDTO.cs
Normal file
20
Models/DTO/InstructionTestCreateDTO.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using GamificationService.Utils.Enums;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionTestCreateDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
public string? Title { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Questions must be specified")]
|
||||||
|
public ICollection<InstructionTestQuestionCreateDTO> Questions { get; set; } = null!;
|
||||||
|
|
||||||
|
public int MaxAttempts { get; set; } = 10;
|
||||||
|
|
||||||
|
[Range(0, 1.0, ErrorMessage = "Minimum score must be between 0.6 and 1.0")]
|
||||||
|
public double MinScore { get; set; } = 0.6;
|
||||||
|
|
||||||
|
public InstructionTestScoreCalcMethod ScoreCalcMethod { get; set; } = InstructionTestScoreCalcMethod.MaxGrade;
|
||||||
|
}
|
||||||
23
Models/DTO/InstructionTestDTO.cs
Normal file
23
Models/DTO/InstructionTestDTO.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using GamificationService.Utils.Enums;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionTestDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
// Reserved just in case
|
||||||
|
[StringLength(300, ErrorMessage = "Title cannot be longer than 300 characters")]
|
||||||
|
public string? Title { get; set; }
|
||||||
|
|
||||||
|
public int MaxAttempts { get; set; } = 10;
|
||||||
|
|
||||||
|
public double MinScore { get; set; } = 0.6;
|
||||||
|
|
||||||
|
public List<InstructionTestQuestionDTO> Questions { get; set; } = new List<InstructionTestQuestionDTO>();
|
||||||
|
|
||||||
|
public InstructionTestScoreCalcMethod ScoreCalcMethod { get; set; } = InstructionTestScoreCalcMethod.MaxGrade;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
26
Models/DTO/InstructionTestQuestionCreateDTO.cs
Normal file
26
Models/DTO/InstructionTestQuestionCreateDTO.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionTestQuestionCreateDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
public bool IsMultipleAnswer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Question will be displayed in the paragraph with the same order number.
|
||||||
|
/// There can be multiple questions attached to the same paragraph.
|
||||||
|
/// </summary>
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Must have question text")]
|
||||||
|
public string Question { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Must have answer options")]
|
||||||
|
public ICollection<string> Answers { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Must have correct answers")]
|
||||||
|
public ICollection<int> CorrectAnswers { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
25
Models/DTO/InstructionTestQuestionDTO.cs
Normal file
25
Models/DTO/InstructionTestQuestionDTO.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionTestQuestionDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
public bool IsMultipleAnswer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Question will be displayed in the paragraph with the same order number.
|
||||||
|
/// There can be multiple questions attached to the same paragraph.
|
||||||
|
/// </summary>
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Must have question text")]
|
||||||
|
public string Question { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Must have answer options")]
|
||||||
|
public ICollection<string> Answers { get; set; } = null!;
|
||||||
|
|
||||||
|
public ICollection<int>? CorrectAnswers { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
12
Models/DTO/InstructionTestResultDTO.cs
Normal file
12
Models/DTO/InstructionTestResultDTO.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionTestResultDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
public long? InstructionTestId { get; set; }
|
||||||
|
|
||||||
|
public long? UserId { get; set; }
|
||||||
|
|
||||||
|
public int Score { get; set; }
|
||||||
|
}
|
||||||
12
Models/DTO/InstructionTestSubmissionDTO.cs
Normal file
12
Models/DTO/InstructionTestSubmissionDTO.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class InstructionTestSubmissionDTO
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "InstructionTestId is required")]
|
||||||
|
public int InstructionTestId { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Answers must be provided")]
|
||||||
|
public List<List<int>> Answers { get; set; } = null!;
|
||||||
|
}
|
||||||
9
Models/DTO/LoginResultResponse.cs
Executable file
9
Models/DTO/LoginResultResponse.cs
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class LoginResultResponse
|
||||||
|
{
|
||||||
|
public bool? RequiresTwoFactorAuth { get; set; }
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public RefreshTokenDTO? Token { get; set; }
|
||||||
|
public int? TwoFactorProvider { get; set; }
|
||||||
|
}
|
||||||
7
Models/DTO/RefreshTokenDTO.cs
Executable file
7
Models/DTO/RefreshTokenDTO.cs
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class RefreshTokenDTO
|
||||||
|
{
|
||||||
|
public string AccessToken { get; set; } = null!;
|
||||||
|
public string RefreshToken { get; set; } = null!;
|
||||||
|
}
|
||||||
7
Models/DTO/RightDTO.cs
Normal file
7
Models/DTO/RightDTO.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class RightDTO
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
}
|
||||||
7
Models/DTO/RoleDTO.cs
Normal file
7
Models/DTO/RoleDTO.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class RoleDTO
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
}
|
||||||
16
Models/DTO/TwoFactorDTO.cs
Executable file
16
Models/DTO/TwoFactorDTO.cs
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class TwoFactorDTO
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public int TwoFactorProvider { get; set; }
|
||||||
|
[StringLength(50, MinimumLength = 3, ErrorMessage = "Username must be between 3 and 50 characters")]
|
||||||
|
public string? Username { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(6, MinimumLength = 6, ErrorMessage = "Code must be 6 characters long")]
|
||||||
|
public string Code { get; set; } = null!;
|
||||||
|
public bool RememberMe { get; set; }
|
||||||
|
}
|
||||||
33
Models/DTO/UserProfileCreateDTO.cs
Normal file
33
Models/DTO/UserProfileCreateDTO.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using GamificationService.Utils.Enums;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class UserProfileCreateDTO
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "Name is required")]
|
||||||
|
[StringLength(100, ErrorMessage = "Name must be less than 100 characters")]
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Surname is required")]
|
||||||
|
[StringLength(100, ErrorMessage = "Surname must be less than 100 characters")]
|
||||||
|
public string Surname { get; set; } = null!;
|
||||||
|
|
||||||
|
[StringLength(50, ErrorMessage = "Patronymic must be less than 50 characters")]
|
||||||
|
public string? Patronymic { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Birthdate is required")]
|
||||||
|
public DateTime Birthdate { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Gender is required")]
|
||||||
|
public Gender Gender { get; set; }
|
||||||
|
|
||||||
|
[EmailAddress(ErrorMessage = "Invalid email")]
|
||||||
|
public string? ContactEmail { get; set; }
|
||||||
|
|
||||||
|
[Phone(ErrorMessage = "Invalid contact phone number")]
|
||||||
|
public string? ContactPhone { get; set; }
|
||||||
|
|
||||||
|
[Url(ErrorMessage = "Invalid avatar url")]
|
||||||
|
public string? ProfilePicture { get; set; }
|
||||||
|
}
|
||||||
37
Models/DTO/UserProfileDTO.cs
Executable file
37
Models/DTO/UserProfileDTO.cs
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using GamificationService.Utils.Enums;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
public class UserProfileDTO
|
||||||
|
{
|
||||||
|
public long? Id { get; set; }
|
||||||
|
|
||||||
|
public long? UserId { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Name is required")]
|
||||||
|
[StringLength(100, ErrorMessage = "Name must be less than 100 characters")]
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Surname is required")]
|
||||||
|
[StringLength(100, ErrorMessage = "Surname must be less than 100 characters")]
|
||||||
|
public string Surname { get; set; } = null!;
|
||||||
|
|
||||||
|
[StringLength(50, ErrorMessage = "Patronymic must be less than 50 characters")]
|
||||||
|
public string? Patronymic { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Birthdate is required")]
|
||||||
|
public DateTime Birthdate { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Gender is required")]
|
||||||
|
public Gender Gender { get; set; }
|
||||||
|
|
||||||
|
[EmailAddress(ErrorMessage = "Invalid email")]
|
||||||
|
public string? ContactEmail { get; set; }
|
||||||
|
|
||||||
|
[Phone(ErrorMessage = "Invalid contact phone number")]
|
||||||
|
public string? ContactPhone { get; set; }
|
||||||
|
|
||||||
|
[Url(ErrorMessage = "Invalid avatar url")]
|
||||||
|
public string? ProfilePicture { get; set; }
|
||||||
|
}
|
||||||
15
Models/Database/ApplicationRole.cs
Executable file
15
Models/Database/ApplicationRole.cs
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
|
||||||
|
public class ApplicationRole : IdentityRole<long>
|
||||||
|
{
|
||||||
|
public ApplicationRole() : base() { }
|
||||||
|
public ApplicationRole(string roleName) : base(roleName) { }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
public List<UserRole> UserRoles { get; set; } = new List<UserRole>();
|
||||||
|
public List<RoleRight> RoleRights { get; set; } = new List<RoleRight>();
|
||||||
|
}
|
||||||
19
Models/Database/ApplicationUser.cs
Executable file
19
Models/Database/ApplicationUser.cs
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using GamificationService.Utils;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class ApplicationUser : IdentityUser<long>
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "Username is required")]
|
||||||
|
[StringLength(50, ErrorMessage = "Username must be less than 50 characters")]
|
||||||
|
public string Username { get; set; } = null!;
|
||||||
|
public bool TwoFactorEnabled { get; set; }
|
||||||
|
public string? TwoFactorSecret { get; set; }
|
||||||
|
public bool EmailConfirmed { get; set; }
|
||||||
|
public List<TwoFactorProvider> TwoFactorProviders { get; set; } = new List<TwoFactorProvider>();
|
||||||
|
public List<RefreshToken> RefreshTokens { get; set; } = new List<RefreshToken>();
|
||||||
|
|
||||||
|
public List<UserRole> UserRoles { get; set; } = new List<UserRole>();
|
||||||
|
}
|
||||||
9
Models/Database/AuditableEntity.cs
Executable file
9
Models/Database/AuditableEntity.cs
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class AuditableEntity
|
||||||
|
{
|
||||||
|
public DateTimeOffset CreatedOn { get; set; }
|
||||||
|
public string CreatedBy { get; set; } = string.Empty;
|
||||||
|
public DateTimeOffset UpdatedOn { get; set; }
|
||||||
|
public string UpdatedBy { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
29
Models/Database/Instruction.cs
Normal file
29
Models/Database/Instruction.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class Instruction
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Title is required")]
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
public long CategoryId { get; set; }
|
||||||
|
[Required(ErrorMessage = "Category must be specified")]
|
||||||
|
public InstructionCategory Category { get; set; } = null!;
|
||||||
|
|
||||||
|
public virtual ICollection<InstructionParagraph> Paragraphs { get; set; }
|
||||||
|
|
||||||
|
public long? InstructionTestId { get; set; }
|
||||||
|
public InstructionTest? InstructionTest { get; set; }
|
||||||
|
|
||||||
|
public DateTime? AssignDate { get; set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
public DateTime? DeadlineDate { get; set; }
|
||||||
|
|
||||||
|
public bool IsEnabled { get; set; }
|
||||||
|
}
|
||||||
13
Models/Database/InstructionCategory.cs
Normal file
13
Models/Database/InstructionCategory.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class InstructionCategory
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Title is required")]
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
}
|
||||||
|
|
||||||
21
Models/Database/InstructionParagraph.cs
Normal file
21
Models/Database/InstructionParagraph.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class InstructionParagraph
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
public long InstructionId { get; set; }
|
||||||
|
[Required(ErrorMessage = "Must be linked to instruction")]
|
||||||
|
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Paragraph text is required")]
|
||||||
|
public string Text { get; set; } = null!;
|
||||||
|
|
||||||
|
public string? ImageUrl { get; set; }
|
||||||
|
|
||||||
|
public string? VideoUrl { get; set; }
|
||||||
|
}
|
||||||
23
Models/Database/InstructionTest.cs
Normal file
23
Models/Database/InstructionTest.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using GamificationService.Utils.Enums;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class InstructionTest
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
// Reserved just in case
|
||||||
|
[MaxLength(300, ErrorMessage = "Title cannot be longer than 300 characters")]
|
||||||
|
public string? Title { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<InstructionTestQuestion> Questions { get; set; }
|
||||||
|
|
||||||
|
public int MaxAttempts { get; set; } = 10;
|
||||||
|
|
||||||
|
public double MinScore { get; set; } = 0.6;
|
||||||
|
|
||||||
|
public InstructionTestScoreCalcMethod ScoreCalcMethod { get; set; } = InstructionTestScoreCalcMethod.MaxGrade;
|
||||||
|
|
||||||
|
}
|
||||||
26
Models/Database/InstructionTestQuestion.cs
Normal file
26
Models/Database/InstructionTestQuestion.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class InstructionTestQuestion
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Must be tied to an instruction test")]
|
||||||
|
public InstructionTest InstructionTest { get; set; } = null!;
|
||||||
|
public long InstructionTestId { get; set; }
|
||||||
|
|
||||||
|
public int Order { get; set; }
|
||||||
|
|
||||||
|
public bool IsMultipleAnswer { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Must have question text")]
|
||||||
|
public string Question { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Must have answer options")]
|
||||||
|
public ICollection<string> Answers { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Must have correct answer ids")]
|
||||||
|
public ICollection<int> CorrectAnswers { get; set; } = null!;
|
||||||
|
}
|
||||||
20
Models/Database/InstructionTestResult.cs
Normal file
20
Models/Database/InstructionTestResult.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class InstructionTestResult
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
public long InstructionTestId { get; set; }
|
||||||
|
[Required(ErrorMessage = "Instruction test is required")]
|
||||||
|
public virtual InstructionTest InstructionTest { get; set; } = null!;
|
||||||
|
|
||||||
|
public long UserId { get; set; }
|
||||||
|
[Required(ErrorMessage = "User is required")]
|
||||||
|
public ApplicationUser User { get; set; } = null!;
|
||||||
|
|
||||||
|
[Range(0, 100, ErrorMessage = "Score must be a number from 0 to 100")]
|
||||||
|
public int Score { get; set; }
|
||||||
|
}
|
||||||
25
Models/Database/RefreshToken.cs
Executable file
25
Models/Database/RefreshToken.cs
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class RefreshToken
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
public long UserId { get; set; }
|
||||||
|
public ApplicationUser User { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string Token { get; set; } = null!;
|
||||||
|
|
||||||
|
public DateTime Expires { get; set; }
|
||||||
|
public DateTime Created { get; set; }
|
||||||
|
public bool IsExpired => DateTime.UtcNow >= Expires;
|
||||||
|
|
||||||
|
public bool IsRevoked { get; set; }
|
||||||
|
public string? RevokedByIp { get; set; }
|
||||||
|
public DateTime? RevokedOn { get; set; }
|
||||||
|
|
||||||
|
public bool IsActive => !IsRevoked && !IsExpired;
|
||||||
|
}
|
||||||
18
Models/Database/Right.cs
Executable file
18
Models/Database/Right.cs
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class Right
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
[StringLength(50)]
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
[StringLength(100)]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
public List<RoleRight> RoleRights { get; set; } = new List<RoleRight>();
|
||||||
|
}
|
||||||
10
Models/Database/RoleRight.cs
Executable file
10
Models/Database/RoleRight.cs
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class RoleRight
|
||||||
|
{
|
||||||
|
public long RoleId { get; set; }
|
||||||
|
public ApplicationRole Role { get; set; } = null!;
|
||||||
|
|
||||||
|
public long RightId { get; set; }
|
||||||
|
public Right Right { get; set; } = null!;
|
||||||
|
}
|
||||||
40
Models/Database/UserProfile.cs
Executable file
40
Models/Database/UserProfile.cs
Executable file
@@ -0,0 +1,40 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using GamificationService.Utils.Enums;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class UserProfile
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "User is required")]
|
||||||
|
public long UserId { get; set; }
|
||||||
|
public ApplicationUser? User { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Name is required")]
|
||||||
|
[StringLength(100, ErrorMessage = "Name must be less than 100 characters")]
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Surname is required")]
|
||||||
|
[StringLength(100, ErrorMessage = "Surname must be less than 100 characters")]
|
||||||
|
public string Surname { get; set; } = null!;
|
||||||
|
|
||||||
|
[StringLength(50, ErrorMessage = "Patronymic must be less than 50 characters")]
|
||||||
|
public string? Patronymic { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Gender is required")]
|
||||||
|
public Gender Gender { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Birthdate is required")]
|
||||||
|
public DateTime Birthdate { get; set; }
|
||||||
|
|
||||||
|
[EmailAddress(ErrorMessage = "Invalid email")]
|
||||||
|
public string? ContactEmail { get; set; }
|
||||||
|
|
||||||
|
[Phone(ErrorMessage = "Invalid contact phone number")]
|
||||||
|
public string? ContactPhone { get; set; }
|
||||||
|
|
||||||
|
[Url(ErrorMessage = "Invalid avatar url")]
|
||||||
|
public string? ProfilePicture { get; set; }
|
||||||
|
}
|
||||||
10
Models/Database/UserRole.cs
Executable file
10
Models/Database/UserRole.cs
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace GamificationService.Models.Database;
|
||||||
|
|
||||||
|
public class UserRole
|
||||||
|
{
|
||||||
|
public long UserId { get; set; }
|
||||||
|
public ApplicationUser User { get; set; } = null!;
|
||||||
|
|
||||||
|
public long RoleId { get; set; }
|
||||||
|
public ApplicationRole Role { get; set; } = null!;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.Messages.InstructionTests;
|
||||||
|
|
||||||
|
public class CreateInstructionTestRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.Messages.InstructionTests;
|
||||||
|
|
||||||
|
public class CreateInstructionTestResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.Messages.InstructionTests;
|
||||||
|
|
||||||
|
public class UpdateInstructionTestRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.Messages.InstructionTests;
|
||||||
|
|
||||||
|
public class UpdateInstructionTestResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
37
Models/Messages/Instructions/CreateInstructionRequest.cs
Normal file
37
Models/Messages/Instructions/CreateInstructionRequest.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Messages.Instructions;
|
||||||
|
|
||||||
|
public class CreateInstructionRequest
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "Title is required")]
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Paragraphs are required")]
|
||||||
|
public List<InstructionParagraphCreateDTO> Paragraphs { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Category id is required")]
|
||||||
|
public long CategoryId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If AssignDate is set, the instruction will be automatically enabled
|
||||||
|
/// when the date is reached. If it's not set, the test will automatically
|
||||||
|
/// obtain the current date as its AssignDate as soon as the instruction
|
||||||
|
/// will be enabled by the IsEnabled parameter.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? AssignDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When deadline is reached, no more submissions are allowed for this instruction.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? DeadlineDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disabled instructions cannot be seen by users.
|
||||||
|
/// Tests for such instructions cannot be submitted either.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnabled { get; set; } = false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.Messages.Instructions;
|
||||||
|
|
||||||
|
public class CreateInstructionResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
40
Models/Messages/Instructions/UpdateInstructionRequest.cs
Normal file
40
Models/Messages/Instructions/UpdateInstructionRequest.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using GamificationService.Models.DTO;
|
||||||
|
|
||||||
|
namespace GamificationService.Models.Messages.Instructions;
|
||||||
|
|
||||||
|
public class UpdateInstructionRequest
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Title is required")]
|
||||||
|
public string Title { get; set; } = null!;
|
||||||
|
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Paragraphs are required")]
|
||||||
|
public List<InstructionParagraphCreateDTO> Paragraphs { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "Category id is required")]
|
||||||
|
public long CategoryId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If AssignDate is set, the instruction will be automatically enabled
|
||||||
|
/// when the date is reached. If it's not set, the test will automatically
|
||||||
|
/// obtain the current date as its AssignDate as soon as the instruction
|
||||||
|
/// will be enabled by the IsEnabled parameter.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? AssignDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When deadline is reached, no more submissions are allowed for this instruction.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? DeadlineDate { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disabled instructions cannot be seen by users.
|
||||||
|
/// Tests for such instructions cannot be submitted either.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnabled { get; set; } = false;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.Messages.Instructions;
|
||||||
|
|
||||||
|
public class UpdateInstructionResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
6
Models/Messages/UserProfiles/CreateUserProfileRequest.cs
Normal file
6
Models/Messages/UserProfiles/CreateUserProfileRequest.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.Messages.UserProfiles;
|
||||||
|
|
||||||
|
public class CreateUserProfileRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GamificationService.Models.Messages.UserProfiles;
|
||||||
|
|
||||||
|
public class CreateUserProfileResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
6
Models/Messages/UserProfiles/UpdateUserProfileRequest.cs
Normal file
6
Models/Messages/UserProfiles/UpdateUserProfileRequest.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.Messages.UserProfiles;
|
||||||
|
|
||||||
|
public class UpdateUserProfileRequest
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace GamificationService.Models.Messages.UserProfiles;
|
||||||
|
|
||||||
|
public class UpdateUserProfileResponse
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
7
Models/UserSession.cs
Executable file
7
Models/UserSession.cs
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GamificationService.Models;
|
||||||
|
|
||||||
|
public class UserSession
|
||||||
|
{
|
||||||
|
public string? Login { get; set; }
|
||||||
|
public bool IsAuthenticated { get; set; }
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user