Initial Commit
This commit is contained in:
commit
16c9aae729
30
.dockerignore
Normal file
30
.dockerignore
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
**/.classpath
|
||||||
|
**/.dockerignore
|
||||||
|
**/.env
|
||||||
|
**/.git
|
||||||
|
**/.gitignore
|
||||||
|
**/.project
|
||||||
|
**/.settings
|
||||||
|
**/.toolstarget
|
||||||
|
**/.vs
|
||||||
|
**/.vscode
|
||||||
|
**/*.*proj.user
|
||||||
|
**/*.dbmdl
|
||||||
|
**/*.jfm
|
||||||
|
**/azds.yaml
|
||||||
|
**/bin
|
||||||
|
**/charts
|
||||||
|
**/docker-compose*
|
||||||
|
**/Dockerfile*
|
||||||
|
**/node_modules
|
||||||
|
**/npm-debug.log
|
||||||
|
**/obj
|
||||||
|
**/secrets.dev.yaml
|
||||||
|
**/values.dev.yaml
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
|
!**/.gitignore
|
||||||
|
!.git/HEAD
|
||||||
|
!.git/config
|
||||||
|
!.git/packed-refs
|
||||||
|
!.git/refs/heads/**
|
||||||
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
###############################################################################
|
||||||
|
# Set default behavior to automatically normalize line endings.
|
||||||
|
###############################################################################
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set default behavior for command prompt diff.
|
||||||
|
#
|
||||||
|
# This is need for earlier builds of msysgit that does not have it on by
|
||||||
|
# default for csharp files.
|
||||||
|
# Note: This is only used by command line
|
||||||
|
###############################################################################
|
||||||
|
#*.cs diff=csharp
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Set the merge driver for project and solution files
|
||||||
|
#
|
||||||
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
|
# these files as binary and thus will always conflict and require user
|
||||||
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
|
###############################################################################
|
||||||
|
#*.sln merge=binary
|
||||||
|
#*.csproj merge=binary
|
||||||
|
#*.vbproj merge=binary
|
||||||
|
#*.vcxproj merge=binary
|
||||||
|
#*.vcproj merge=binary
|
||||||
|
#*.dbproj merge=binary
|
||||||
|
#*.fsproj merge=binary
|
||||||
|
#*.lsproj merge=binary
|
||||||
|
#*.wixproj merge=binary
|
||||||
|
#*.modelproj merge=binary
|
||||||
|
#*.sqlproj merge=binary
|
||||||
|
#*.wwaproj merge=binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# behavior for image files
|
||||||
|
#
|
||||||
|
# image files are treated as binary by default.
|
||||||
|
###############################################################################
|
||||||
|
#*.jpg binary
|
||||||
|
#*.png binary
|
||||||
|
#*.gif binary
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# diff behavior for common document formats
|
||||||
|
#
|
||||||
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
|
# entries below.
|
||||||
|
###############################################################################
|
||||||
|
#*.doc diff=astextplain
|
||||||
|
#*.DOC diff=astextplain
|
||||||
|
#*.docx diff=astextplain
|
||||||
|
#*.DOCX diff=astextplain
|
||||||
|
#*.dot diff=astextplain
|
||||||
|
#*.DOT diff=astextplain
|
||||||
|
#*.pdf diff=astextplain
|
||||||
|
#*.PDF diff=astextplain
|
||||||
|
#*.rtf diff=astextplain
|
||||||
|
#*.RTF diff=astextplain
|
||||||
366
.gitignore
vendored
Normal file
366
.gitignore
vendored
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]ut/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.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
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# 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
|
||||||
|
*.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
|
||||||
|
# Note: 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
|
||||||
|
# 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
|
||||||
|
*.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
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# 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
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
#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
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# 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/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# 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/
|
||||||
|
|
||||||
|
# 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
|
||||||
|
/qtc-net-server/qtcdev.db
|
||||||
|
/qtc-net-server/qtcdev.db-shm
|
||||||
|
/qtc-net-server/qtcdev.db-wal
|
||||||
19
docker-compose.dcproj
Normal file
19
docker-compose.dcproj
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectVersion>2.1</ProjectVersion>
|
||||||
|
<DockerTargetOS>Linux</DockerTargetOS>
|
||||||
|
<DockerPublishLocally>False</DockerPublishLocally>
|
||||||
|
<ProjectGuid>b1b3d2c9-92e6-4711-842e-c940a40a9a2e</ProjectGuid>
|
||||||
|
<DockerLaunchAction>LaunchBrowser</DockerLaunchAction>
|
||||||
|
<DockerServiceUrl>{Scheme}://localhost:{ServicePort}/swagger</DockerServiceUrl>
|
||||||
|
<DockerServiceName>qtc-net-server</DockerServiceName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="docker-compose.override.yml">
|
||||||
|
<DependentUpon>docker-compose.yml</DependentUpon>
|
||||||
|
</None>
|
||||||
|
<None Include="docker-compose.yml" />
|
||||||
|
<None Include=".dockerignore" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
9
docker-compose.override.yml
Normal file
9
docker-compose.override.yml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
version: '3.4'
|
||||||
|
|
||||||
|
services:
|
||||||
|
qtc-net-server:
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Development
|
||||||
|
- ASPNETCORE_HTTP_PORTS=8080
|
||||||
|
ports:
|
||||||
|
- "8080"
|
||||||
8
docker-compose.yml
Normal file
8
docker-compose.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
version: '3.4'
|
||||||
|
|
||||||
|
services:
|
||||||
|
qtc-net-server:
|
||||||
|
image: ${DOCKER_REGISTRY-}qtcnetserver
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: qtc-net-server/Dockerfile
|
||||||
11
launchSettings.json
Normal file
11
launchSettings.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"Docker Compose": {
|
||||||
|
"commandName": "DockerCompose",
|
||||||
|
"commandVersion": "1.0",
|
||||||
|
"serviceActions": {
|
||||||
|
"qtc-net-server": "StartDebugging"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
qtc-net-server.sln
Normal file
31
qtc-net-server.sln
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.5.33414.496
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "qtc-net-server", "qtc-net-server\qtc-net-server.csproj", "{AE9BEB1A-340C-4EE4-90D1-0B16456DDE6A}"
|
||||||
|
EndProject
|
||||||
|
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{B1B3D2C9-92E6-4711-842E-C940A40A9A2E}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{AE9BEB1A-340C-4EE4-90D1-0B16456DDE6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AE9BEB1A-340C-4EE4-90D1-0B16456DDE6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{AE9BEB1A-340C-4EE4-90D1-0B16456DDE6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{AE9BEB1A-340C-4EE4-90D1-0B16456DDE6A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B1B3D2C9-92E6-4711-842E-C940A40A9A2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B1B3D2C9-92E6-4711-842E-C940A40A9A2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B1B3D2C9-92E6-4711-842E-C940A40A9A2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B1B3D2C9-92E6-4711-842E-C940A40A9A2E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {1B6C7F89-981F-4871-860E-D961CB6A204A}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
96
qtc-net-server/Controllers/AuthController.cs
Normal file
96
qtc-net-server/Controllers/AuthController.cs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using qtc_api.Dtos.User;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace qtc_api.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/auth")]
|
||||||
|
[ApiController]
|
||||||
|
public class AuthController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
private readonly ITokenService _tokenService;
|
||||||
|
|
||||||
|
private readonly ServerConfig serverConfig;
|
||||||
|
private readonly DataContext dataContext;
|
||||||
|
|
||||||
|
public AuthController(IUserService userService, ITokenService tokenService, DataContext dataContext)
|
||||||
|
{
|
||||||
|
_userService = userService;
|
||||||
|
_tokenService = tokenService;
|
||||||
|
|
||||||
|
serverConfig = JsonSerializer.Deserialize<ServerConfig>(JsonDocument.Parse(System.IO.File.ReadAllText("./ServerConfig.json")));
|
||||||
|
this.dataContext = dataContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("register")]
|
||||||
|
public async Task<ActionResult<ServiceResponse<User>>> Register(UserDto userDto)
|
||||||
|
{
|
||||||
|
if(userDto != null)
|
||||||
|
{
|
||||||
|
var response = await _userService.AddUser(userDto);
|
||||||
|
if(response.Success != false)
|
||||||
|
{
|
||||||
|
return Ok(response);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return StatusCode(500, response.Message);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return BadRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("login")]
|
||||||
|
public async Task<ActionResult<ServiceResponse<string>>> Login(UserLoginDto request)
|
||||||
|
{
|
||||||
|
var dbUser = await _userService.GetUserByEmail(request.Email);
|
||||||
|
|
||||||
|
if (dbUser.Data == null)
|
||||||
|
{
|
||||||
|
return Ok(new ServiceResponse<string>
|
||||||
|
{
|
||||||
|
Message = "User not found.",
|
||||||
|
Success = false
|
||||||
|
});
|
||||||
|
} else if(!BCrypt.Net.BCrypt.Verify(request.Password, dbUser.Data.PasswordHash))
|
||||||
|
{
|
||||||
|
return Ok(new ServiceResponse<string>
|
||||||
|
{
|
||||||
|
Message = "Incorrect password.",
|
||||||
|
Success = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbUser.Data.Id == serverConfig.AdminUserId && dbUser.Data.Role != "Admin")
|
||||||
|
{
|
||||||
|
dbUser.Data.Role = "Admin";
|
||||||
|
dataContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dbUser.Data.Status == 1)
|
||||||
|
{
|
||||||
|
return Ok(new ServiceResponse<string>
|
||||||
|
{
|
||||||
|
Message = "User is already signed in.",
|
||||||
|
Success = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = await _tokenService.GenerateAccessTokenAndRefreshToken(dbUser.Data, true, request.RememberMe);
|
||||||
|
|
||||||
|
return Ok(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("refresh")]
|
||||||
|
public async Task<ActionResult<ServiceResponse<string>>> RefreshLogin(string token)
|
||||||
|
{
|
||||||
|
var response = await _tokenService.ValidateRefreshToken(token);
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
83
qtc-net-server/Controllers/ContactController.cs
Normal file
83
qtc-net-server/Controllers/ContactController.cs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using qtc_api.Models;
|
||||||
|
using qtc_api.Services.ContactService;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace qtc_api.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/contacts")]
|
||||||
|
[ApiController]
|
||||||
|
public class ContactController : ControllerBase
|
||||||
|
{
|
||||||
|
private IContactService _contactService;
|
||||||
|
|
||||||
|
public ContactController(IContactService contactService)
|
||||||
|
{
|
||||||
|
_contactService = contactService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("add-contact")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<Contact>>> AddContact(string userId)
|
||||||
|
{
|
||||||
|
var identity = HttpContext.User.Identity as ClaimsIdentity;
|
||||||
|
|
||||||
|
if (identity != null)
|
||||||
|
{
|
||||||
|
IEnumerable<Claim> claims = identity.Claims;
|
||||||
|
var ownerId = claims.First().Value;
|
||||||
|
|
||||||
|
var result = await _contactService.CreateContact(ownerId, userId);
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("approve-contact")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<bool>>> ApproveContact(string userId)
|
||||||
|
{
|
||||||
|
var identity = HttpContext.User.Identity as ClaimsIdentity;
|
||||||
|
|
||||||
|
if (identity != null)
|
||||||
|
{
|
||||||
|
IEnumerable<Claim> claims = identity.Claims;
|
||||||
|
var ownerId = claims.First().Value;
|
||||||
|
|
||||||
|
var result = await _contactService.UpdateContactStatus(ownerId, userId, Contact.ContactStatus.Accepted, Contact.ContactStatus.Accepted);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("remove-contact")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<Contact>>> RemoveContact(string userId)
|
||||||
|
{
|
||||||
|
var identity = HttpContext.User.Identity as ClaimsIdentity;
|
||||||
|
|
||||||
|
if (identity != null)
|
||||||
|
{
|
||||||
|
IEnumerable<Claim> claims = identity.Claims;
|
||||||
|
var ownerId = claims.First().Value;
|
||||||
|
|
||||||
|
var response = await _contactService.DeleteContact(ownerId, userId);
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("get-user-contacts")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<List<Contact>>>> GetUserContacts(User user)
|
||||||
|
{
|
||||||
|
var result = await _contactService.GetUserContacts(user);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
qtc-net-server/Controllers/GeneralController.cs
Normal file
20
qtc-net-server/Controllers/GeneralController.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace qtc_api.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/general")]
|
||||||
|
[ApiController]
|
||||||
|
public class GeneralController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly ILogger<GeneralController> logger;
|
||||||
|
public GeneralController(ILogger<GeneralController> logger) => this.logger = logger;
|
||||||
|
|
||||||
|
[HttpGet("ping")]
|
||||||
|
public ActionResult PingAsync()
|
||||||
|
{
|
||||||
|
logger.LogInformation($"Ping Received From Client");
|
||||||
|
return Ok("Pong!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
qtc-net-server/Controllers/RoomsController.cs
Normal file
46
qtc-net-server/Controllers/RoomsController.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using qtc_api.Services.RoomService;
|
||||||
|
|
||||||
|
namespace qtc_api.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/rooms")]
|
||||||
|
[ApiController]
|
||||||
|
public class RoomsController : ControllerBase
|
||||||
|
{
|
||||||
|
public IRoomService _roomService;
|
||||||
|
public IHubContext<ChatHub> _hubContext;
|
||||||
|
|
||||||
|
public RoomsController(IRoomService roomService, IHubContext<ChatHub> hubContext)
|
||||||
|
{
|
||||||
|
_roomService = roomService;
|
||||||
|
_hubContext = hubContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("create-room")]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
public async Task<ActionResult<ServiceResponse<Room>>> CreateRoom(string userId, RoomDto request)
|
||||||
|
{
|
||||||
|
var response = await _roomService.AddRoom(userId, request);
|
||||||
|
await _hubContext.Clients.All.SendAsync("cf", "rul");
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("delete-room")]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
public async Task<ActionResult<ServiceResponse<Room>>> DeleteRoom(string roomId)
|
||||||
|
{
|
||||||
|
var response = await _roomService.DeleteRoom(roomId);
|
||||||
|
await _hubContext.Clients.All.SendAsync("cf", "rul");
|
||||||
|
return Ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("get-all-rooms")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<List<Room>>>> GetAllRooms()
|
||||||
|
{
|
||||||
|
var rooms = await _roomService.GetAllRooms();
|
||||||
|
return Ok(rooms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
156
qtc-net-server/Controllers/UsersController.cs
Normal file
156
qtc-net-server/Controllers/UsersController.cs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Identity;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using qtc_api.Dtos.User;
|
||||||
|
using System.Net.Mime;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace qtc_api.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/users")]
|
||||||
|
[ApiController]
|
||||||
|
public class UsersController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IUserService _userService;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
|
public UsersController(IUserService userService, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
_userService = userService;
|
||||||
|
_configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("all")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<List<UserInformationDto>>>> GetAllUsers()
|
||||||
|
{
|
||||||
|
var users = await _userService.GetAllUsers();
|
||||||
|
return Ok(users);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("user-info")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<UserInformationDto>>> GetUserInformation(string id)
|
||||||
|
{
|
||||||
|
var user = await _userService.GetUserInformationById(id);
|
||||||
|
return Ok(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("user-authorized")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<User>>> UserFromAuthorizeHead()
|
||||||
|
{
|
||||||
|
var identity = HttpContext.User.Identity as ClaimsIdentity;
|
||||||
|
|
||||||
|
if(identity != null)
|
||||||
|
{
|
||||||
|
IEnumerable<Claim> claims = identity.Claims;
|
||||||
|
var id = claims.First().Value;
|
||||||
|
|
||||||
|
if(id != null)
|
||||||
|
{
|
||||||
|
var user = await _userService.GetUserById(id);
|
||||||
|
return Ok(user);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return BadRequest("Token did not contain an ID.");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return BadRequest("Header not found.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("users-online")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<List<UserInformationDto>>>> GetAllOnlineUsers()
|
||||||
|
{
|
||||||
|
var users = await _userService.GetAllOnlineUsers();
|
||||||
|
return Ok(users);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPut("update")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<UserInformationDto>>> UpdateUserInformation(UserUpdateInformationDto user)
|
||||||
|
{
|
||||||
|
var identity = HttpContext.User.Identity as ClaimsIdentity;
|
||||||
|
|
||||||
|
if(identity != null)
|
||||||
|
{
|
||||||
|
IEnumerable<Claim> claims = identity.Claims;
|
||||||
|
var id = claims.First().Value;
|
||||||
|
|
||||||
|
if(id != null && id == user.Id)
|
||||||
|
{
|
||||||
|
var updatedUser = await _userService.UpdateUserInfo(user);
|
||||||
|
return Ok(updatedUser);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return Unauthorized("You are not authorized to edit that user.");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return BadRequest("Session Expired.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("upload-profile-pic")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult<ServiceResponse<string>>> UploadOrUpdateProfilePic(string userId, IFormFile file)
|
||||||
|
{
|
||||||
|
var identity = HttpContext.User.Identity as ClaimsIdentity;
|
||||||
|
|
||||||
|
if(identity != null)
|
||||||
|
{
|
||||||
|
IEnumerable<Claim> claims = identity.Claims;
|
||||||
|
var id = claims.First().Value;
|
||||||
|
|
||||||
|
if(id != null && id == userId)
|
||||||
|
{
|
||||||
|
if (file.Length > 3000000)
|
||||||
|
{
|
||||||
|
return BadRequest("File Is Above Limit.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = await _userService.UpdateUserPic(userId, file);
|
||||||
|
|
||||||
|
return Ok(response);
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return BadRequest("You are not permitted to edit that user.");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return BadRequest("No Identity.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("profile-pic/{userId}")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<ActionResult> GetUserProfilePicture(string userId)
|
||||||
|
{
|
||||||
|
var result = await _userService.GetUserPic(userId);
|
||||||
|
|
||||||
|
if (result != null && result.Success != false)
|
||||||
|
{
|
||||||
|
return result.Data!;
|
||||||
|
} else if (result!.Message == "User Does Not Have A Profile Picture." || result!.Message == "User Content Folder Does Not Exist Yet.")
|
||||||
|
{
|
||||||
|
return BadRequest("User has no profile picture.");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
return BadRequest("Failed To Get Profile Picture.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpDelete("delete-user")]
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
public async Task<ActionResult<ServiceResponse<User>>> DeleteUserById(string id)
|
||||||
|
{
|
||||||
|
var result = await _userService.DeleteUser(id);
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
qtc-net-server/Data/DataContext.cs
Normal file
42
qtc-net-server/Data/DataContext.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
namespace qtc_api.Data
|
||||||
|
{
|
||||||
|
public class DataContext : DbContext
|
||||||
|
{
|
||||||
|
public DataContext(DbContextOptions<DataContext> options) : base(options)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbSet<User> Users { get; set; }
|
||||||
|
public DbSet<Room> Rooms { get; set; }
|
||||||
|
public DbSet<RefreshToken> ValidRefreshTokens { get; set; }
|
||||||
|
public DbSet<Contact> Contacts { get; set; }
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder builder)
|
||||||
|
{
|
||||||
|
// Users
|
||||||
|
|
||||||
|
builder.Entity<User>().HasMany(e => e.ContactsList);
|
||||||
|
builder.Entity<User>().HasMany(e => e.ContactsMade);
|
||||||
|
|
||||||
|
// Rooms (no relations)
|
||||||
|
|
||||||
|
builder.Entity<Room>();
|
||||||
|
|
||||||
|
// Refresh Tokens
|
||||||
|
|
||||||
|
builder.Entity<RefreshToken>().HasOne(e => e.User)
|
||||||
|
.WithMany(e => e.RefreshTokens)
|
||||||
|
.HasForeignKey(e => e.UserID);
|
||||||
|
|
||||||
|
// Contacts
|
||||||
|
|
||||||
|
builder.Entity<Contact>().HasOne(e => e.Owner)
|
||||||
|
.WithMany(e => e.ContactsMade)
|
||||||
|
.HasForeignKey(e => e.OwnerId);
|
||||||
|
|
||||||
|
builder.Entity<Contact>().HasOne(e => e.User)
|
||||||
|
.WithMany(e => e.ContactsList)
|
||||||
|
.HasForeignKey(e => e.UserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
qtc-net-server/Dockerfile
Normal file
21
qtc-net-server/Dockerfile
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||||
|
WORKDIR /app
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||||
|
WORKDIR /src
|
||||||
|
COPY ["qtc-net-server/qtc-net-server.csproj", "qtc-net-server/"]
|
||||||
|
RUN dotnet restore "qtc-net-server/qtc-net-server.csproj"
|
||||||
|
COPY . .
|
||||||
|
WORKDIR "/src/qtc-net-server"
|
||||||
|
RUN dotnet build "qtc-net-server.csproj" -c Release -o /app/build
|
||||||
|
|
||||||
|
FROM build AS publish
|
||||||
|
RUN dotnet publish "qtc-net-server.csproj" -c Release -o /app/publish /p:UseAppHost=false
|
||||||
|
|
||||||
|
FROM base AS final
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=publish /app/publish .
|
||||||
|
ENTRYPOINT ["dotnet", "qtc-net-server.dll"]
|
||||||
8
qtc-net-server/Dtos/Room/RoomDto.cs
Normal file
8
qtc-net-server/Dtos/Room/RoomDto.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace qtc_api.Dtos.Room
|
||||||
|
{
|
||||||
|
public class RoomDto
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public DateTime CreatedAt { get; set; } = new DateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
8
qtc-net-server/Dtos/User/UserConnectionDto.cs
Normal file
8
qtc-net-server/Dtos/User/UserConnectionDto.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace qtc_api.Dtos.User
|
||||||
|
{
|
||||||
|
public class UserConnectionDto
|
||||||
|
{
|
||||||
|
public Models.User? ConnectedUser { get; set; }
|
||||||
|
public string? ConnectionId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
qtc-net-server/Dtos/User/UserDto.cs
Normal file
10
qtc-net-server/Dtos/User/UserDto.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace qtc_api.Dtos.User
|
||||||
|
{
|
||||||
|
public class UserDto
|
||||||
|
{
|
||||||
|
public string Username { get; set; } = string.Empty;
|
||||||
|
public string Password { get; set; } = string.Empty;
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
public DateTime DateOfBirth { get; set; } = new DateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
14
qtc-net-server/Dtos/User/UserInformationDto.cs
Normal file
14
qtc-net-server/Dtos/User/UserInformationDto.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace qtc_api.Dtos.User
|
||||||
|
{
|
||||||
|
public class UserInformationDto
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string Username { get; set; } = string.Empty;
|
||||||
|
public string ProfilePicture { get; set; } = string.Empty;
|
||||||
|
public string Bio { get; set; } = string.Empty;
|
||||||
|
public string Role { get; set; } = string.Empty;
|
||||||
|
public DateTime DateOfBirth { get; set; } = new DateTime();
|
||||||
|
public DateTime CreatedAt { get; set; } = new DateTime();
|
||||||
|
public int Status { get; set; } = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
qtc-net-server/Dtos/User/UserLoginDto.cs
Normal file
9
qtc-net-server/Dtos/User/UserLoginDto.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace qtc_api.Dtos.User
|
||||||
|
{
|
||||||
|
public class UserLoginDto
|
||||||
|
{
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
public string Password { get; set; } = string.Empty;
|
||||||
|
public bool RememberMe { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
8
qtc-net-server/Dtos/User/UserStatusDto.cs
Normal file
8
qtc-net-server/Dtos/User/UserStatusDto.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace qtc_api.Dtos.User
|
||||||
|
{
|
||||||
|
public class UserStatusDto
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public int Status { get; set; } = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
qtc-net-server/Dtos/User/UserUpdateInformationDto.cs
Normal file
10
qtc-net-server/Dtos/User/UserUpdateInformationDto.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace qtc_api.Dtos.User
|
||||||
|
{
|
||||||
|
public class UserUpdateInformationDto
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string Username { get; set; } = string.Empty;
|
||||||
|
public string Bio { get; set; } = string.Empty;
|
||||||
|
public DateTime DateOfBirth { get; set; } = new DateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
167
qtc-net-server/Hubs/ChatHub.cs
Normal file
167
qtc-net-server/Hubs/ChatHub.cs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace qtc_gateway.Hubs
|
||||||
|
{
|
||||||
|
[Authorize]
|
||||||
|
public class ChatHub : Hub
|
||||||
|
{
|
||||||
|
private IUserService _userService;
|
||||||
|
private ILogger<ChatHub> _logger;
|
||||||
|
private static List<UserConnectionDto> ConnectedUsers = new List<UserConnectionDto>();
|
||||||
|
private static List<User> OnlineUsers = new List<User>();
|
||||||
|
|
||||||
|
public ChatHub(IUserService userService, ILogger<ChatHub> logger)
|
||||||
|
{
|
||||||
|
_userService = userService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task OnDisconnectedAsync(Exception? ex)
|
||||||
|
{
|
||||||
|
Log("Client Disconnected.");
|
||||||
|
|
||||||
|
var connection = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
|
||||||
|
|
||||||
|
if (connection != null)
|
||||||
|
{
|
||||||
|
var user = OnlineUsers.FirstOrDefault(x => x.Id == connection!.ConnectedUser!.Id);
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
await LogoutAsync(user!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("l")]
|
||||||
|
public async Task LoginAsync(User user)
|
||||||
|
{
|
||||||
|
await Clients.All.SendAsync("rm", $"[SERVER] User {user.Username} Is Now Online");
|
||||||
|
Log($"User {user.Username} Has Logged In");
|
||||||
|
|
||||||
|
var statusDto = new UserStatusDto { Id = user.Id, Status = 1 };
|
||||||
|
|
||||||
|
await _userService.UpdateStatus(statusDto);
|
||||||
|
|
||||||
|
ConnectedUsers.Add(new UserConnectionDto() { ConnectedUser = user, ConnectionId = Context.ConnectionId });
|
||||||
|
OnlineUsers.Add(user);
|
||||||
|
|
||||||
|
ServerConfig serverConfig = JsonSerializer.Deserialize<ServerConfig>(JsonDocument.Parse(File.ReadAllText("./ServerConfig.json")));
|
||||||
|
|
||||||
|
await Clients.Client(ConnectedUsers.FirstOrDefault(e => e.ConnectionId == Context.ConnectionId)!.ConnectionId!).SendAsync("rc", serverConfig);
|
||||||
|
await Clients.All.SendAsync("cf", "rul");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("us")]
|
||||||
|
public async Task UpdateStatusAsync(User user, int status)
|
||||||
|
{
|
||||||
|
var statusDto = new UserStatusDto { Id = user.Id, Status = status };
|
||||||
|
|
||||||
|
await _userService.UpdateStatus(statusDto);
|
||||||
|
|
||||||
|
await Clients.All.SendAsync("cf", "rul");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("jl")]
|
||||||
|
public async Task JoinHubAsync(User user)
|
||||||
|
{
|
||||||
|
await Groups.AddToGroupAsync(Context.ConnectionId, "LOBBY");
|
||||||
|
|
||||||
|
await Clients.Group("LOBBY").SendAsync("rm", $"[SERVER] User {user.Username} Has Joined The Lobby");
|
||||||
|
Log($"User {user.Username} Has Joined The Lobby");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("ll")]
|
||||||
|
public async Task LeaveLobbyAsync(User user)
|
||||||
|
{
|
||||||
|
await Groups.RemoveFromGroupAsync(Context.ConnectionId, "LOBBY");
|
||||||
|
|
||||||
|
await Clients.Group("LOBBY").SendAsync("rm", $"[SERVER] User {user.Username} Has Left The Lobby");
|
||||||
|
Log($"User {user.Username} Has Left The Lobby");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("jr")]
|
||||||
|
public async Task JoinRoomAsync(User user, Room room)
|
||||||
|
{
|
||||||
|
await Groups.AddToGroupAsync(Context.ConnectionId, room.Id);
|
||||||
|
|
||||||
|
await Clients.Group(room.Id).SendAsync("rm", $"[SERVER] User {user.Username} Has Joined The Room");
|
||||||
|
Log($"User {user.Username} Has Joined {room.Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("lr")]
|
||||||
|
public async Task LeaveRoomAsync(User user, Room room)
|
||||||
|
{
|
||||||
|
await Groups.RemoveFromGroupAsync(Context.ConnectionId, room.Id);
|
||||||
|
|
||||||
|
await Clients.Group(room.Id).SendAsync("rm", $"[SERVER] User {user.Username} Has Left The Room");
|
||||||
|
Log($"User {user.Username} Has Left {room.Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("hdr")]
|
||||||
|
public async Task HandleDeletedRoomAsync(Room room)
|
||||||
|
{
|
||||||
|
await Clients.Group(room.Id).SendAsync("rm", $"[SERVER] This Room Has Been Deleted By An Administrator.");
|
||||||
|
await Clients.Group(room.Id).SendAsync("cf", "rtl");
|
||||||
|
|
||||||
|
await Clients.All.SendAsync("cf", "rr");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("rcl")]
|
||||||
|
public async Task RefreshContactsListForUser(UserInformationDto user, User execUser)
|
||||||
|
{
|
||||||
|
var connection = ConnectedUsers.FirstOrDefault(e => e.ConnectedUser.Id == user.Id);
|
||||||
|
var connection2 = ConnectedUsers.FirstOrDefault(e => e.ConnectedUser.Id == execUser.Id);
|
||||||
|
if (connection != null && connection2 != null)
|
||||||
|
{
|
||||||
|
await Clients.Client(connection.ConnectionId).SendAsync("cf", "rcl");
|
||||||
|
await Clients.Client(connection2.ConnectionId).SendAsync("cf", "rcl");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("s")]
|
||||||
|
public async Task SendMessageAsync(User user, Message message, bool IsLobbyMsg, Room room = null!)
|
||||||
|
{
|
||||||
|
if(IsLobbyMsg == true) { await Clients.Group("LOBBY").SendAsync("rm", $"[{user.Username}] {message.Content}"); return; }
|
||||||
|
await Clients.Group(room.Id).SendAsync("rm", $"[{user.Username}] {message.Content}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[HubMethodName("sdm")]
|
||||||
|
public async Task SendDirectMessageAsync(User user, UserInformationDto userToMsg, Message message)
|
||||||
|
{
|
||||||
|
// send direct message directly to connected user
|
||||||
|
var connection = ConnectedUsers.FirstOrDefault(e => e.ConnectedUser.Id == userToMsg.Id);
|
||||||
|
if (connection != null)
|
||||||
|
{
|
||||||
|
UserInformationDto userInformationDto = new UserInformationDto { Id = user.Id, Username = user.Username, Bio = user.Bio, Role = user.Role, Status = user.Status, CreatedAt = user.CreatedAt, DateOfBirth = user.DateOfBirth, ProfilePicture = user.ProfilePicture };
|
||||||
|
await Clients.Client(connection.ConnectionId).SendAsync("rdm", message, userInformationDto);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LogoutAsync(User user)
|
||||||
|
{
|
||||||
|
await Clients.All.SendAsync("rm", $"[SERVER] User {user.Username} Is Now Offline");
|
||||||
|
Log($"User {user.Username} Has Logged Out");
|
||||||
|
|
||||||
|
var statusDto = new UserStatusDto { Id = user.Id, Status = 0 };
|
||||||
|
|
||||||
|
await _userService.UpdateStatus(statusDto);
|
||||||
|
|
||||||
|
Log($"Set User {user.Username} To Offline");
|
||||||
|
|
||||||
|
await Clients.All.SendAsync("cf", "rul");
|
||||||
|
|
||||||
|
OnlineUsers.Remove(user);
|
||||||
|
|
||||||
|
var connection = ConnectedUsers.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);
|
||||||
|
ConnectedUsers.Remove(connection!);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Log(string message)
|
||||||
|
{
|
||||||
|
_logger.LogInformation(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
133
qtc-net-server/Migrations/20250605232504_InitialData.Designer.cs
generated
Normal file
133
qtc-net-server/Migrations/20250605232504_InitialData.Designer.cs
generated
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using qtc_api.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20250605232504_InitialData")]
|
||||||
|
partial class InitialData
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.5")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("OwnerId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Contacts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("ID")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Expires")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("ValidRefreshTokens");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Room", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("CreatorId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Rooms");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Bio")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateOfBirth")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ProfilePicture")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Role")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
100
qtc-net-server/Migrations/20250605232504_InitialData.cs
Normal file
100
qtc-net-server/Migrations/20250605232504_InitialData.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class InitialData : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterDatabase()
|
||||||
|
.Annotation("MySQL:Charset", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Contacts",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(type: "varchar(255)", nullable: false),
|
||||||
|
OwnerId = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
UserId = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "int", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Contacts", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySQL:Charset", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Rooms",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(type: "varchar(255)", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
CreatorId = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Rooms", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySQL:Charset", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Users",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(type: "varchar(255)", nullable: false),
|
||||||
|
Username = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
ProfilePicture = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
Bio = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
Role = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
PasswordHash = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
Email = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
DateOfBirth = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
Status = table.Column<int>(type: "int", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Users", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySQL:Charset", "utf8mb4");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ValidRefreshTokens",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ID = table.Column<string>(type: "varchar(255)", nullable: false),
|
||||||
|
UserID = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
Token = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
Expires = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ValidRefreshTokens", x => x.ID);
|
||||||
|
})
|
||||||
|
.Annotation("MySQL:Charset", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Contacts");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Rooms");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ValidRefreshTokens");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
136
qtc-net-server/Migrations/20250606000415_AddExtraStatus.Designer.cs
generated
Normal file
136
qtc-net-server/Migrations/20250606000415_AddExtraStatus.Designer.cs
generated
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using qtc_api.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20250606000415_AddExtraStatus")]
|
||||||
|
partial class AddExtraStatus
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.5")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("OwnerId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("UserStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Contacts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("ID")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Expires")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.ToTable("ValidRefreshTokens");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Room", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("CreatorId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Rooms");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Bio")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateOfBirth")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ProfilePicture")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Role")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
qtc-net-server/Migrations/20250606000415_AddExtraStatus.cs
Normal file
39
qtc-net-server/Migrations/20250606000415_AddExtraStatus.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddExtraStatus : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "Status",
|
||||||
|
table: "Contacts",
|
||||||
|
newName: "UserStatus");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "OwnerStatus",
|
||||||
|
table: "Contacts",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "OwnerStatus",
|
||||||
|
table: "Contacts");
|
||||||
|
|
||||||
|
migrationBuilder.RenameColumn(
|
||||||
|
name: "UserStatus",
|
||||||
|
table: "Contacts",
|
||||||
|
newName: "Status");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
160
qtc-net-server/Migrations/20250608203855_RefreshTokensForeignKey.Designer.cs
generated
Normal file
160
qtc-net-server/Migrations/20250608203855_RefreshTokensForeignKey.Designer.cs
generated
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using qtc_api.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20250608203855_RefreshTokensForeignKey")]
|
||||||
|
partial class RefreshTokensForeignKey
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.5")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("OwnerId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("UserStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Contact");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("ID")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Expires")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("UserID");
|
||||||
|
|
||||||
|
b.ToTable("RefreshToken");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Bio")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateOfBirth")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ProfilePicture")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Role")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("qtc_api.Models.User", "Owner")
|
||||||
|
.WithMany("ContactsMade")
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("qtc_api.Models.User", "User")
|
||||||
|
.WithMany("ContactsList")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("qtc_api.Models.User", "User")
|
||||||
|
.WithMany("RefreshTokens")
|
||||||
|
.HasForeignKey("UserID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ContactsList");
|
||||||
|
|
||||||
|
b.Navigation("ContactsMade");
|
||||||
|
|
||||||
|
b.Navigation("RefreshTokens");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,226 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class RefreshTokensForeignKey : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Rooms");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_ValidRefreshTokens",
|
||||||
|
table: "ValidRefreshTokens");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Users",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Contacts",
|
||||||
|
table: "Contacts");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "ValidRefreshTokens",
|
||||||
|
newName: "RefreshToken");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "Users",
|
||||||
|
newName: "User");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "Contacts",
|
||||||
|
newName: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "UserID",
|
||||||
|
table: "RefreshToken",
|
||||||
|
type: "varchar(255)",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "longtext");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "UserId",
|
||||||
|
table: "Contact",
|
||||||
|
type: "varchar(255)",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "longtext");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "OwnerId",
|
||||||
|
table: "Contact",
|
||||||
|
type: "varchar(255)",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "longtext");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_RefreshToken",
|
||||||
|
table: "RefreshToken",
|
||||||
|
column: "ID");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_User",
|
||||||
|
table: "User",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Contact",
|
||||||
|
table: "Contact",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_RefreshToken_UserID",
|
||||||
|
table: "RefreshToken",
|
||||||
|
column: "UserID");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Contact_OwnerId",
|
||||||
|
table: "Contact",
|
||||||
|
column: "OwnerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Contact_UserId",
|
||||||
|
table: "Contact",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Contact_User_OwnerId",
|
||||||
|
table: "Contact",
|
||||||
|
column: "OwnerId",
|
||||||
|
principalTable: "User",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Contact_User_UserId",
|
||||||
|
table: "Contact",
|
||||||
|
column: "UserId",
|
||||||
|
principalTable: "User",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_RefreshToken_User_UserID",
|
||||||
|
table: "RefreshToken",
|
||||||
|
column: "UserID",
|
||||||
|
principalTable: "User",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Contact_User_OwnerId",
|
||||||
|
table: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Contact_User_UserId",
|
||||||
|
table: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_RefreshToken_User_UserID",
|
||||||
|
table: "RefreshToken");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_User",
|
||||||
|
table: "User");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_RefreshToken",
|
||||||
|
table: "RefreshToken");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_RefreshToken_UserID",
|
||||||
|
table: "RefreshToken");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Contact",
|
||||||
|
table: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Contact_OwnerId",
|
||||||
|
table: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Contact_UserId",
|
||||||
|
table: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "User",
|
||||||
|
newName: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "RefreshToken",
|
||||||
|
newName: "ValidRefreshTokens");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "Contact",
|
||||||
|
newName: "Contacts");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "UserID",
|
||||||
|
table: "ValidRefreshTokens",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "varchar(255)");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "UserId",
|
||||||
|
table: "Contacts",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "varchar(255)");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "OwnerId",
|
||||||
|
table: "Contacts",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "varchar(255)");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Users",
|
||||||
|
table: "Users",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_ValidRefreshTokens",
|
||||||
|
table: "ValidRefreshTokens",
|
||||||
|
column: "ID");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Contacts",
|
||||||
|
table: "Contacts",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Rooms",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(type: "varchar(255)", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false),
|
||||||
|
CreatorId = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "longtext", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Rooms", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySQL:Charset", "utf8mb4");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
181
qtc-net-server/Migrations/20250608204114_AddRemainingRelations.Designer.cs
generated
Normal file
181
qtc-net-server/Migrations/20250608204114_AddRemainingRelations.Designer.cs
generated
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using qtc_api.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20250608204114_AddRemainingRelations")]
|
||||||
|
partial class AddRemainingRelations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.5")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("OwnerId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("UserStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Contact");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("ID")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Expires")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("UserID");
|
||||||
|
|
||||||
|
b.ToTable("RefreshToken");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Room", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("CreatorId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Room");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Bio")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateOfBirth")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ProfilePicture")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Role")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("qtc_api.Models.User", "Owner")
|
||||||
|
.WithMany("ContactsMade")
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("qtc_api.Models.User", "User")
|
||||||
|
.WithMany("ContactsList")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("qtc_api.Models.User", "User")
|
||||||
|
.WithMany("RefreshTokens")
|
||||||
|
.HasForeignKey("UserID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ContactsList");
|
||||||
|
|
||||||
|
b.Navigation("ContactsMade");
|
||||||
|
|
||||||
|
b.Navigation("RefreshTokens");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddRemainingRelations : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Room",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<string>(type: "varchar(255)", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
CreatorId = table.Column<string>(type: "longtext", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "datetime(6)", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Room", x => x.Id);
|
||||||
|
})
|
||||||
|
.Annotation("MySQL:Charset", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Room");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
181
qtc-net-server/Migrations/20250608204625_ValidRefreshTokens.Designer.cs
generated
Normal file
181
qtc-net-server/Migrations/20250608204625_ValidRefreshTokens.Designer.cs
generated
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using qtc_api.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20250608204625_ValidRefreshTokens")]
|
||||||
|
partial class ValidRefreshTokens
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.5")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("OwnerId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("UserStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Contacts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("ID")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Expires")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("UserID");
|
||||||
|
|
||||||
|
b.ToTable("ValidRefreshTokens");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Room", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("CreatorId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Rooms");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Bio")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateOfBirth")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ProfilePicture")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Role")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("qtc_api.Models.User", "Owner")
|
||||||
|
.WithMany("ContactsMade")
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("qtc_api.Models.User", "User")
|
||||||
|
.WithMany("ContactsList")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("qtc_api.Models.User", "User")
|
||||||
|
.WithMany("RefreshTokens")
|
||||||
|
.HasForeignKey("UserID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ContactsList");
|
||||||
|
|
||||||
|
b.Navigation("ContactsMade");
|
||||||
|
|
||||||
|
b.Navigation("RefreshTokens");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
224
qtc-net-server/Migrations/20250608204625_ValidRefreshTokens.cs
Normal file
224
qtc-net-server/Migrations/20250608204625_ValidRefreshTokens.cs
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ValidRefreshTokens : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Contact_User_OwnerId",
|
||||||
|
table: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Contact_User_UserId",
|
||||||
|
table: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_RefreshToken_User_UserID",
|
||||||
|
table: "RefreshToken");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_User",
|
||||||
|
table: "User");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Room",
|
||||||
|
table: "Room");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_RefreshToken",
|
||||||
|
table: "RefreshToken");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Contact",
|
||||||
|
table: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "User",
|
||||||
|
newName: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "Room",
|
||||||
|
newName: "Rooms");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "RefreshToken",
|
||||||
|
newName: "ValidRefreshTokens");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "Contact",
|
||||||
|
newName: "Contacts");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_RefreshToken_UserID",
|
||||||
|
table: "ValidRefreshTokens",
|
||||||
|
newName: "IX_ValidRefreshTokens_UserID");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_Contact_UserId",
|
||||||
|
table: "Contacts",
|
||||||
|
newName: "IX_Contacts_UserId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_Contact_OwnerId",
|
||||||
|
table: "Contacts",
|
||||||
|
newName: "IX_Contacts_OwnerId");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Users",
|
||||||
|
table: "Users",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Rooms",
|
||||||
|
table: "Rooms",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_ValidRefreshTokens",
|
||||||
|
table: "ValidRefreshTokens",
|
||||||
|
column: "ID");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Contacts",
|
||||||
|
table: "Contacts",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Contacts_Users_OwnerId",
|
||||||
|
table: "Contacts",
|
||||||
|
column: "OwnerId",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Contacts_Users_UserId",
|
||||||
|
table: "Contacts",
|
||||||
|
column: "UserId",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_ValidRefreshTokens_Users_UserID",
|
||||||
|
table: "ValidRefreshTokens",
|
||||||
|
column: "UserID",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Contacts_Users_OwnerId",
|
||||||
|
table: "Contacts");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Contacts_Users_UserId",
|
||||||
|
table: "Contacts");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_ValidRefreshTokens_Users_UserID",
|
||||||
|
table: "ValidRefreshTokens");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_ValidRefreshTokens",
|
||||||
|
table: "ValidRefreshTokens");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Users",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Rooms",
|
||||||
|
table: "Rooms");
|
||||||
|
|
||||||
|
migrationBuilder.DropPrimaryKey(
|
||||||
|
name: "PK_Contacts",
|
||||||
|
table: "Contacts");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "ValidRefreshTokens",
|
||||||
|
newName: "RefreshToken");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "Users",
|
||||||
|
newName: "User");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "Rooms",
|
||||||
|
newName: "Room");
|
||||||
|
|
||||||
|
migrationBuilder.RenameTable(
|
||||||
|
name: "Contacts",
|
||||||
|
newName: "Contact");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_ValidRefreshTokens_UserID",
|
||||||
|
table: "RefreshToken",
|
||||||
|
newName: "IX_RefreshToken_UserID");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_Contacts_UserId",
|
||||||
|
table: "Contact",
|
||||||
|
newName: "IX_Contact_UserId");
|
||||||
|
|
||||||
|
migrationBuilder.RenameIndex(
|
||||||
|
name: "IX_Contacts_OwnerId",
|
||||||
|
table: "Contact",
|
||||||
|
newName: "IX_Contact_OwnerId");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_RefreshToken",
|
||||||
|
table: "RefreshToken",
|
||||||
|
column: "ID");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_User",
|
||||||
|
table: "User",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Room",
|
||||||
|
table: "Room",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddPrimaryKey(
|
||||||
|
name: "PK_Contact",
|
||||||
|
table: "Contact",
|
||||||
|
column: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Contact_User_OwnerId",
|
||||||
|
table: "Contact",
|
||||||
|
column: "OwnerId",
|
||||||
|
principalTable: "User",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Contact_User_UserId",
|
||||||
|
table: "Contact",
|
||||||
|
column: "UserId",
|
||||||
|
principalTable: "User",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_RefreshToken_User_UserID",
|
||||||
|
table: "RefreshToken",
|
||||||
|
column: "UserID",
|
||||||
|
principalTable: "User",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
178
qtc-net-server/Migrations/DataContextModelSnapshot.cs
Normal file
178
qtc-net-server/Migrations/DataContextModelSnapshot.cs
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using qtc_api.Data;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace qtc_api.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
partial class DataContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.5")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("OwnerId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("UserId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<int>("UserStatus")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Contacts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("ID")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Expires")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Token")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("UserID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("ID");
|
||||||
|
|
||||||
|
b.HasIndex("UserID");
|
||||||
|
|
||||||
|
b.ToTable("ValidRefreshTokens");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Room", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("CreatorId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Rooms");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("varchar(255)");
|
||||||
|
|
||||||
|
b.Property<string>("Bio")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateOfBirth")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("ProfilePicture")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<string>("Role")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.Property<int>("Status")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.Contact", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("qtc_api.Models.User", "Owner")
|
||||||
|
.WithMany("ContactsMade")
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("qtc_api.Models.User", "User")
|
||||||
|
.WithMany("ContactsList")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.RefreshToken", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("qtc_api.Models.User", "User")
|
||||||
|
.WithMany("RefreshTokens")
|
||||||
|
.HasForeignKey("UserID")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("qtc_api.Models.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("ContactsList");
|
||||||
|
|
||||||
|
b.Navigation("ContactsMade");
|
||||||
|
|
||||||
|
b.Navigation("RefreshTokens");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
qtc-net-server/Models/Contact.cs
Normal file
16
qtc-net-server/Models/Contact.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace qtc_api.Models
|
||||||
|
{
|
||||||
|
public class Contact
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string OwnerId { get; set; } = string.Empty;
|
||||||
|
public string UserId { get; set; } = string.Empty;
|
||||||
|
public ContactStatus OwnerStatus { get; set; } = ContactStatus.AwaitingApprovalFromOther;
|
||||||
|
public ContactStatus UserStatus { get; set; } = ContactStatus.AwaitingApprovalFromSelf;
|
||||||
|
|
||||||
|
public virtual User? Owner { get; }
|
||||||
|
public virtual User? User { get; }
|
||||||
|
|
||||||
|
public enum ContactStatus { AwaitingApprovalFromOther = 0, AwaitingApprovalFromSelf = 1, Accepted = 2 }
|
||||||
|
}
|
||||||
|
}
|
||||||
10
qtc-net-server/Models/Message.cs
Normal file
10
qtc-net-server/Models/Message.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace qtc_api.Models
|
||||||
|
{
|
||||||
|
public class Message
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string AuthorId { get; set; } = string.Empty;
|
||||||
|
public string Content { get; set; } = string.Empty;
|
||||||
|
public DateTime CreatedAt { get; set; } = new DateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
12
qtc-net-server/Models/RefreshToken.cs
Normal file
12
qtc-net-server/Models/RefreshToken.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
namespace qtc_api.Models
|
||||||
|
{
|
||||||
|
public class RefreshToken
|
||||||
|
{
|
||||||
|
public string ID { get; set; } = string.Empty;
|
||||||
|
public string UserID { get; set; } = string.Empty;
|
||||||
|
public string Token { get; set; } = string.Empty;
|
||||||
|
public DateTime Expires { get; set; }
|
||||||
|
|
||||||
|
public virtual User User { get; } = null!;
|
||||||
|
}
|
||||||
|
}
|
||||||
10
qtc-net-server/Models/Room.cs
Normal file
10
qtc-net-server/Models/Room.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace qtc_api.Models
|
||||||
|
{
|
||||||
|
public class Room
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
public string CreatorId { get; set; } = string.Empty;
|
||||||
|
public DateTime CreatedAt { get; set; } = new DateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
qtc-net-server/Models/ServerConfig.cs
Normal file
11
qtc-net-server/Models/ServerConfig.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace qtc_api.Models
|
||||||
|
{
|
||||||
|
public class ServerConfig
|
||||||
|
{
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public string? Description { get; set; }
|
||||||
|
public string? AdminUserId { get; set; }
|
||||||
|
public bool IsDown { get; set; }
|
||||||
|
public string? IsDownMessage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
9
qtc-net-server/Models/ServiceResponse.cs
Normal file
9
qtc-net-server/Models/ServiceResponse.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace qtc_api.Models
|
||||||
|
{
|
||||||
|
public class ServiceResponse<T>
|
||||||
|
{
|
||||||
|
public T? Data { get; set; }
|
||||||
|
public bool Success { get; set; } = false;
|
||||||
|
public string Message { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
20
qtc-net-server/Models/User.cs
Normal file
20
qtc-net-server/Models/User.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace qtc_api.Models
|
||||||
|
{
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string Username { get; set; } = string.Empty;
|
||||||
|
public string ProfilePicture { get; set; } = string.Empty;
|
||||||
|
public string Bio { get; set; } = string.Empty;
|
||||||
|
public string Role { get; set; } = string.Empty;
|
||||||
|
public string PasswordHash { get; set; } = string.Empty;
|
||||||
|
public string Email { get; set; } = string.Empty;
|
||||||
|
public DateTime DateOfBirth { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
public int Status { get; set; } = 0;
|
||||||
|
|
||||||
|
public virtual IEnumerable<RefreshToken>? RefreshTokens { get; }
|
||||||
|
public virtual IEnumerable<Contact>? ContactsMade { get; }
|
||||||
|
public virtual IEnumerable<Contact>? ContactsList { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
63
qtc-net-server/Program.cs
Normal file
63
qtc-net-server/Program.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
global using Microsoft.AspNetCore.Mvc;
|
||||||
|
global using Microsoft.EntityFrameworkCore;
|
||||||
|
global using Microsoft.AspNetCore.SignalR;
|
||||||
|
global using Microsoft.AspNetCore.Authorization;
|
||||||
|
global using qtc_api.Models;
|
||||||
|
global using qtc_api.Data;
|
||||||
|
global using qtc_api.Dtos.User;
|
||||||
|
global using qtc_api.Dtos.Room;
|
||||||
|
global using qtc_api.Services.UserService;
|
||||||
|
global using Microsoft.IdentityModel.Tokens;
|
||||||
|
global using System.Text;
|
||||||
|
global using qtc_api.Services.TokenService;
|
||||||
|
global using qtc_gateway.Hubs;
|
||||||
|
using qtc_api.Services.RoomService;
|
||||||
|
using qtc_api.Services.ContactService;
|
||||||
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddDbContext<DataContext>(options =>
|
||||||
|
{
|
||||||
|
if (builder.Environment.IsProduction()) options.UseMySQL(builder.Configuration.GetConnectionString("DefaultConnection"));
|
||||||
|
else options.UseSqlite(builder.Configuration.GetConnectionString("DevelopmentConnection"));
|
||||||
|
|
||||||
|
// ignore pending model changes warning
|
||||||
|
options.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning));
|
||||||
|
});
|
||||||
|
builder.Services.AddSignalR();
|
||||||
|
|
||||||
|
builder.Services.AddAuthentication().AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = false,
|
||||||
|
ValidateAudience = false,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidIssuer = builder.Configuration["Jwt:Issuer"],
|
||||||
|
ValidAudience = builder.Configuration["Jwt:Audience"],
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]!))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
builder.Services.AddScoped<IUserService, UserService>();
|
||||||
|
builder.Services.AddScoped<ITokenService, TokenService>();
|
||||||
|
builder.Services.AddScoped<IRoomService, RoomService>();
|
||||||
|
builder.Services.AddScoped<IContactService, ContactService>();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
using var scope = app.Services.CreateScope();
|
||||||
|
|
||||||
|
await scope.ServiceProvider.GetRequiredService<DataContext>().Database.EnsureCreatedAsync();
|
||||||
|
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
app.MapHub<ChatHub>("/chat");
|
||||||
|
|
||||||
|
app.Run();
|
||||||
37
qtc-net-server/Properties/launchSettings.json
Normal file
37
qtc-net-server/Properties/launchSettings.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"profiles": {
|
||||||
|
"http": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
},
|
||||||
|
"dotnetRunMessages": true,
|
||||||
|
"applicationUrl": "http://localhost:5268"
|
||||||
|
},
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "swagger",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Docker": {
|
||||||
|
"commandName": "Docker",
|
||||||
|
"launchBrowser": true,
|
||||||
|
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
|
||||||
|
"publishAllPorts": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:26136",
|
||||||
|
"sslPort": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
7
qtc-net-server/ServerConfig.json
Normal file
7
qtc-net-server/ServerConfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"Name": "QtC.NET Server",
|
||||||
|
"Description": "This is a QtC.NET Server.",
|
||||||
|
"AdminUserId": "523736357658921388",
|
||||||
|
"IsDown": false,
|
||||||
|
"IsDownMessage": "This server is currently down. Please try again later."
|
||||||
|
}
|
||||||
118
qtc-net-server/Services/ContactService/ContactService.cs
Normal file
118
qtc-net-server/Services/ContactService/ContactService.cs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
namespace qtc_api.Services.ContactService
|
||||||
|
{
|
||||||
|
public class ContactService : IContactService
|
||||||
|
{
|
||||||
|
private readonly DataContext _dataContext;
|
||||||
|
|
||||||
|
public ContactService(DataContext dataContext)
|
||||||
|
{
|
||||||
|
_dataContext = dataContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<Contact>> CreateContact(string ownerId, string userId)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<Contact>();
|
||||||
|
var rnd = LongRandom(1, 900000000000000000, new Random());
|
||||||
|
|
||||||
|
var contact = new Contact()
|
||||||
|
{
|
||||||
|
Id = rnd.ToString(),
|
||||||
|
OwnerId = ownerId,
|
||||||
|
UserId = userId,
|
||||||
|
OwnerStatus = Contact.ContactStatus.AwaitingApprovalFromOther,
|
||||||
|
UserStatus = Contact.ContactStatus.AwaitingApprovalFromSelf,
|
||||||
|
};
|
||||||
|
|
||||||
|
await _dataContext.Contacts.AddAsync(contact);
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = contact;
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<bool>> UpdateContactStatus(string ownerId, string userId, Contact.ContactStatus ownerStatus, Contact.ContactStatus userStatus)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<bool>();
|
||||||
|
var contact = await _dataContext.Contacts.FirstOrDefaultAsync(e => (e.OwnerId == ownerId || e.UserId == userId) || (e.OwnerId == userId || e.UserId == ownerId));
|
||||||
|
|
||||||
|
if(contact != null)
|
||||||
|
{
|
||||||
|
contact.OwnerStatus = ownerStatus;
|
||||||
|
contact.UserStatus = userStatus;
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
}
|
||||||
|
else serviceResponse.Success = false;
|
||||||
|
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<Contact>> DeleteContact(string ownerId, string userId)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<Contact>();
|
||||||
|
var contact = await _dataContext.Contacts.FirstOrDefaultAsync(x => (x.OwnerId == ownerId || x.UserId == userId) || (x.OwnerId == userId || x.UserId == ownerId));
|
||||||
|
|
||||||
|
if (contact != null)
|
||||||
|
{
|
||||||
|
var result = _dataContext.Contacts.Remove(contact);
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = result.Entity;
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Data = null;
|
||||||
|
serviceResponse.Message = "Contact Not Found";
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<Contact>> GetContactById(string id)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<Contact>();
|
||||||
|
|
||||||
|
var contact = await _dataContext.Contacts.FirstOrDefaultAsync(x => x.Id == id);
|
||||||
|
|
||||||
|
if (contact == null) { serviceResponse.Success = false; serviceResponse.Message = "Contact Does Not Exist."; }
|
||||||
|
else { serviceResponse.Success = true; serviceResponse.Data = contact; }
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<List<Contact>>> GetUserContacts(User user)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<List<Contact>>();
|
||||||
|
|
||||||
|
var contactsMade = await _dataContext.Contacts.Where(x => x.OwnerId == user.Id).ToListAsync();
|
||||||
|
var contactsList = await _dataContext.Contacts.Where(x => x.UserId == user.Id).ToListAsync();
|
||||||
|
|
||||||
|
var contactsCombined = new List<Contact>();
|
||||||
|
|
||||||
|
foreach (var contact in contactsMade)
|
||||||
|
contactsCombined.Add(contact); // all contacts the user has made
|
||||||
|
foreach (var contact in contactsList)
|
||||||
|
contactsCombined.Add(contact); // all contacts the user has received
|
||||||
|
|
||||||
|
if (contactsCombined.Count == 0) { serviceResponse.Success = true; serviceResponse.Message = "User Has No Contacts."; }
|
||||||
|
else { serviceResponse.Success = true; serviceResponse.Data = contactsCombined; }
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long LongRandom(long min, long max, Random rnd)
|
||||||
|
{
|
||||||
|
long result = rnd.Next((int)(min >> 32), (int)(max >> 32));
|
||||||
|
result = result << 32;
|
||||||
|
result = result | (long)rnd.Next((int)min, (int)max);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
qtc-net-server/Services/ContactService/IContactService.cs
Normal file
11
qtc-net-server/Services/ContactService/IContactService.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace qtc_api.Services.ContactService
|
||||||
|
{
|
||||||
|
public interface IContactService
|
||||||
|
{
|
||||||
|
public Task<ServiceResponse<Contact>> CreateContact(string ownerId, string userId);
|
||||||
|
public Task<ServiceResponse<bool>> UpdateContactStatus(string ownerId, string userId, Contact.ContactStatus ownerStatus, Contact.ContactStatus userStatus);
|
||||||
|
public Task<ServiceResponse<List<Contact>>> GetUserContacts(User user);
|
||||||
|
public Task<ServiceResponse<Contact>> GetContactById(string id);
|
||||||
|
public Task<ServiceResponse<Contact>> DeleteContact(string ownerId, string userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
qtc-net-server/Services/RoomService/IRoomService.cs
Normal file
11
qtc-net-server/Services/RoomService/IRoomService.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace qtc_api.Services.RoomService
|
||||||
|
{
|
||||||
|
public interface IRoomService
|
||||||
|
{
|
||||||
|
public Task<ServiceResponse<Room>> GetRoom(string id);
|
||||||
|
public Task<ServiceResponse<List<Room>>> GetAllRooms();
|
||||||
|
public Task<ServiceResponse<Room>> AddRoom(string userId, RoomDto room);
|
||||||
|
public Task<ServiceResponse<Room>> UpdateRoom(Room room);
|
||||||
|
public Task<ServiceResponse<Room>> DeleteRoom(string id);
|
||||||
|
}
|
||||||
|
}
|
||||||
107
qtc-net-server/Services/RoomService/RoomService.cs
Normal file
107
qtc-net-server/Services/RoomService/RoomService.cs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
namespace qtc_api.Services.RoomService
|
||||||
|
{
|
||||||
|
public class RoomService : IRoomService
|
||||||
|
{
|
||||||
|
private readonly DataContext _dataContext;
|
||||||
|
|
||||||
|
private long idMax = 900000000000000000;
|
||||||
|
|
||||||
|
public RoomService(DataContext dataContext)
|
||||||
|
{
|
||||||
|
_dataContext = dataContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<Room>> AddRoom(string userId, RoomDto room)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<Room>();
|
||||||
|
var roomList = await _dataContext.Rooms.ToListAsync();
|
||||||
|
|
||||||
|
var roomToAdd = new Room();
|
||||||
|
Random rnd = new Random();
|
||||||
|
|
||||||
|
roomToAdd.Id = LongRandom(1, idMax, rnd).ToString();
|
||||||
|
roomToAdd.Name = room.Name;
|
||||||
|
roomToAdd.CreatorId = userId;
|
||||||
|
roomToAdd.CreatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
var cRoom = await _dataContext.Rooms.FirstOrDefaultAsync(x => x.Name == roomToAdd.Name);
|
||||||
|
|
||||||
|
if (cRoom == null)
|
||||||
|
{
|
||||||
|
await _dataContext.Rooms.AddAsync(roomToAdd);
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = roomToAdd;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "Room already exists.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<Room>> DeleteRoom(string id)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<Room>();
|
||||||
|
var room = await _dataContext.Rooms.FirstOrDefaultAsync(x => x.Id == id);
|
||||||
|
|
||||||
|
if (room != null)
|
||||||
|
{
|
||||||
|
_dataContext.Rooms.Remove(room);
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = room;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "Room not found.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<List<Room>>> GetAllRooms()
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<List<Room>>();
|
||||||
|
var rooms = await _dataContext.Rooms.ToListAsync();
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = rooms;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<Room>> GetRoom(string id)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<Room>();
|
||||||
|
var room = await _dataContext.Rooms.FirstOrDefaultAsync(x => x.Id == id);
|
||||||
|
|
||||||
|
if (room != null)
|
||||||
|
{
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = room;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "Room not found.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ServiceResponse<Room>> UpdateRoom(Room room)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private long LongRandom(long min, long max, Random rnd)
|
||||||
|
{
|
||||||
|
long result = rnd.Next((int)(min >> 32), (int)(max >> 32));
|
||||||
|
result = result << 32;
|
||||||
|
result = result | (long)rnd.Next((int)min, (int)max);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
qtc-net-server/Services/TokenService/ITokenService.cs
Normal file
10
qtc-net-server/Services/TokenService/ITokenService.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace qtc_api.Services.TokenService
|
||||||
|
{
|
||||||
|
public interface ITokenService
|
||||||
|
{
|
||||||
|
public Task<ServiceResponse<string>> GenerateAccessTokenAndRefreshToken(User user, bool generateRefToken = true, bool remember = false);
|
||||||
|
public Task<ServiceResponse<bool>> ValidateAccessToken(string accessToken);
|
||||||
|
public Task<ServiceResponse<string>> ValidateRefreshToken(string refreshToken);
|
||||||
|
public ServiceResponse<TokenValidationParameters> GetValidationParams();
|
||||||
|
}
|
||||||
|
}
|
||||||
176
qtc-net-server/Services/TokenService/TokenService.cs
Normal file
176
qtc-net-server/Services/TokenService/TokenService.cs
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
|
namespace qtc_api.Services.TokenService
|
||||||
|
{
|
||||||
|
public class TokenService : ITokenService
|
||||||
|
{
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
private readonly DataContext _dataContext;
|
||||||
|
|
||||||
|
public TokenService(IConfiguration configuration, DataContext dataContext)
|
||||||
|
{
|
||||||
|
_configuration = configuration;
|
||||||
|
_dataContext = dataContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<string>> GenerateAccessTokenAndRefreshToken(User user, bool generateRefToken, bool remember)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<string>();
|
||||||
|
|
||||||
|
// Generate JWT Access Token
|
||||||
|
|
||||||
|
List<Claim> claims = new List<Claim>()
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.Hash, user.Id),
|
||||||
|
new Claim(ClaimTypes.Name, user.Username),
|
||||||
|
new Claim(ClaimTypes.Email, user.Email),
|
||||||
|
new Claim(ClaimTypes.Role, user.Role)
|
||||||
|
};
|
||||||
|
|
||||||
|
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration.GetSection("Jwt:Key").Value!));
|
||||||
|
var issuer = _configuration["Jwt:Issuer"];
|
||||||
|
var audience = _configuration["Jwt:Audience"];
|
||||||
|
|
||||||
|
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||||
|
|
||||||
|
var token = new JwtSecurityToken(
|
||||||
|
issuer: issuer,
|
||||||
|
audience: audience,
|
||||||
|
claims: claims,
|
||||||
|
expires: DateTime.UtcNow.AddHours(1),
|
||||||
|
signingCredentials: creds
|
||||||
|
);
|
||||||
|
|
||||||
|
var jwt = new JwtSecurityTokenHandler().WriteToken(token);
|
||||||
|
|
||||||
|
serviceResponse.Data = jwt;
|
||||||
|
|
||||||
|
// Generate and Store Refresh Token
|
||||||
|
|
||||||
|
if (generateRefToken)
|
||||||
|
{
|
||||||
|
var random = new byte[32];
|
||||||
|
using (var rng = RandomNumberGenerator.Create())
|
||||||
|
{
|
||||||
|
rng.GetBytes(random);
|
||||||
|
}
|
||||||
|
|
||||||
|
RefreshToken refToken = new RefreshToken()
|
||||||
|
{
|
||||||
|
ID = LongRandom(1, 900000000000000000, new Random()).ToString(),
|
||||||
|
UserID = user.Id,
|
||||||
|
Token = Convert.ToBase64String(random)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (remember) refToken.Expires = DateTime.UtcNow.AddDays(7);
|
||||||
|
else refToken.Expires = DateTime.UtcNow.AddDays(1);
|
||||||
|
|
||||||
|
_dataContext.ValidRefreshTokens.Add(refToken);
|
||||||
|
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
serviceResponse.Message = refToken.Token;
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<string>> ValidateRefreshToken(string refreshToken)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<string>();
|
||||||
|
|
||||||
|
var dbRefresh = await _dataContext.ValidRefreshTokens.FirstOrDefaultAsync(x => x.Token == refreshToken);
|
||||||
|
|
||||||
|
if (dbRefresh != null)
|
||||||
|
{
|
||||||
|
if (dbRefresh.Expires < DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "Refresh Token Expired.";
|
||||||
|
|
||||||
|
// Handle Expired Refresh Token
|
||||||
|
|
||||||
|
_dataContext.ValidRefreshTokens.Remove(dbRefresh);
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == dbRefresh.UserID);
|
||||||
|
|
||||||
|
if (user != null && dbRefresh.UserID == user.Id)
|
||||||
|
{
|
||||||
|
var token = await GenerateAccessTokenAndRefreshToken(user, false, false);
|
||||||
|
|
||||||
|
if (token != null)
|
||||||
|
{
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = token.Data;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "Requesting User ID and the associated Refresh Token's User ID does not match.";
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "Invalid Refresh Token.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<bool>> ValidateAccessToken(string accessToken)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<bool>();
|
||||||
|
|
||||||
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
var validationParams = GetValidationParams();
|
||||||
|
|
||||||
|
TokenValidationResult result = await tokenHandler.ValidateTokenAsync(accessToken, validationParams.Data);
|
||||||
|
|
||||||
|
if (result.IsValid)
|
||||||
|
{
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = true;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = false;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceResponse<TokenValidationParameters> GetValidationParams()
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<TokenValidationParameters>();
|
||||||
|
|
||||||
|
serviceResponse.Data = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidIssuer = _configuration["Jwt:Issuer"],
|
||||||
|
ValidAudience = _configuration["Jwt:Audience"],
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]!))
|
||||||
|
};
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long LongRandom(long min, long max, Random rnd)
|
||||||
|
{
|
||||||
|
long result = rnd.Next((int)(min >> 32), (int)(max >> 32));
|
||||||
|
result = result << 32;
|
||||||
|
result = result | (long)rnd.Next((int)min, (int)max);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
qtc-net-server/Services/UserService/IUserService.cs
Normal file
19
qtc-net-server/Services/UserService/IUserService.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using qtc_api.Dtos.User;
|
||||||
|
|
||||||
|
namespace qtc_api.Services.UserService
|
||||||
|
{
|
||||||
|
public interface IUserService
|
||||||
|
{
|
||||||
|
public Task<ServiceResponse<User>> GetUserById(string id);
|
||||||
|
public Task<ServiceResponse<UserInformationDto>> GetUserInformationById(string id);
|
||||||
|
public Task<ServiceResponse<User>> GetUserByEmail(string email);
|
||||||
|
public Task<ServiceResponse<List<UserInformationDto>>> GetAllUsers();
|
||||||
|
public Task<ServiceResponse<List<UserInformationDto>>> GetAllOnlineUsers();
|
||||||
|
public Task<ServiceResponse<User>> AddUser(UserDto userReq);
|
||||||
|
public Task<ServiceResponse<UserInformationDto>> UpdateUserInfo(UserUpdateInformationDto request);
|
||||||
|
public Task<ServiceResponse<string>> UpdateUserPic(string userId, IFormFile file);
|
||||||
|
public Task<ServiceResponse<FileContentResult>> GetUserPic(string userId);
|
||||||
|
public Task<ServiceResponse<UserStatusDto>> UpdateStatus(UserStatusDto request);
|
||||||
|
public Task<ServiceResponse<User>> DeleteUser(string id);
|
||||||
|
}
|
||||||
|
}
|
||||||
340
qtc-net-server/Services/UserService/UserService.cs
Normal file
340
qtc-net-server/Services/UserService/UserService.cs
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
namespace qtc_api.Services.UserService
|
||||||
|
{
|
||||||
|
public class UserService : IUserService
|
||||||
|
{
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
private readonly DataContext _dataContext;
|
||||||
|
|
||||||
|
private long idMax = 900000000000000000;
|
||||||
|
|
||||||
|
public UserService(IConfiguration configuration, DataContext dataContext)
|
||||||
|
{
|
||||||
|
_configuration = configuration;
|
||||||
|
_dataContext = dataContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<User>> AddUser(UserDto userReq)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<User>();
|
||||||
|
var userList = await _dataContext.Users.ToListAsync();
|
||||||
|
|
||||||
|
var user = new User();
|
||||||
|
Random rnd = new Random();
|
||||||
|
var id = LongRandom(1, idMax, rnd);
|
||||||
|
|
||||||
|
user.Id = id.ToString();
|
||||||
|
user.Username = userReq.Username;
|
||||||
|
user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(userReq.Password);
|
||||||
|
user.Email = userReq.Email;
|
||||||
|
user.DateOfBirth = userReq.DateOfBirth;
|
||||||
|
user.Role = _configuration["Jwt:DefaultUserRole"]!;
|
||||||
|
user.CreatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var cUser = userList.FirstOrDefault(x => x.Email == user.Email);
|
||||||
|
|
||||||
|
if (cUser != null)
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User with that email already exists.";
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _dataContext.Users.AddAsync(user);
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
userList = await _dataContext.Users.ToListAsync();
|
||||||
|
|
||||||
|
if (userList.Contains(user))
|
||||||
|
{
|
||||||
|
var createdUser = await _dataContext.Users.FindAsync(user.Id);
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = createdUser;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User not created.";
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = ex.Message;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<User>> DeleteUser(string id)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<User>();
|
||||||
|
var user = _dataContext.Users.FirstOrDefault(x => x.Id == id)!;
|
||||||
|
|
||||||
|
if(user != null)
|
||||||
|
{
|
||||||
|
_dataContext.Users.Remove(user);
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = user;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User not found.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<List<UserInformationDto>>> GetAllUsers()
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<List<UserInformationDto>>();
|
||||||
|
var userList = await _dataContext.Users.ToListAsync();
|
||||||
|
|
||||||
|
var userInfoList = new List<UserInformationDto>();
|
||||||
|
foreach(var user in userList)
|
||||||
|
{
|
||||||
|
var x = new UserInformationDto();
|
||||||
|
|
||||||
|
x.Id = user.Id;
|
||||||
|
x.Username = user.Username;
|
||||||
|
x.ProfilePicture = user.ProfilePicture;
|
||||||
|
x.Role = user.Role;
|
||||||
|
x.Bio = user.Bio;
|
||||||
|
x.DateOfBirth = user.DateOfBirth;
|
||||||
|
|
||||||
|
userInfoList.Add(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = userInfoList;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<List<UserInformationDto>>> GetAllOnlineUsers()
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<List<UserInformationDto>>();
|
||||||
|
var onlineUsers = new List<UserInformationDto>();
|
||||||
|
|
||||||
|
await _dataContext.Users.ForEachAsync(user =>
|
||||||
|
{
|
||||||
|
if (user.Status == 1 || user.Status == 2 || user.Status == 3)
|
||||||
|
{
|
||||||
|
var x = new UserInformationDto();
|
||||||
|
|
||||||
|
x.Id = user.Id;
|
||||||
|
x.Username = user.Username;
|
||||||
|
x.ProfilePicture = user.ProfilePicture;
|
||||||
|
x.Role = user.Role;
|
||||||
|
x.Bio = user.Bio;
|
||||||
|
x.Status = user.Status;
|
||||||
|
x.DateOfBirth = user.DateOfBirth;
|
||||||
|
x.CreatedAt = user.CreatedAt;
|
||||||
|
|
||||||
|
onlineUsers.Add(x);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = onlineUsers;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<User>> GetUserById(string id)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<User>();
|
||||||
|
var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == id);
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = user;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<UserInformationDto>> GetUserInformationById(string id)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<UserInformationDto>();
|
||||||
|
var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == id);
|
||||||
|
|
||||||
|
if(user != null)
|
||||||
|
{
|
||||||
|
var dto = new UserInformationDto();
|
||||||
|
|
||||||
|
dto.Id = user.Id;
|
||||||
|
dto.Username = user.Username;
|
||||||
|
dto.ProfilePicture = user.ProfilePicture;
|
||||||
|
dto.Role = user.Role;
|
||||||
|
dto.Bio = user.Bio;
|
||||||
|
dto.DateOfBirth = user.DateOfBirth;
|
||||||
|
dto.CreatedAt = user.CreatedAt;
|
||||||
|
dto.Status = user.Status;
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = dto;
|
||||||
|
return serviceResponse;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User not found.";
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<User>> GetUserByEmail(string email)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<User>();
|
||||||
|
var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.Email == email);
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = user;
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<UserInformationDto>> UpdateUserInfo(UserUpdateInformationDto request)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<UserInformationDto>();
|
||||||
|
var dbUser = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == request.Id);
|
||||||
|
|
||||||
|
if(dbUser != null)
|
||||||
|
{
|
||||||
|
dbUser.Username = request.Username;
|
||||||
|
dbUser.Bio = request.Bio;
|
||||||
|
dbUser.DateOfBirth = request.DateOfBirth;
|
||||||
|
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
var infoDto = new UserInformationDto();
|
||||||
|
|
||||||
|
infoDto.Id = dbUser.Id;
|
||||||
|
infoDto.Username = request.Username;
|
||||||
|
infoDto.ProfilePicture = dbUser.ProfilePicture;
|
||||||
|
infoDto.Bio = request.Bio;
|
||||||
|
infoDto.Role = dbUser.Role;
|
||||||
|
infoDto.DateOfBirth = request.DateOfBirth;
|
||||||
|
infoDto.CreatedAt = dbUser.CreatedAt;
|
||||||
|
infoDto.Status = dbUser.Status;
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = infoDto;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User not found.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<string>> UpdateUserPic(string userId, IFormFile file)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<string>();
|
||||||
|
|
||||||
|
var userToUpdate = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == userId);
|
||||||
|
var cdnPath = _configuration["GeneralConfig:CDNPath"];
|
||||||
|
|
||||||
|
if (userToUpdate == null)
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User Not Found.";
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file != null && file.Length > 0)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(cdnPath)) Directory.CreateDirectory(cdnPath!);
|
||||||
|
if (!Directory.Exists($"{cdnPath}/{userId}")) Directory.CreateDirectory($"{cdnPath}/{userId}");
|
||||||
|
|
||||||
|
var fileName = $"{userId}.{file.FileName.Split('.')[1]}";
|
||||||
|
var filePath = Path.Combine(cdnPath!, userId, fileName);
|
||||||
|
|
||||||
|
using (var stream = File.Create(filePath))
|
||||||
|
{
|
||||||
|
await file.CopyToAsync(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
userToUpdate.ProfilePicture = fileName;
|
||||||
|
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = fileName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "Empty File.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<FileContentResult>> GetUserPic(string userId)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<FileContentResult>();
|
||||||
|
|
||||||
|
var user = await _dataContext.Users.FirstOrDefaultAsync(x => x.Id == userId);
|
||||||
|
var cdnPath = _configuration["GeneralConfig:CDNPath"];
|
||||||
|
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
if (user.ProfilePicture != null)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(cdnPath))
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User Content Folder Does Not Exist Yet.";
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pic = Path.Combine(cdnPath, userId, user.ProfilePicture);
|
||||||
|
|
||||||
|
if (!File.Exists(pic))
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User Does Not Have A Profile Picture.";
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Message = user.ProfilePicture;
|
||||||
|
|
||||||
|
serviceResponse.Data = new FileContentResult(File.ReadAllBytes(pic), $"image/{Path.GetExtension(pic)}");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User Does Not Have A Profile Picture.";
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
serviceResponse.Success = false;
|
||||||
|
serviceResponse.Message = "User Not Found.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ServiceResponse<UserStatusDto>> UpdateStatus(UserStatusDto request)
|
||||||
|
{
|
||||||
|
var serviceResponse = new ServiceResponse<UserStatusDto>();
|
||||||
|
var user = _dataContext.Users.FirstOrDefault(x => x.Id == request.Id)!;
|
||||||
|
|
||||||
|
user.Status = request.Status;
|
||||||
|
|
||||||
|
await _dataContext.SaveChangesAsync();
|
||||||
|
|
||||||
|
serviceResponse.Success = true;
|
||||||
|
serviceResponse.Data = request;
|
||||||
|
|
||||||
|
return serviceResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long LongRandom(long min, long max, Random rnd)
|
||||||
|
{
|
||||||
|
long result = rnd.Next((int)(min >> 32), (int)(max >> 32));
|
||||||
|
result = result << 32;
|
||||||
|
result = result | (long)rnd.Next((int)min, (int)max);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
qtc-net-server/appsettings.Development.json
Normal file
8
qtc-net-server/appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Debug",
|
||||||
|
"Microsoft.AspNetCore": "Debug"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
22
qtc-net-server/appsettings.json
Normal file
22
qtc-net-server/appsettings.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"Jwt": {
|
||||||
|
"Key": "bgpLLhY2L2UeZN3sj6WwSzScFmY3JgWfs33ZEJNcaPzC2TEnfZz",
|
||||||
|
"Issuer": "http://localhost",
|
||||||
|
"Audience": "http://localhost",
|
||||||
|
"DefaultUserRole": "User"
|
||||||
|
},
|
||||||
|
"ConnectionStrings": {
|
||||||
|
"DefaultConnection": "Server=db;Database=qtcdb;Uid=root;Pwd=EuK3pXkaPCR9cW",
|
||||||
|
"DevelopmentConnection": "Data Source=qtcdev.db"
|
||||||
|
},
|
||||||
|
"GeneralConfig": {
|
||||||
|
"CDNPath": "./user-content"
|
||||||
|
},
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
||||||
5
qtc-net-server/libman.json
Normal file
5
qtc-net-server/libman.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0",
|
||||||
|
"defaultProvider": "cdnjs",
|
||||||
|
"libraries": []
|
||||||
|
}
|
||||||
37
qtc-net-server/qtc-net-server.csproj
Normal file
37
qtc-net-server/qtc-net-server.csproj
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<RootNamespace>qtc_api</RootNamespace>
|
||||||
|
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||||
|
<DockerComposeProjectPath>..\docker-compose.dcproj</DockerComposeProjectPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.5" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.5" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.5" />
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.5" />
|
||||||
|
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.10.0" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
|
||||||
|
<PackageReference Include="MySql.EntityFrameworkCore" Version="9.0.3" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||||
|
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.3" />
|
||||||
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.10.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Update="ServerConfig.json">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
2
qtc-net-server/run.Development.bat
Normal file
2
qtc-net-server/run.Development.bat
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
dotnet run --project qtc-net-server.csproj -lp http -e ASPNETCORE_ENVIRONMENT="Development"
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 245 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 245 KiB |
Loading…
x
Reference in New Issue
Block a user