ceshi
This commit is contained in:
commit
2183073421
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
|
||||
363
.gitignore
vendored
Normal file
363
.gitignore
vendored
Normal file
@ -0,0 +1,363 @@
|
||||
## 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
|
||||
31
Dockerfile
Normal file
31
Dockerfile
Normal file
@ -0,0 +1,31 @@
|
||||
#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
|
||||
USER app
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
# ¸´ÖÆËùÓеÄÏîÄ¿Îļþ
|
||||
COPY ["LMS.service/LMS.service.csproj", "LMS.service/"]
|
||||
COPY ["LMS.Common/LMS.Common.csproj", "LMS.Common/"]
|
||||
COPY ["LMS.DAO/LMS.DAO.csproj", "LMS.DAO/"]
|
||||
COPY ["LMS.Repository/LMS.Repository.csproj", "LMS.Repository/"]
|
||||
COPY ["LMS.Tools/LMS.Tools.csproj", "LMS.Tools/"]
|
||||
|
||||
RUN dotnet restore "LMS.service/LMS.service.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/LMS.service"
|
||||
RUN dotnet build "LMS.service.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "LMS.service.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "LMS.service.dll"]
|
||||
13
LMS.Common/Attributes/DescriptionAttribute.cs
Normal file
13
LMS.Common/Attributes/DescriptionAttribute.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace LMS.Common.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class DescriptionAttribute : Attribute
|
||||
{
|
||||
public string Description { get; set; }
|
||||
|
||||
public DescriptionAttribute(string description)
|
||||
{
|
||||
Description = description;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
LMS.Common/Attributes/ResultAttribute.cs
Normal file
13
LMS.Common/Attributes/ResultAttribute.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace LMS.Common.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class ResultAttribute : Attribute
|
||||
{
|
||||
public string Result { get; set; }
|
||||
|
||||
public ResultAttribute(string result)
|
||||
{
|
||||
Result = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
LMS.Common/Enum/MachineEnum.cs
Normal file
31
LMS.Common/Enum/MachineEnum.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using LMS.Common.Attributes;
|
||||
|
||||
namespace LMS.Common.Enums
|
||||
{
|
||||
public class MachineEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 机器码使用状态
|
||||
/// </summary>
|
||||
public enum MachineUseStatus
|
||||
{
|
||||
[Description("试用")]
|
||||
Trial = 0,
|
||||
|
||||
[Description("永久")]
|
||||
Permanent = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 机器码状态
|
||||
/// </summary>
|
||||
public enum MachineStatus
|
||||
{
|
||||
[Description("激活")]
|
||||
Active = 1,
|
||||
|
||||
[Description("冻结")]
|
||||
Frozen = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
41
LMS.Common/Enum/PermissionEnum.cs
Normal file
41
LMS.Common/Enum/PermissionEnum.cs
Normal file
@ -0,0 +1,41 @@
|
||||
|
||||
|
||||
using LMS.Common.Attributes;
|
||||
|
||||
namespace LMS.Common.Enums
|
||||
{
|
||||
public class PermissionEnum
|
||||
{
|
||||
public enum PermissionType
|
||||
{
|
||||
[Description("用户权限")]
|
||||
User = 1,
|
||||
|
||||
[Description("机器码权限")]
|
||||
Machine = 2,
|
||||
|
||||
[Description("角色权限")]
|
||||
Role = 3,
|
||||
|
||||
[Description("提示词类型")]
|
||||
Prompt = 4,
|
||||
|
||||
[Description("权限类型权限")]
|
||||
PermissionType = 5,
|
||||
|
||||
[Description("权限权限")]
|
||||
Permission = 6,
|
||||
|
||||
[Description("其他权限")]
|
||||
Custom = 100
|
||||
|
||||
}
|
||||
|
||||
public enum PType
|
||||
{
|
||||
User = 1,
|
||||
Machine = 2,
|
||||
Role = 3,
|
||||
}
|
||||
}
|
||||
}
|
||||
49
LMS.Common/Enum/PromptEnum.cs
Normal file
49
LMS.Common/Enum/PromptEnum.cs
Normal file
@ -0,0 +1,49 @@
|
||||
namespace LMS.Common.Enums
|
||||
{
|
||||
public class PromptEnum
|
||||
{
|
||||
public enum PromptType
|
||||
{
|
||||
/// <summary>
|
||||
/// 开头提示词
|
||||
/// </summary>
|
||||
StartPrompt = 0,
|
||||
}
|
||||
|
||||
public class PromptStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 提示词状态:启用
|
||||
/// </summary>
|
||||
public const string Enable = "enable";
|
||||
///
|
||||
/// <summary>
|
||||
///提示词状态:禁用
|
||||
/// </summary>
|
||||
public const string Disable = "disable";
|
||||
}
|
||||
|
||||
public class PromptTypeStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// 提示词类型状态:启用
|
||||
/// </summary>
|
||||
public const string Enable = "enable";
|
||||
///
|
||||
/// <summary>
|
||||
///提示词类型状态:禁用
|
||||
/// </summary>
|
||||
public const string Disable = "disable";
|
||||
|
||||
/// <summary>
|
||||
/// 所有有效的提示词类型状态
|
||||
/// </summary>
|
||||
public static readonly HashSet<string> ValidStatuses = new HashSet<string>
|
||||
{
|
||||
Enable,
|
||||
Disable
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
198
LMS.Common/Enum/ResponseCodeEnum.cs
Normal file
198
LMS.Common/Enum/ResponseCodeEnum.cs
Normal file
@ -0,0 +1,198 @@
|
||||
using LMS.Common.Attributes;
|
||||
|
||||
namespace LMS.Common.Enums
|
||||
{
|
||||
public class ResponseCodeEnum
|
||||
{
|
||||
public enum ResponseCode
|
||||
{
|
||||
#region 成功
|
||||
|
||||
[Result("请求成功")]
|
||||
[Description("请求成功")]
|
||||
Success = 1,
|
||||
|
||||
#endregion
|
||||
|
||||
#region User 操作失败
|
||||
|
||||
[Result(ResponseString.UndefinedLoginType)]
|
||||
[Description(ResponseString.UndefinedLoginType)]
|
||||
UndefinedLoginType = 1000,
|
||||
|
||||
[Result(ResponseString.UserNotFound)]
|
||||
[Description("未找到对应用户名的账号")]
|
||||
FindUserByNameFail = 1001,
|
||||
|
||||
[Result(ResponseString.UserPasswordError)]
|
||||
[Description("用户密码错误")]
|
||||
UserPasswordFail = 1002,
|
||||
|
||||
[Result(ResponseString.IdDateNotFound)]
|
||||
[Description("指定ID的用户不存在")]
|
||||
FindUserByIdFail = 1003,
|
||||
|
||||
[Result(ResponseString.UserStatusError)]
|
||||
[Description("用户的状态错误,只能状态为正常的用户可以登录")]
|
||||
UserStatusError = 1004,
|
||||
|
||||
|
||||
[Result("指定邮箱的用户已经存在")]
|
||||
[Description("指定邮箱的用户已经存在")]
|
||||
UserEmailExist = 1005,
|
||||
|
||||
[Result("指定手机号的用户已经存在")]
|
||||
[Description("指定手机号的用户已经存在")]
|
||||
UserPhoneExist = 1006,
|
||||
|
||||
[Result("指定邮箱或手机号的用户已经存在")]
|
||||
[Description("指定邮箱或手机号的用户已经存在")]
|
||||
UserEmailOrPhoneExist = 1007,
|
||||
|
||||
[Result("指定的用户名已存在")]
|
||||
[Description("指定的用户名已存在")]
|
||||
UasrNameExist = 1008,
|
||||
|
||||
[Result("指定的用户昵称已存在")]
|
||||
[Description("指定的用户昵称已存在")]
|
||||
UserNickNameExist = 1009,
|
||||
|
||||
[Result(ResponseString.UserIsLockedOut)]
|
||||
[Description(ResponseString.UserIsLockedOut)]
|
||||
UserIsLockedOut = 1010,
|
||||
|
||||
[Result(ResponseString.UserLoginOut)]
|
||||
[Description("用户的刷新令牌无效,可能是二次登录,或者是登录到期,请重新登录")]
|
||||
RefreshTokenInvalid = 1011,
|
||||
|
||||
[Result("用户注册失败")]
|
||||
[Description("用户注册失败")]
|
||||
UserRegisterFial = 1012,
|
||||
|
||||
[Result("用户不是VIP用户")]
|
||||
[Description("用户不是VIP用户")]
|
||||
UserNotVip = 1013,
|
||||
|
||||
[Result("无效的邀请码")]
|
||||
[Description("无效的邀请码")]
|
||||
InvalidAffiliateCode = 1014,
|
||||
|
||||
#endregion
|
||||
|
||||
#region Machine 操作失败
|
||||
|
||||
[Result(ResponseString.MachineStatusNotFoundOrStatusIsNot)]
|
||||
[Description(ResponseString.MachineStatusNotFoundOrStatusIsNot)]
|
||||
MachineNotFound = 2001,
|
||||
|
||||
[Result(ResponseString.IdDateNotFound)]
|
||||
[Description("指定ID的机器码不存在")]
|
||||
FindMachineByIdFail = 2002,
|
||||
|
||||
[Result(ResponseString.DataExist)]
|
||||
[Description("指定机器码已经存在")]
|
||||
MachineAlreadyExist = 2003,
|
||||
|
||||
#endregion
|
||||
|
||||
#region PermissionType 操作失败
|
||||
|
||||
[Result(ResponseString.IdDateNotFound)]
|
||||
[Description("指定ID的权限分类没有找到")]
|
||||
FindPermissionTypeByIdFail = 3001,
|
||||
|
||||
[Result(ResponseString.DataExist)]
|
||||
[Description("指定ID的权限名称和编码已经存在")]
|
||||
PermissionTypeExist = 3002,
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 权限操作失败
|
||||
|
||||
[Result(ResponseString.NotPermissionAction)]
|
||||
[Description(ResponseString.NotPermissionAction)]
|
||||
NotPermissionAction = 4001,
|
||||
|
||||
[Result(ResponseString.DataExist)]
|
||||
[Description("指定用户ID和权限分类ID已存在,不可新增")]
|
||||
PermissionExist = 4002,
|
||||
|
||||
[Result(ResponseString.IdDateNotFound)]
|
||||
[Description("指定ID的权限没有找到")]
|
||||
FindPermissionByIdFail = 4003,
|
||||
|
||||
[Result("权限编码已存在,请检查")]
|
||||
[Description("权限编码已存在,请检查")]
|
||||
PermissionCodeExist = 4004,
|
||||
|
||||
#endregion
|
||||
|
||||
#region 系统报错
|
||||
|
||||
[Result(ResponseString.SystemError)]
|
||||
[Description(ResponseString.SystemError)]
|
||||
SystemError = 5000,
|
||||
|
||||
[Result(ResponseString.ParameterError)]
|
||||
[Description(ResponseString.ParameterError)]
|
||||
ParameterError = 5001,
|
||||
|
||||
[Result(ResponseString.InvalidOptions)]
|
||||
[Description(ResponseString.InvalidOptions)]
|
||||
InvalidOptions = 5002,
|
||||
#endregion
|
||||
|
||||
#region 提示词操作失败
|
||||
|
||||
[Result(ResponseString.DataExist)]
|
||||
[Description("指定的提示词已经存在")]
|
||||
PromptStringExist = 6001,
|
||||
|
||||
[Result(ResponseString.IdDateNotFound)]
|
||||
[Description("指定ID的提示词没有找到")]
|
||||
FindPromptStringFail = 6002,
|
||||
|
||||
#endregion
|
||||
|
||||
#region 提示词类型操作失败
|
||||
|
||||
[Result(ResponseString.DataExist)]
|
||||
[Description("指定的提示词的名称或者是编码已存在")]
|
||||
PromptTypeExist = 7001,
|
||||
|
||||
[Result(ResponseString.IdDateNotFound)]
|
||||
[Description("指定ID的提示词类型没有找到")]
|
||||
FindPromptTypeFail = 7002,
|
||||
#endregion
|
||||
|
||||
#region 文案转发失败
|
||||
|
||||
[Result(ResponseString.ForwardFail)]
|
||||
[Description("文案转发失败")]
|
||||
ForwardWordFail = 8001,
|
||||
|
||||
#endregion
|
||||
|
||||
#region 角色操作失败
|
||||
|
||||
[Result(ResponseString.DataExist)]
|
||||
[Description("指定的角色名称已经存在")]
|
||||
RoleNameExist = 9001,
|
||||
|
||||
[Result(ResponseString.IdDateNotFound)]
|
||||
[Description("指定ID的角色不存在")]
|
||||
FindRoleByIdFail = 9002,
|
||||
|
||||
[Result(ResponseString.DataNotExist)]
|
||||
[Description("指定编码的角色不存在")]
|
||||
FindRoleByCodeFail = 9003,
|
||||
|
||||
[Result(ResponseString.HasRelationship)]
|
||||
[Description("指定角色已经绑定了用户,无法删除")]
|
||||
RoleHasUser = 9004,
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
42
LMS.Common/Enum/ResponseString.cs
Normal file
42
LMS.Common/Enum/ResponseString.cs
Normal file
@ -0,0 +1,42 @@
|
||||
namespace LMS.Common.Enums
|
||||
{
|
||||
public static class ResponseString
|
||||
{
|
||||
#region 用户相关
|
||||
public const string UndefinedLoginType = "未知的登录类型";
|
||||
|
||||
public const string UserNotFound = "用户未找到,请先注册";
|
||||
|
||||
public const string UserIsLockedOut = "用户已被锁定,请联系管理员";
|
||||
|
||||
public const string UserPasswordError = "检查账号和密码是否正确";
|
||||
|
||||
public const string UserLoginOut = "用户已退出,请重新登录";
|
||||
|
||||
#endregion
|
||||
|
||||
public const string UserLogin = "检查账号和密码是否正确";
|
||||
public const string UserEmailNotFound = "未找到对应用户名/邮箱的账号";
|
||||
public const string UserStatusError = "用户的状态错误";
|
||||
|
||||
public const string MachineStatusNotFoundOrStatusIsNot = "未找到对应的机器码或者是机器码已过期,请联系开发或客服";
|
||||
|
||||
public const string SystemError = "系统错误";
|
||||
|
||||
public const string ParameterError = "参数错误";
|
||||
|
||||
public const string InvalidOptions = "无效的操作";
|
||||
|
||||
public const string IdDateNotFound = "指定ID的数据没有找到";
|
||||
|
||||
public const string DataExist = "数据已存在,不可新增";
|
||||
|
||||
public const string HasRelationship = "数据存在关联,请先删除关联";
|
||||
|
||||
public const string DataNotExist = "数据不存在,请检查";
|
||||
|
||||
public const string NotPermissionAction = "没有执行该操作的权限";
|
||||
|
||||
public const string ForwardFail = "转发失败";
|
||||
}
|
||||
}
|
||||
31
LMS.Common/Enum/UserStatus.cs
Normal file
31
LMS.Common/Enum/UserStatus.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using LMS.Common.Attributes;
|
||||
|
||||
namespace LMS.Common.Enums
|
||||
{
|
||||
public class UserStatus
|
||||
{
|
||||
public enum UserStatusEnum
|
||||
{
|
||||
[Description("正常")]
|
||||
Normal = 1,
|
||||
|
||||
[Description("禁用")]
|
||||
Disable = 0,
|
||||
|
||||
[Description("删除")]
|
||||
Delete = 2,
|
||||
|
||||
[Description("黑名单")]
|
||||
BlackList = 3,
|
||||
|
||||
[Description("未激活")]
|
||||
NotActive = 4,
|
||||
|
||||
[Description("违规")]
|
||||
Violation = 5,
|
||||
|
||||
[Description("未知")]
|
||||
Unknown = 6
|
||||
}
|
||||
}
|
||||
}
|
||||
9
LMS.Common/LMS.Common.csproj
Normal file
9
LMS.Common/LMS.Common.csproj
Normal file
@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
37
LMS.Common/RSAKey/AESGenerate.cs
Normal file
37
LMS.Common/RSAKey/AESGenerate.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace LMS.Common.RSAKey
|
||||
{
|
||||
public static class AESGenerate
|
||||
{
|
||||
|
||||
public static string Encrypt(string plainText, byte[] key, byte[] iv)
|
||||
{
|
||||
using Aes aesAlg = Aes.Create();
|
||||
aesAlg.Key = key;
|
||||
aesAlg.IV = iv; // 使用全零的IV,实际使用时应该使用随机IV
|
||||
|
||||
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
byte[] encrypted = encryptor.TransformFinalBlock(Encoding.UTF8.GetBytes(plainText), 0, plainText.Length);
|
||||
|
||||
return Convert.ToBase64String(encrypted);
|
||||
}
|
||||
|
||||
public static string Decrypt(string cipherText, byte[] key, byte[] iv)
|
||||
{
|
||||
using Aes aesAlg = Aes.Create();
|
||||
aesAlg.Key = key;
|
||||
aesAlg.IV = iv; // 使用全零的IV,需要与加密时使用的IV一致
|
||||
|
||||
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
byte[] cipher = Convert.FromBase64String(cipherText);
|
||||
byte[] decrypted = decryptor.TransformFinalBlock(cipher, 0, cipher.Length);
|
||||
|
||||
return Encoding.UTF8.GetString(decrypted);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
99
LMS.Common/RSAKey/ComplexKeyObfuscator.cs
Normal file
99
LMS.Common/RSAKey/ComplexKeyObfuscator.cs
Normal file
@ -0,0 +1,99 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace LMS.Common.RSAKey
|
||||
{
|
||||
/// <summary>
|
||||
/// 这是一个混淆器,用于对密钥进行混淆,以增加破解难度
|
||||
/// </summary>
|
||||
public static class ComplexKeyObfuscator
|
||||
{
|
||||
private const int SaltSize = 16;
|
||||
|
||||
/// <summary>
|
||||
/// 混淆方法
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public static byte[] Obfuscate(byte[] key)
|
||||
{
|
||||
if (key == null || key.Length == 0)
|
||||
throw new ArgumentException("Key cannot be null or empty");
|
||||
|
||||
byte[] salt = GenerateRandomSalt();
|
||||
byte[] obfuscatedKey = new byte[key.Length];
|
||||
Array.Copy(key, obfuscatedKey, key.Length);
|
||||
|
||||
// 多层混淆操作
|
||||
for (int i = 0; i < obfuscatedKey.Length; i++)
|
||||
{
|
||||
// 异或操作
|
||||
obfuscatedKey[i] ^= salt[i % salt.Length];
|
||||
obfuscatedKey[i] ^= (byte)((i * 17) % 256); // 使用质数17
|
||||
obfuscatedKey[i] ^= (byte)((obfuscatedKey.Length - i) % 256);
|
||||
|
||||
// 位移操作
|
||||
obfuscatedKey[i] = (byte)(((obfuscatedKey[i] << 3) | (obfuscatedKey[i] >> 5)) & 0xFF);
|
||||
|
||||
// 基于位置的置换
|
||||
int newPos = (i * 7 + 5) % obfuscatedKey.Length; // 使用质数7
|
||||
byte temp = obfuscatedKey[i];
|
||||
obfuscatedKey[i] = obfuscatedKey[newPos];
|
||||
obfuscatedKey[newPos] = temp;
|
||||
}
|
||||
|
||||
// 将salt和混淆后的密钥合并
|
||||
byte[] result = new byte[salt.Length + obfuscatedKey.Length];
|
||||
Array.Copy(salt, 0, result, 0, salt.Length);
|
||||
Array.Copy(obfuscatedKey, 0, result, salt.Length, obfuscatedKey.Length);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解决混淆方法
|
||||
/// </summary>
|
||||
/// <param name="obfuscatedData"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public static byte[] Deobfuscate(byte[] obfuscatedData)
|
||||
{
|
||||
if (obfuscatedData == null || obfuscatedData.Length <= SaltSize)
|
||||
throw new ArgumentException("Invalid obfuscated data");
|
||||
|
||||
byte[] salt = new byte[SaltSize];
|
||||
byte[] obfuscatedKey = new byte[obfuscatedData.Length - SaltSize];
|
||||
|
||||
Array.Copy(obfuscatedData, 0, salt, 0, SaltSize);
|
||||
Array.Copy(obfuscatedData, SaltSize, obfuscatedKey, 0, obfuscatedKey.Length);
|
||||
|
||||
// 反向多层混淆操作
|
||||
for (int i = obfuscatedKey.Length - 1; i >= 0; i--)
|
||||
{
|
||||
// 反向置换
|
||||
int newPos = (i * 7 + 5) % obfuscatedKey.Length;
|
||||
byte temp = obfuscatedKey[i];
|
||||
obfuscatedKey[i] = obfuscatedKey[newPos];
|
||||
obfuscatedKey[newPos] = temp;
|
||||
|
||||
// 反向位移操作
|
||||
obfuscatedKey[i] = (byte)(((obfuscatedKey[i] >> 3) | (obfuscatedKey[i] << 5)) & 0xFF);
|
||||
|
||||
// 反向异或操作
|
||||
obfuscatedKey[i] ^= (byte)((obfuscatedKey.Length - i) % 256);
|
||||
obfuscatedKey[i] ^= (byte)((i * 17) % 256);
|
||||
obfuscatedKey[i] ^= salt[i % salt.Length];
|
||||
}
|
||||
|
||||
return obfuscatedKey;
|
||||
}
|
||||
|
||||
private static byte[] GenerateRandomSalt()
|
||||
{
|
||||
using var rng = RandomNumberGenerator.Create();
|
||||
byte[] salt = new byte[SaltSize];
|
||||
rng.GetBytes(salt);
|
||||
return salt;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
LMS.Common/RSAKey/RSAKeyGenerateModel.cs
Normal file
19
LMS.Common/RSAKey/RSAKeyGenerateModel.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LMS.Common.RSAKey
|
||||
{
|
||||
public class RSAKeyGenerateModel
|
||||
{
|
||||
public string PublicKey { get; set; }
|
||||
|
||||
public string EncryptedPrivateKey { get; set; }
|
||||
|
||||
public string EncryptedKey { get; set; }
|
||||
|
||||
public string EncryptionIV { get; set; }
|
||||
}
|
||||
}
|
||||
131
LMS.Common/RSAKey/RsaKeyPairGenerator.cs
Normal file
131
LMS.Common/RSAKey/RsaKeyPairGenerator.cs
Normal file
@ -0,0 +1,131 @@
|
||||
using LMS.Common.RSAKey;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
namespace LMS.Common.RSAKey
|
||||
{
|
||||
public static class RsaKeyPairGenerator
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 初始化一个RSA密钥对
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static RSAKeyGenerateModel InitRsaKey()
|
||||
{
|
||||
using RSACryptoServiceProvider rsa = new(2048);
|
||||
string publicKeyPem = ExportPublicKeyToPem(rsa);
|
||||
string privateKeyPem = ExportPrivateKeyToPem(rsa);
|
||||
|
||||
// 随机生成一个AES密钥
|
||||
byte[] aesKey = GenerateRandomAesKey(32);
|
||||
byte[] aesIv = GenerateRandomAesKey(16);
|
||||
|
||||
// 通过随机的密钥开始AES加密私钥
|
||||
string encryptPrivateKey = AESGenerate.Encrypt(privateKeyPem, aesKey, aesIv);
|
||||
|
||||
return new RSAKeyGenerateModel
|
||||
{
|
||||
PublicKey = publicKeyPem,
|
||||
EncryptedPrivateKey = encryptPrivateKey,
|
||||
EncryptedKey = Convert.ToBase64String(ComplexKeyObfuscator.Obfuscate(aesKey)),
|
||||
EncryptionIV = Convert.ToBase64String(ComplexKeyObfuscator.Obfuscate(aesIv))
|
||||
};
|
||||
}
|
||||
|
||||
private static byte[] GenerateRandomAesKey(int bits)
|
||||
{
|
||||
using var randomNumberGenerator = RandomNumberGenerator.Create();
|
||||
var randomBytes = new byte[bits]; // 256 bits
|
||||
randomNumberGenerator.GetBytes(randomBytes);
|
||||
return randomBytes;
|
||||
}
|
||||
|
||||
public static void GenerateRsaKeyPair()
|
||||
{
|
||||
using RSACryptoServiceProvider rsa = new(2048);
|
||||
|
||||
string publicKeyPem = ExportPublicKeyToPem(rsa);
|
||||
string privateKeyPem = ExportPrivateKeyToPem(rsa);
|
||||
|
||||
Console.WriteLine("公钥 (PEM):\n" + publicKeyPem);
|
||||
Console.WriteLine("私钥 (PEM):\n" + privateKeyPem);
|
||||
|
||||
Console.WriteLine();
|
||||
string original = "Hello, RSA!";
|
||||
var encrypted = Encrypt(publicKeyPem, original);
|
||||
Console.WriteLine("Encrypted: " + encrypted);
|
||||
|
||||
Console.WriteLine();
|
||||
var decrypted = Decrypt(privateKeyPem, encrypted);
|
||||
Console.WriteLine("Decrypted: " + decrypted);
|
||||
|
||||
var signData = SignData(privateKeyPem, original);
|
||||
Console.WriteLine("SignData: " + signData);
|
||||
|
||||
var isVerify = VerifySignData(publicKeyPem, original, signData);
|
||||
Console.WriteLine("VerifySign: " + isVerify);
|
||||
}
|
||||
|
||||
private static string ExportPublicKeyToPem(RSA rsa)
|
||||
{
|
||||
var publicKey = rsa.ExportSubjectPublicKeyInfo();
|
||||
var base64 = Convert.ToBase64String(publicKey);
|
||||
return $"-----BEGIN PUBLIC KEY-----\n{InsertNewLines(base64)}\n-----END PUBLIC KEY-----";
|
||||
}
|
||||
|
||||
private static string ExportPrivateKeyToPem(RSA rsa)
|
||||
{
|
||||
var privateKey = rsa.ExportPkcs8PrivateKey();
|
||||
var base64 = Convert.ToBase64String(privateKey);
|
||||
return $"-----BEGIN PRIVATE KEY-----\n{InsertNewLines(base64)}\n-----END PRIVATE KEY-----";
|
||||
}
|
||||
|
||||
private static string InsertNewLines(string input)
|
||||
{
|
||||
return string.Join("\n", Enumerable.Range(0, input.Length / 64 + 1)
|
||||
.Select(i => input.Substring(i * 64, Math.Min(64, input.Length - i * 64))));
|
||||
}
|
||||
|
||||
public static string Encrypt(string publicKeyPem, string data)
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportFromPem(publicKeyPem);
|
||||
byte[] encryptedData = rsa.Encrypt(Encoding.UTF8.GetBytes(data), RSAEncryptionPadding.OaepSHA256);
|
||||
return Convert.ToBase64String(encryptedData);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Decrypt(string privateKeyPem, string data)
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportFromPem(privateKeyPem);
|
||||
byte[] decryptedData = rsa.Decrypt(Convert.FromBase64String(data), RSAEncryptionPadding.OaepSHA256);
|
||||
return Encoding.UTF8.GetString(decryptedData);
|
||||
}
|
||||
}
|
||||
|
||||
public static string SignData(string privateKeyPem, string data)
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportFromPem(privateKeyPem);
|
||||
var inputBytes = Encoding.UTF8.GetBytes(data);
|
||||
var resultBytes = rsa.SignData(inputBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
return Convert.ToBase64String(resultBytes);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool VerifySignData(string publicKeyPem, string data, string sign)
|
||||
{
|
||||
using (var rsa = RSA.Create())
|
||||
{
|
||||
rsa.ImportFromPem(publicKeyPem);
|
||||
var dataBytes = Encoding.UTF8.GetBytes(data);
|
||||
var signBytes = Convert.FromBase64String(sign);
|
||||
return rsa.VerifyData(dataBytes, signBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
46
LMS.DAO/ApplicationDbContext.cs
Normal file
46
LMS.DAO/ApplicationDbContext.cs
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
|
||||
using LMS.Repository.DB;
|
||||
using LMS.Repository.Models.DB;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace LMS.DAO
|
||||
{
|
||||
public class ApplicationDbContext : IdentityDbContext<User, Role, long>
|
||||
{
|
||||
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
|
||||
|
||||
//public DbSet<Prompt> Prompt { get; set; }
|
||||
|
||||
//public DbSet<PromptType> PromptType { get; set; }
|
||||
|
||||
public DbSet<Permission> Permission { get; set; }
|
||||
|
||||
public DbSet<PermissionType> PermissionType { get; set; }
|
||||
|
||||
public DbSet<Machine> Machine { get; set; }
|
||||
|
||||
public DbSet<RefreshTokens> RefreshTokens { get; set; }
|
||||
|
||||
public DbSet<ApiEndpoints> ApiEndpoints { get; set; }
|
||||
|
||||
public DbSet<RsaKeys> RsaKeys { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
modelBuilder.Entity<ApiEndpoints>()
|
||||
.Property(a => a.RequiredPermissionIds)
|
||||
.HasConversion(
|
||||
v => string.IsNullOrEmpty(JsonSerializer.Serialize(v, (JsonSerializerOptions?)null))
|
||||
? "[]" // 如果序列化结果为空,则存储空数组
|
||||
: JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
|
||||
v => string.IsNullOrEmpty(v) || v == "[]"
|
||||
? new List<string>() // 如果存储的是空字符串或空数组,则返回空列表
|
||||
: JsonSerializer.Deserialize<List<string>>(v, (JsonSerializerOptions?)null) ?? new List<string>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
LMS.DAO/LMS.DAO.csproj
Normal file
21
LMS.DAO/LMS.DAO.csproj
Normal file
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.8" />
|
||||
<PackageReference Include="OneOf" Version="3.0.271" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LMS.Common\LMS.Common.csproj" />
|
||||
<ProjectReference Include="..\LMS.Repository\LMS.Repository.csproj" />
|
||||
<ProjectReference Include="..\LMS.Tools\LMS.Tools.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
43
LMS.DAO/MachineDAO/MachineBasicDao.cs
Normal file
43
LMS.DAO/MachineDAO/MachineBasicDao.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LMS.DAO.MachineDAO
|
||||
{
|
||||
public class MachineBasicDao(ApplicationDbContext context)
|
||||
{
|
||||
private readonly ApplicationDbContext _context = context;
|
||||
|
||||
/// <summary>
|
||||
/// 检查机器码是否存在(机器码,不是对应的ID)
|
||||
/// </summary>
|
||||
/// <param name="machineId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CheckMachineByMachineId(string? machineId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(machineId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return await _context.Machine.AnyAsync(x => x.MachineId == machineId);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查机器码是否存在(机器码,对应的ID)
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CheckMachineById(string Id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return await _context.Machine.AnyAsync(x => x.Id == Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
26
LMS.DAO/MyDbcontextDesignFactory.cs
Normal file
26
LMS.DAO/MyDbcontextDesignFactory.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Design;
|
||||
|
||||
namespace LMS.DAO
|
||||
{
|
||||
public class MyDbcontextDesignFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
|
||||
{
|
||||
//public MyDbcontextDesignFactory CreateDbContext(string[] args)
|
||||
//{
|
||||
// DbContextOptionsBuilder<ApplicationDbContext> optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
|
||||
// string str = Environment.GetEnvironmentVariable("CONNECTION_STRING");
|
||||
// optionsBuilder.UseMySql(str, ServerVersion.Parse("8.0.18-mysql"));
|
||||
// ApplicationDbContext db = new ApplicationDbContext(optionsBuilder.Options);
|
||||
// return db;
|
||||
//}
|
||||
|
||||
public ApplicationDbContext CreateDbContext(string[] args)
|
||||
{
|
||||
DbContextOptionsBuilder<ApplicationDbContext> optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
|
||||
string str = "server=123.129.219.240;port=14080;user=luo;password=Luoqiang1405;database=LMS_TEST";
|
||||
optionsBuilder.UseMySql(str, ServerVersion.Parse("8.0.18-mysql"));
|
||||
ApplicationDbContext db = new ApplicationDbContext(optionsBuilder.Options);
|
||||
return db;
|
||||
}
|
||||
}
|
||||
}
|
||||
117
LMS.DAO/PermissionDAO/PermissionBasicDao.cs
Normal file
117
LMS.DAO/PermissionDAO/PermissionBasicDao.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using OneOf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static LMS.Common.Enums.PermissionEnum;
|
||||
|
||||
namespace LMS.DAO.PermissionDAO
|
||||
{
|
||||
public class PermissionBasicDao(ApplicationDbContext context)
|
||||
{
|
||||
private readonly ApplicationDbContext _context = context;
|
||||
|
||||
/// <summary>
|
||||
/// 判断指定的ID的权限是不是存在
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CheckPermissionExistById(string id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return await _context.Permission.AnyAsync(x => x.Id == id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断权限的PermissionCode是不是存在
|
||||
/// 通过判断是不是有传递ID , 判断是不是需要排除当前的数据
|
||||
/// </summary>
|
||||
/// <param name="permissionCode"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CheckPermissionCodeExist(string permissionCode, string id = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(permissionCode))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(permissionCode));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
return await _context.Permission.AnyAsync(x => x.PermissionCode == permissionCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
return await _context.Permission.AnyAsync(x => x.PermissionCode == permissionCode && x.Id != id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查对应分类的权限是不是存在
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="pid">再修改的时候必传这个值,用于判断对应的关联ID是不是有其他的值,有的话不能修改</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task<bool> CheckPermissionByTypeAndId(PType type, OneOf<string, long?> id, string pid = null)
|
||||
{
|
||||
if (id.IsT0)
|
||||
{
|
||||
if (type != PType.Machine)
|
||||
{
|
||||
throw new Exception("请检查参数的对应关系");
|
||||
}
|
||||
if (!string.IsNullOrEmpty(pid))
|
||||
{
|
||||
return await _context.Permission.AnyAsync(x => x.MachineId == id.AsT0 && x.Type == type && x.Id != pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return await _context.Permission.AnyAsync(x => x.MachineId == id.AsT0 && x.Type == type);
|
||||
}
|
||||
}
|
||||
else if (id.IsT1)
|
||||
{
|
||||
if (type == PType.Machine)
|
||||
{
|
||||
throw new Exception("请检查参数的对应关系");
|
||||
}
|
||||
if (id.AsT1 == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(pid))
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
PType.User => await _context.Permission.AnyAsync(x => x.UserId == id.AsT1 && x.Type == type && x.Id != pid),
|
||||
PType.Role => await _context.Permission.AnyAsync(x => x.RoleId == id.AsT1 && x.Type == type && x.Id != pid),
|
||||
PType.Machine => throw new Exception("请检查参数的对应关系"),
|
||||
_ => throw new Exception("参数类型错误"),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
PType.User => await _context.Permission.AnyAsync(x => x.UserId == id.AsT1 && x.Type == type),
|
||||
PType.Role => await _context.Permission.AnyAsync(x => x.RoleId == id.AsT1 && x.Type == type),
|
||||
PType.Machine => throw new Exception("请检查参数的对应关系"),
|
||||
_ => throw new Exception("参数类型错误"),
|
||||
};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("参数类型错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
55
LMS.DAO/PermissionDAO/PermissionTypeDao.cs
Normal file
55
LMS.DAO/PermissionDAO/PermissionTypeDao.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
|
||||
namespace LMS.DAO.PermissionDAO
|
||||
{
|
||||
public class PermissionTypeDao(ApplicationDbContext context)
|
||||
{
|
||||
private readonly ApplicationDbContext _context = context;
|
||||
|
||||
/// <summary>
|
||||
/// 判断权限类型ID数组中的数据是不是都存在数据库中
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CheckPermissionTypeIdsExist(List<string> ids)
|
||||
{
|
||||
foreach (var id in ids)
|
||||
{
|
||||
if (!await _context.PermissionType.AnyAsync(x => x.Id == id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查权限类型的Code是不是存在
|
||||
/// </summary>
|
||||
/// <param name="Code"></param>
|
||||
/// <param name="Id"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
public async Task<bool> CheckPermissionTypeCodeExist(string Code, string Id = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Code))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Code));
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
{
|
||||
return await _context.PermissionType.AnyAsync(x => x.Code == Code);
|
||||
}
|
||||
else
|
||||
{
|
||||
return await _context.PermissionType.AnyAsync(x => x.Code == Code && x.Id != Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
LMS.DAO/RoleDAO/RoleBasicDao.cs
Normal file
28
LMS.DAO/RoleDAO/RoleBasicDao.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using LMS.Repository.Models.DB;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LMS.DAO.RoleDAO
|
||||
{
|
||||
public class RoleBasicDao(ApplicationDbContext context, RoleManager<Role> roleManager)
|
||||
{
|
||||
private readonly ApplicationDbContext _context = context;
|
||||
private readonly RoleManager<Role> _roleManager = roleManager;
|
||||
|
||||
/// <summary>
|
||||
/// 检查角色是不是存在
|
||||
/// </summary>
|
||||
/// <param name="roleName"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CheckRoleExistById(long? roleId)
|
||||
{
|
||||
if (roleId == null)
|
||||
return false;
|
||||
return await _roleManager.FindByIdAsync(roleId.ToString()) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
LMS.DAO/UserDAO/UserBasicDAO.cs
Normal file
29
LMS.DAO/UserDAO/UserBasicDAO.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using LMS.Repository.Models.DB;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LMS.DAO.UserDAO
|
||||
{
|
||||
public class UserBasicDao(UserManager<User> userManager)
|
||||
{
|
||||
private readonly UserManager<User> _userManager = userManager;
|
||||
/// <summary>
|
||||
/// 检查用户是否存在,通过用户ID
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CheckUserExistsByID(long? userId)
|
||||
{
|
||||
if (userId == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return await _userManager.FindByIdAsync(userId.ToString()) != null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
22
LMS.Repository/DB/ApiEndpoints.cs
Normal file
22
LMS.Repository/DB/ApiEndpoints.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using LMS.Tools.Extensions;
|
||||
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
public class ApiEndpoints
|
||||
{
|
||||
|
||||
public string Id { get; set; }
|
||||
|
||||
public string HttpMethod { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; } = BeijingTimeExtension.GetBeijingTime();
|
||||
|
||||
public List<string> RequiredPermissionIds { get; set; }
|
||||
|
||||
public long CreatedId { get; set; }
|
||||
|
||||
public long UpdatedId { get; set; }
|
||||
}
|
||||
}
|
||||
62
LMS.Repository/DB/Machine.cs
Normal file
62
LMS.Repository/DB/Machine.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using static LMS.Common.Enums.MachineEnum;
|
||||
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
public class Machine
|
||||
{
|
||||
/// <summary>
|
||||
/// ID 主键
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 机器ID
|
||||
/// </summary>
|
||||
public string MachineId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 停用时间
|
||||
/// </summary>
|
||||
public DateTime? DeactivationTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态(是否可用)
|
||||
/// </summary>
|
||||
public MachineStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建者ID
|
||||
/// </summary>
|
||||
public long CreateId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新者ID
|
||||
/// </summary>
|
||||
public long UpdateId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用状态(试用,永久)
|
||||
/// </summary>
|
||||
public MachineUseStatus UseStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属用户ID
|
||||
/// </summary>
|
||||
public required long UserID { get; set; }
|
||||
}
|
||||
}
|
||||
82
LMS.Repository/DB/Permission.cs
Normal file
82
LMS.Repository/DB/Permission.cs
Normal file
@ -0,0 +1,82 @@
|
||||
using LMS.Common.Enums;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json;
|
||||
using static LMS.Common.Enums.PermissionEnum;
|
||||
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
/// <summary>
|
||||
/// 所有的权限集合
|
||||
/// </summary>
|
||||
public class Permission
|
||||
{
|
||||
/// <summary>
|
||||
/// 权限的ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户的ID
|
||||
/// </summary>
|
||||
public long? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 机器码的ID(是ID,不是机器码)
|
||||
/// </summary>
|
||||
public string? MachineId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 角色ID
|
||||
/// </summary>
|
||||
public long? RoleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限类型的ID(子权限)
|
||||
/// </summary>
|
||||
[Column(TypeName = "json")]
|
||||
public string PermissionTypeIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限对应的Code
|
||||
/// </summary>
|
||||
public string PermissionCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限类型
|
||||
/// </summary>
|
||||
public PType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建人ID
|
||||
/// </summary>
|
||||
public long CreateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新人ID
|
||||
/// </summary>
|
||||
public long UpdateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public List<string> PermissionTypeIdsJson
|
||||
{
|
||||
get => JsonSerializer.Deserialize<List<string>>(PermissionTypeIds) ?? [];
|
||||
set => PermissionTypeIds = JsonSerializer.Serialize(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
56
LMS.Repository/DB/PermissionType.cs
Normal file
56
LMS.Repository/DB/PermissionType.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using LMS.Common.Enums;
|
||||
using static LMS.Common.Enums.PermissionEnum;
|
||||
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
/// <summary>
|
||||
/// 存放权限的表
|
||||
/// </summary>
|
||||
public class PermissionType
|
||||
{
|
||||
/// <summary>
|
||||
/// 权限ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限的名字
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表示权限的代码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限的分类(user和machine)
|
||||
/// </summary>
|
||||
public PermissionEnum.PermissionType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建者ID
|
||||
/// </summary>
|
||||
public long CreateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新者ID
|
||||
/// </summary>
|
||||
public long UpdateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新权限的时间
|
||||
/// </summary>
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限的描述
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
}
|
||||
71
LMS.Repository/DB/Prompt.cs
Normal file
71
LMS.Repository/DB/Prompt.cs
Normal file
@ -0,0 +1,71 @@
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
public class Prompt
|
||||
{
|
||||
/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提示词预设的名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提示词的类型ID
|
||||
/// </summary>
|
||||
public string PromptTypeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提示词的类型编码
|
||||
/// </summary>
|
||||
public string PromptTypeCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提示词预设字符串
|
||||
/// </summary>
|
||||
public string PromptString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前版本
|
||||
/// </summary>
|
||||
public int Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 状态
|
||||
/// </summary>
|
||||
public string Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提示词的描述
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建者
|
||||
/// </summary>
|
||||
public string CreateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新者
|
||||
/// </summary>
|
||||
public string UpdateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
61
LMS.Repository/DB/PromptType.cs
Normal file
61
LMS.Repository/DB/PromptType.cs
Normal file
@ -0,0 +1,61 @@
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
/// <summary>
|
||||
/// 提示词类型的库
|
||||
/// </summary>
|
||||
public class PromptType
|
||||
{
|
||||
/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提示词类型编码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提示词类型名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提示词类型描述
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 提示词类型状态
|
||||
/// </summary>
|
||||
public string Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否删除
|
||||
/// </summary>
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建用户ID
|
||||
/// </summary>
|
||||
public string CreateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新者ID
|
||||
/// </summary>
|
||||
public string UpdateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
46
LMS.Repository/DB/RefreshTokens.cs
Normal file
46
LMS.Repository/DB/RefreshTokens.cs
Normal file
@ -0,0 +1,46 @@
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
public class RefreshTokens
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键 ID
|
||||
/// </summary>
|
||||
public required string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
/// </summary>
|
||||
public required long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Token
|
||||
/// </summary>
|
||||
public required string Token { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 到期时间
|
||||
/// </summary>
|
||||
public DateTime Expiration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是不是失效
|
||||
/// </summary>
|
||||
public Boolean Revoked { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上次校验IP
|
||||
/// </summary>
|
||||
public required string LastCheckIp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 设备信息,浏览器信息等
|
||||
/// </summary>
|
||||
public required string DeviceInfo { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
18
LMS.Repository/DB/Role.cs
Normal file
18
LMS.Repository/DB/Role.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
public class Role : IdentityRole<long>
|
||||
{
|
||||
public long CreatedUserId { get; set; }
|
||||
|
||||
public long UpdatedUserId { get; set; }
|
||||
|
||||
public DateTime CreatedTime { get; set; }
|
||||
|
||||
public DateTime UpdatedTime { get; set; }
|
||||
|
||||
public string? Remark { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
57
LMS.Repository/DB/RsaKeys.cs
Normal file
57
LMS.Repository/DB/RsaKeys.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using LMS.Tools.Extensions;
|
||||
|
||||
namespace LMS.Repository.DB
|
||||
{
|
||||
public class RsaKeys
|
||||
{
|
||||
/// <summary>
|
||||
/// ID 主键
|
||||
/// </summary>
|
||||
public required string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用次数
|
||||
/// </summary>
|
||||
public int UseCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 公钥
|
||||
/// </summary>
|
||||
public required string PublicKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 加密后的私钥
|
||||
/// </summary>
|
||||
public required string EncryptedPrivateKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 加密私钥的随机字符串
|
||||
/// </summary>
|
||||
public required string EncryptionKey { get; set; } // 加密私钥的随机字符串
|
||||
|
||||
/// <summary>
|
||||
/// 加密私钥的随机IV
|
||||
/// </summary>
|
||||
public required string EncryptionIV { get; set; } // 加密私钥的随机字符串
|
||||
|
||||
/// <summary>
|
||||
/// Key的版本
|
||||
/// </summary>
|
||||
public int KeyVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime CreatedTime { get; set; } = BeijingTimeExtension.GetBeijingTime();
|
||||
|
||||
/// <summary>
|
||||
/// 上次使用的时间
|
||||
/// </summary>
|
||||
public DateTime? LastUsed { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 到期时间
|
||||
/// </summary>
|
||||
public DateTime ExpirationTime { get; set; }
|
||||
}
|
||||
}
|
||||
69
LMS.Repository/DB/User.cs
Normal file
69
LMS.Repository/DB/User.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using LMS.Repository.User;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
public class User : IdentityUser<long>
|
||||
{
|
||||
[MaxLength(50)]
|
||||
public string NickName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 允许使用的机器码数量
|
||||
/// </summary>
|
||||
public long AllDeviceCount { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 代理分成比例
|
||||
/// </summary>
|
||||
public double AgentPercent { get; set; } = 0.00;
|
||||
|
||||
/// <summary>
|
||||
/// 免费修改机器码次数
|
||||
/// </summary>
|
||||
public long FreeCount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 用户的一些简单的操作
|
||||
/// </summary>
|
||||
[Column(TypeName = "json")]
|
||||
public string? Options { get; set; } = "{}";
|
||||
|
||||
[Column(TypeName = "datetime")]
|
||||
public DateTime CreatedDate { get; set; } = DateTime.Now;
|
||||
|
||||
[Column(TypeName = "datetime")]
|
||||
public DateTime UpdatedDate { get; set; } = DateTime.Now;
|
||||
|
||||
[Column(TypeName = "datetime")]
|
||||
public DateTime LastLoginDate { get; set; } = DateTime.Now;
|
||||
|
||||
public string? LastLoginIp { get; set; } = "";
|
||||
|
||||
public string? LastLoginDevice { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// 上级ID
|
||||
/// </summary>
|
||||
public long? ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 推广码
|
||||
/// </summary>
|
||||
public string AffiliateCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 实际使用的Options
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public UserPrivateOptions OptionsJson
|
||||
{
|
||||
get => JsonSerializer.Deserialize<UserPrivateOptions>(Options ?? "{}") ?? new UserPrivateOptions();
|
||||
set => Options = JsonSerializer.Serialize(value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
LMS.Repository/DB/UserRoles.cs
Normal file
11
LMS.Repository/DB/UserRoles.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace LMS.Repository.Models.DB
|
||||
{
|
||||
public class UserRoles
|
||||
{
|
||||
|
||||
public required string RoleId { get; set; }
|
||||
|
||||
public required string UserId { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
19
LMS.Repository/DTO/CollectionResponse.cs
Normal file
19
LMS.Repository/DTO/CollectionResponse.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LMS.Repository.DTO
|
||||
{
|
||||
public class CollectionResponse<T>
|
||||
{
|
||||
|
||||
public int Current { get; set; }
|
||||
|
||||
public int Total { get; set; }
|
||||
|
||||
public List<T> Collection { get; set; } = new List<T>();
|
||||
|
||||
}
|
||||
}
|
||||
14
LMS.Repository/DTO/MachineDetailDto.cs
Normal file
14
LMS.Repository/DTO/MachineDetailDto.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using LMS.Repository.DTO.UserDto;
|
||||
using LMS.Repository.Models.DB;
|
||||
|
||||
namespace LMS.Repository.DTO
|
||||
{
|
||||
public class MachineDetailDto : Machine
|
||||
{
|
||||
public UserBaseDto? CreatedUser { get; set; }
|
||||
|
||||
public UserBaseDto? UpdatedUser { get; set; }
|
||||
|
||||
public UserBaseDto? OwnUser { get; set; }
|
||||
}
|
||||
}
|
||||
30
LMS.Repository/DTO/MachineDto.cs
Normal file
30
LMS.Repository/DTO/MachineDto.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using static LMS.Common.Enums.MachineEnum;
|
||||
|
||||
namespace LMS.Repository.DTO.MachineResponse
|
||||
{
|
||||
public class MachineDto
|
||||
{
|
||||
public class MachineStatusResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// 机器状态
|
||||
/// </summary>
|
||||
public MachineStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 到期时间
|
||||
/// </summary>
|
||||
public DateTime? DeactivationTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 机器码ID
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 机器码
|
||||
/// </summary>
|
||||
public string MachineId { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
21
LMS.Repository/DTO/RoleDto.cs
Normal file
21
LMS.Repository/DTO/RoleDto.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using LMS.Repository.DTO.UserDto;
|
||||
|
||||
namespace LMS.Repository.DTO
|
||||
{
|
||||
public class RoleDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public UserBaseDto? CreatedUser { get; set; }
|
||||
|
||||
public UserBaseDto? UpdeatedUser { get; set; }
|
||||
|
||||
public DateTime CreatedTime { get; set; }
|
||||
|
||||
public DateTime UpdatedTime { get; set; }
|
||||
|
||||
public string Remark { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
10
LMS.Repository/DTO/SoftwareDao.cs
Normal file
10
LMS.Repository/DTO/SoftwareDao.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace LMS.Repository.DTO;
|
||||
|
||||
public class SoftwareDao
|
||||
{
|
||||
public string Version { get; set; }
|
||||
|
||||
public string Author { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
}
|
||||
44
LMS.Repository/DTO/UserDto/UserAgentInfoDto.cs
Normal file
44
LMS.Repository/DTO/UserDto/UserAgentInfoDto.cs
Normal file
@ -0,0 +1,44 @@
|
||||
namespace LMS.Repository.DTO.UserDto;
|
||||
|
||||
public class UserAgentInfoDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
/// </summary>
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名称
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户昵称
|
||||
/// </summary>
|
||||
public string NickName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户的邀请码
|
||||
/// </summary>
|
||||
public string AffiliateCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户的代理分成比例
|
||||
/// </summary>
|
||||
public double AgentPercent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邀请人数
|
||||
/// </summary>
|
||||
public int AffiliateNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邀请的VIP人数
|
||||
/// </summary>
|
||||
public int AffiliateVIPNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邀请获取的金额
|
||||
/// </summary>
|
||||
public double AffiliateMoney { get; set; }
|
||||
}
|
||||
18
LMS.Repository/DTO/UserDto/UserBaseDto.cs
Normal file
18
LMS.Repository/DTO/UserDto/UserBaseDto.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using LMS.Repository.User;
|
||||
|
||||
namespace LMS.Repository.DTO.UserDto;
|
||||
|
||||
public class UserBaseDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public string NickName { get; set; } = string.Empty;
|
||||
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
|
||||
public string Email { get; set; } = string.Empty;
|
||||
|
||||
public string PhoneNumber { get; set; } = string.Empty;
|
||||
|
||||
public string Avatar { get; set; } = string.Empty;
|
||||
}
|
||||
17
LMS.Repository/DTO/UserDto/UserCollectionDto.cs
Normal file
17
LMS.Repository/DTO/UserDto/UserCollectionDto.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace LMS.Repository.DTO.UserDto
|
||||
{
|
||||
public class UserCollectionDto : UserBaseDto
|
||||
{
|
||||
public List<string> RoleNames { get; set; } = [];
|
||||
|
||||
public DateTime CreatedDate { get; set; }
|
||||
|
||||
public DateTime LastLoginDate { get; set; }
|
||||
|
||||
public long ParentId { get; set; }
|
||||
|
||||
public string LastLoginIp { get; set; } = string.Empty;
|
||||
|
||||
public string LastLoginDevice { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
40
LMS.Repository/DTO/UserDto/UserDto.cs
Normal file
40
LMS.Repository/DTO/UserDto/UserDto.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using LMS.Repository.User;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace LMS.Repository.DTO.UserDto
|
||||
{
|
||||
public class UserDto : UserBaseDto
|
||||
{
|
||||
public List<string> RoleNames { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 允许使用的机器码数量
|
||||
/// </summary>
|
||||
public long AllDeviceCount { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 代理分成比例
|
||||
/// </summary>
|
||||
public double AgentPercent { get; set; } = 0.00;
|
||||
|
||||
/// <summary>
|
||||
/// 免费修改机器码次数
|
||||
/// </summary>
|
||||
public long FreeCount { get; set; } = 0;
|
||||
|
||||
public DateTime CreatedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 邀请码
|
||||
/// </summary>
|
||||
public string AffiliateCode { get; set; } = string.Empty;
|
||||
|
||||
public long ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 放一些操作信息 不能频繁的修改数据库,使用的json格式存放
|
||||
/// </summary>
|
||||
public UserPrivateOptions Options { get; set; } = new UserPrivateOptions();
|
||||
}
|
||||
}
|
||||
27
LMS.Repository/Forward/OpenAI.cs
Normal file
27
LMS.Repository/Forward/OpenAI.cs
Normal file
@ -0,0 +1,27 @@
|
||||
namespace LMS.Repository.Model
|
||||
{
|
||||
public class OpenAI
|
||||
{
|
||||
public class RequestMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求的角色
|
||||
/// </summary>
|
||||
public string role { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求的消息
|
||||
/// </summary>
|
||||
public string content { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求失败,返回错误信息
|
||||
/// </summary>
|
||||
public class ErrorResponse
|
||||
{
|
||||
public string Error { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
21
LMS.Repository/LMS.Repository.csproj
Normal file
21
LMS.Repository/LMS.Repository.csproj
Normal file
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Prompt\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Stores" Version="8.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LMS.Tools\LMS.Tools.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
42
LMS.Repository/Machine/MachineModel.cs
Normal file
42
LMS.Repository/Machine/MachineModel.cs
Normal file
@ -0,0 +1,42 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using static LMS.Common.Enums.MachineEnum;
|
||||
|
||||
namespace LMS.Repository.Models.Machine
|
||||
{
|
||||
public class MachineModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 机器ID
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string MachineId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 停用时间
|
||||
/// </summary>
|
||||
public DateTime? DeactivationTime { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 使用状态(试用,永久)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public MachineUseStatus UseStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前机器的状态(激活,冻结)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public MachineStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 所属用户ID
|
||||
/// </summary>
|
||||
public long? UserId { get; set; }
|
||||
}
|
||||
}
|
||||
47
LMS.Repository/Promission/PermissionModel.cs
Normal file
47
LMS.Repository/Promission/PermissionModel.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using static LMS.Common.Enums.PermissionEnum;
|
||||
|
||||
namespace LMS.Repository.RequestModel.Permission
|
||||
{
|
||||
public class PermissionModel
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 角色ID
|
||||
/// </summary>
|
||||
public long? RoleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户的ID
|
||||
/// </summary>
|
||||
public long? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 机器码的ID(是ID,不是机器码)
|
||||
/// </summary>
|
||||
public string? MachineId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限类型的ID(子权限)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public List<string> PermissionTypeIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限对应的Code
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string PermissionCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限类型
|
||||
/// </summary>
|
||||
[Required]
|
||||
public PType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
}
|
||||
}
|
||||
35
LMS.Repository/Promission/PermissionTypeModel.cs
Normal file
35
LMS.Repository/Promission/PermissionTypeModel.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using static LMS.Common.Enums.PermissionEnum;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace LMS.Repository.Models.Promission
|
||||
{
|
||||
public class PermissionTypeModel
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 权限的名字
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权限的分类(user和machine)
|
||||
/// </summary>
|
||||
[Required]
|
||||
public PermissionType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 表示权限的代码
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string Code { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 权限的描述
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
19
LMS.Repository/RSAKey/RSAKeyGenerateModel.cs
Normal file
19
LMS.Repository/RSAKey/RSAKeyGenerateModel.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LMS.Repository.RSAKey
|
||||
{
|
||||
public class RSAKeyGenerateModel
|
||||
{
|
||||
public string PublicKey { get; set; }
|
||||
|
||||
public string EncryptedPrivateKey { get; set; }
|
||||
|
||||
public string EncryptedKey { get; set; }
|
||||
|
||||
public string EncryptionIV { get; set; }
|
||||
}
|
||||
}
|
||||
17
LMS.Repository/Role/RoleModel.cs
Normal file
17
LMS.Repository/Role/RoleModel.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LMS.Repository.Role
|
||||
{
|
||||
public class RoleModel
|
||||
{
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Remark { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
31
LMS.Repository/User/LoginModel.cs
Normal file
31
LMS.Repository/User/LoginModel.cs
Normal file
@ -0,0 +1,31 @@
|
||||
namespace LMS.Repository.Models.User
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户登录的类型
|
||||
/// </summary>
|
||||
public enum LoginType
|
||||
{
|
||||
Username = 1, Email = 0,
|
||||
PhoneNumber = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户登录的实体类
|
||||
/// </summary>
|
||||
public class LoginModel
|
||||
{
|
||||
public string? UserName { get; set; }
|
||||
|
||||
public string? Email { get; set; }
|
||||
|
||||
public LoginType LoginType { get; set; } = 0;
|
||||
|
||||
public required string Password { get; set; }
|
||||
|
||||
public required string TokenId { get; set; }
|
||||
|
||||
public bool RememberMe { get; set; } = false;
|
||||
|
||||
public required string DeviceInfo { get; set; }
|
||||
}
|
||||
}
|
||||
19
LMS.Repository/User/PublicKeyModel.cs
Normal file
19
LMS.Repository/User/PublicKeyModel.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LMS.Repository.User
|
||||
{
|
||||
public class PublicKeyModel
|
||||
{
|
||||
public required string ClientPublicKey { get; set; }
|
||||
}
|
||||
|
||||
public class PublicKeyResponse
|
||||
{
|
||||
public required string Token { get; set; }
|
||||
public required string PublicKey { get; set; }
|
||||
}
|
||||
}
|
||||
10
LMS.Repository/User/RefreshTokenModel.cs
Normal file
10
LMS.Repository/User/RefreshTokenModel.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace LMS.Repository.Models.User
|
||||
{
|
||||
public class RefreshTokenModel
|
||||
{
|
||||
public string refreshToken { get; set; }
|
||||
public required long UserId { get; set; }
|
||||
|
||||
public required string DeviceInfo { get; set; }
|
||||
}
|
||||
}
|
||||
18
LMS.Repository/User/RegisterModel.cs
Normal file
18
LMS.Repository/User/RegisterModel.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace LMS.Repository.Models.User
|
||||
{
|
||||
public class RegisterModel
|
||||
{
|
||||
[Required]
|
||||
public required string UserName { get; set; }
|
||||
public string? Email { get; set; }
|
||||
[Required]
|
||||
public required string Password { get; set; }
|
||||
[Required]
|
||||
public required string TokenId { get; set; }
|
||||
|
||||
[Required]
|
||||
public required string AffiliateCode { get; set; }
|
||||
}
|
||||
}
|
||||
14
LMS.Repository/User/UpdatedUserModel.cs
Normal file
14
LMS.Repository/User/UpdatedUserModel.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace LMS.Repository.User
|
||||
{
|
||||
public class UpdatedUserModel
|
||||
{
|
||||
public double? AgentPercent { get; set; }
|
||||
public int? AllDeviceCount { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public int? FreeCount { get; set; }
|
||||
public string? NickName { get; set; }
|
||||
public string? UserName { get; set; }
|
||||
public string? PhoneNumber { get; set; }
|
||||
public List<string>? RoleNames { get; set; }
|
||||
}
|
||||
}
|
||||
12
LMS.Repository/User/UserPrivateOptions.cs
Normal file
12
LMS.Repository/User/UserPrivateOptions.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace LMS.Repository.User;
|
||||
|
||||
public class UserPrivateOptions
|
||||
{
|
||||
|
||||
}
|
||||
15
LMS.Tools/Extensions/BeijingTimeExtension.cs
Normal file
15
LMS.Tools/Extensions/BeijingTimeExtension.cs
Normal file
@ -0,0 +1,15 @@
|
||||
namespace LMS.Tools.Extensions
|
||||
{
|
||||
public class BeijingTimeExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取北京时间,将时区转换为北京时间
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime GetBeijingTime()
|
||||
{
|
||||
return TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow,
|
||||
TimeZoneInfo.FindSystemTimeZoneById("China Standard Time"));
|
||||
}
|
||||
}
|
||||
}
|
||||
44
LMS.Tools/Extensions/ConvertExtension.cs
Normal file
44
LMS.Tools/Extensions/ConvertExtension.cs
Normal file
@ -0,0 +1,44 @@
|
||||
namespace LMS.Tools.Extensions
|
||||
{
|
||||
public class ConvertExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// 将字符串转换为long,默认或者是转换错误返回0
|
||||
/// </summary>
|
||||
/// <param name="str"></param>
|
||||
/// <returns></returns>
|
||||
public static long ObjectToLong(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return 0;
|
||||
|
||||
if (obj is long longValue)
|
||||
return longValue;
|
||||
|
||||
if (obj is int intValue)
|
||||
return intValue;
|
||||
|
||||
if (obj is string strValue)
|
||||
{
|
||||
if (long.TryParse(strValue, out long result))
|
||||
return result;
|
||||
}
|
||||
|
||||
// 处理其他数值类型
|
||||
if (obj is IConvertible convertible)
|
||||
{
|
||||
try
|
||||
{
|
||||
return convertible.ToInt64(System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 转换失败,返回0
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // 默认返回0
|
||||
}
|
||||
}
|
||||
}
|
||||
74
LMS.Tools/Extensions/EnumExtensions.cs
Normal file
74
LMS.Tools/Extensions/EnumExtensions.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using LMS.Common.Attributes;
|
||||
using static LMS.Common.Enums.PermissionEnum;
|
||||
|
||||
namespace LMS.Tools
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 判断是否为有效的权限类型
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidPermissionType(Type enumType, object value)
|
||||
{
|
||||
if (enumType == null || !enumType.IsEnum)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 处理整数类型
|
||||
if (value is int intValue)
|
||||
{
|
||||
return Enum.IsDefined(enumType, intValue);
|
||||
}
|
||||
|
||||
// 处理字符串类型
|
||||
if (value is string stringValue)
|
||||
{
|
||||
return Enum.TryParse(enumType, stringValue, true, out _);
|
||||
}
|
||||
|
||||
// 如果不是整数或字符串,尝试转换为枚举底层类型
|
||||
try
|
||||
{
|
||||
var underlyingType = Enum.GetUnderlyingType(enumType);
|
||||
var convertedValue = Convert.ChangeType(value, underlyingType);
|
||||
return Enum.IsDefined(enumType, convertedValue);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对应的枚举的描述
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetDescription(this Enum value)
|
||||
{
|
||||
var field = value.GetType().GetField(value.ToString());
|
||||
var attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
|
||||
return attribute == null ? value.ToString() : attribute.Description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取对应的枚举的结果
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetResult(this Enum value)
|
||||
{
|
||||
var field = value.GetType().GetField(value.ToString());
|
||||
var attribute = Attribute.GetCustomAttribute(field, typeof(ResultAttribute)) as ResultAttribute;
|
||||
return attribute == null ? value.ToString() : attribute.Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
LMS.Tools/LMS.Tools.csproj
Normal file
13
LMS.Tools/LMS.Tools.csproj
Normal file
@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LMS.Common\LMS.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
30
LMS.service/.dockerignore
Normal file
30
LMS.service/.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
LMS.service/.gitattributes
vendored
Normal file
63
LMS.service/.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
|
||||
364
LMS.service/.gitignore
vendored
Normal file
364
LMS.service/.gitignore
vendored
Normal file
@ -0,0 +1,364 @@
|
||||
## 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
|
||||
/Properties/launchSettings.json
|
||||
174
LMS.service/APIResponseModel.cs
Normal file
174
LMS.service/APIResponseModel.cs
Normal file
@ -0,0 +1,174 @@
|
||||
using LMS.Tools;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
|
||||
namespace LMS.service
|
||||
{
|
||||
public class APIResponseModel<T>
|
||||
{
|
||||
public APIResponseModel()
|
||||
{
|
||||
Code = (int)ResponseCode.Success;
|
||||
Message = string.Empty;
|
||||
Data = default(T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回的码 0,1
|
||||
/// </summary>
|
||||
public int Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 返回的信息,成功或者失败的信息
|
||||
/// </summary>
|
||||
public string? Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 返回的数据,可以是任何类型
|
||||
/// </summary>
|
||||
public object? Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建返回消息
|
||||
/// </summary>
|
||||
/// <param name="code">返回码</param>
|
||||
/// <param name="data">返回数据</param>
|
||||
/// <param name="message">返回消息</param>
|
||||
/// <returns></returns>
|
||||
public static APIResponseModel<T> CreateResponseModel(ResponseCode code, T data)
|
||||
{
|
||||
return new APIResponseModel<T>
|
||||
{
|
||||
Code = (int)code,
|
||||
Message = code.GetResult(),
|
||||
Data = data
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建正常的返回数据
|
||||
/// </summary>
|
||||
/// <param name="data">返回的数据</param>
|
||||
/// <param name="message">返回成功的消息</param>
|
||||
/// <returns></returns>
|
||||
public static APIResponseModel<T> CreateSuccessResponseModel(ResponseCode code, T data)
|
||||
{
|
||||
return new APIResponseModel<T>
|
||||
{
|
||||
Code = (int)code,
|
||||
Message = code.GetResult(),
|
||||
Data = data
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个返回成功的消息
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public static APIResponseModel<T> CreateSuccessResponseModel(T data, string message)
|
||||
{
|
||||
return new APIResponseModel<T>
|
||||
{
|
||||
Code = (int)ResponseCode.Success,
|
||||
Message = message,
|
||||
Data = data
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个返回成功的消息
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <returns></returns>
|
||||
public static APIResponseModel<T> CreateSuccessResponseModel(T data)
|
||||
{
|
||||
return new APIResponseModel<T>
|
||||
{
|
||||
Code = (int)ResponseCode.Success,
|
||||
Message = "请求成功",
|
||||
Data = data
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建正常的返回数据
|
||||
/// </summary>
|
||||
/// <param name="data">返回的数据</param>
|
||||
/// <returns></returns>
|
||||
public static APIResponseModel<T> CreateSuccessResponseModel(ResponseCode code)
|
||||
{
|
||||
return new APIResponseModel<T>
|
||||
{
|
||||
Code = (int)code,
|
||||
Message = code.GetResult(),
|
||||
Data = null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回错误消息
|
||||
/// </summary>
|
||||
/// <param name="code">错误的码</param>
|
||||
/// <param name="data">返回的数据</param>
|
||||
/// <returns></returns>
|
||||
public static APIResponseModel<T> CreateErrorResponseModel(ResponseCode code, T data)
|
||||
{
|
||||
return new APIResponseModel<T>
|
||||
{
|
||||
Code = (int)code,
|
||||
Message = code.GetResult(),
|
||||
Data = data
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回错误消息
|
||||
/// </summary>
|
||||
/// <param name="code">错误的码</param>
|
||||
/// <param name="data">返回的数据</param>
|
||||
/// <param name="message">返回的错误消息</param>
|
||||
/// <returns></returns>
|
||||
public static APIResponseModel<T> CreateErrorResponseModel(ResponseCode code, T data, string message)
|
||||
{
|
||||
return new APIResponseModel<T>
|
||||
{
|
||||
Code = (int)code,
|
||||
Message = message,
|
||||
Data = data
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个错误的返回数据,只有错误消息
|
||||
/// </summary>
|
||||
/// <param name="code">错误的码</param>
|
||||
/// <returns></returns>
|
||||
public static APIResponseModel<T> CreateErrorResponseModel(ResponseCode code)
|
||||
{
|
||||
return new APIResponseModel<T>
|
||||
{
|
||||
Code = (int)code,
|
||||
Message = code.GetResult(),
|
||||
Data = null
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建一个错误的返回数据,只有错误消息
|
||||
/// </summary>
|
||||
/// <param name="code">错误的码</param>
|
||||
/// <param name="message">错误消息提示</param>
|
||||
/// <returns></returns>
|
||||
public static APIResponseModel<T> CreateErrorResponseModel(ResponseCode code, string message)
|
||||
{
|
||||
return new APIResponseModel<T>
|
||||
{
|
||||
Code = (int)code,
|
||||
Message = message,
|
||||
Data = null
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
19
LMS.service/Configuration/AddCorsConifg.cs
Normal file
19
LMS.service/Configuration/AddCorsConifg.cs
Normal file
@ -0,0 +1,19 @@
|
||||
namespace LMS.service.Configuration
|
||||
{
|
||||
public static class AddCorsConifg
|
||||
{
|
||||
public static void AddCorsServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowAll",
|
||||
builder =>
|
||||
{
|
||||
builder.AllowAnyOrigin()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
28
LMS.service/Configuration/AuthenticationExtensions.cs
Normal file
28
LMS.service/Configuration/AuthenticationExtensions.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Text;
|
||||
|
||||
namespace Lai_server.Configuration
|
||||
{
|
||||
public static class AuthenticationExtensions
|
||||
{
|
||||
public static void AddJWTAuthentication(this IServiceCollection services)
|
||||
{
|
||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(x =>
|
||||
{
|
||||
string secKeyEnv = Environment.GetEnvironmentVariable("SecKey");
|
||||
byte[] keyBytes = Encoding.UTF8.GetBytes(secKeyEnv);
|
||||
var secKey = new SymmetricSecurityKey(keyBytes);
|
||||
x.TokenValidationParameters = new()
|
||||
{
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = secKey
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
31
LMS.service/Configuration/AutoMapperConfig.cs
Normal file
31
LMS.service/Configuration/AutoMapperConfig.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using AutoMapper;
|
||||
using LMS.Repository.DTO;
|
||||
using LMS.Repository.DTO.UserDto;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.Models.Machine;
|
||||
using LMS.Repository.Models.Promission;
|
||||
using LMS.Repository.RequestModel.Permission;
|
||||
using static LMS.Repository.DTO.MachineResponse.MachineDto;
|
||||
|
||||
namespace Lai_server.Configuration
|
||||
{
|
||||
public class AutoMapperConfig : Profile
|
||||
{
|
||||
public AutoMapperConfig()
|
||||
{
|
||||
CreateMap<Machine, MachineStatusResponse>();
|
||||
|
||||
CreateMap<Machine, MachineDetailDto>();
|
||||
|
||||
CreateMap<MachineModel, Machine>();
|
||||
|
||||
CreateMap<PermissionTypeModel, PermissionType>();
|
||||
|
||||
CreateMap<PermissionModel, Permission>();
|
||||
|
||||
CreateMap<User, UserDto>();
|
||||
|
||||
CreateMap<User, UserBaseDto>();
|
||||
}
|
||||
}
|
||||
}
|
||||
10
LMS.service/Configuration/JWTSetting.cs
Normal file
10
LMS.service/Configuration/JWTSetting.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Lai_server.Configuration
|
||||
{
|
||||
public class JWTSetting
|
||||
{
|
||||
public string SecKey { get; set; }
|
||||
|
||||
public int ExpireMinutes { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
66
LMS.service/Configuration/RsaConfigurattions.cs
Normal file
66
LMS.service/Configuration/RsaConfigurattions.cs
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
using LMS.Common.RSAKey;
|
||||
using LMS.DAO;
|
||||
using LMS.Repository.DB;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LMS.service.Configuration
|
||||
{
|
||||
public class RsaConfigurattions(IServiceProvider serviceProvider) : IHostedService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider = serviceProvider;
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||
using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken);
|
||||
try
|
||||
{
|
||||
int count = await dbContext.RsaKeys.CountAsync(cancellationToken: cancellationToken);
|
||||
|
||||
// 先删除无效的RSA数据
|
||||
List<RsaKeys> rsaKeys = await dbContext.RsaKeys.Where(x => x.UseCount > 50 || x.ExpirationTime < BeijingTimeExtension.GetBeijingTime()).ToListAsync(cancellationToken: cancellationToken);
|
||||
if (rsaKeys.Count > 0)
|
||||
{
|
||||
dbContext.RsaKeys.RemoveRange(rsaKeys);
|
||||
}
|
||||
|
||||
// 新增 保证数据库中有指定数量的RSA数据
|
||||
|
||||
int AddCount = 20 - (count - rsaKeys.Count);
|
||||
for (int i = 0; i < AddCount; i++)
|
||||
{
|
||||
RSAKeyGenerateModel rSAKeyGenerate = RsaKeyPairGenerator.InitRsaKey();
|
||||
|
||||
await dbContext.RsaKeys.AddAsync(new RsaKeys
|
||||
{
|
||||
PublicKey = rSAKeyGenerate.PublicKey,
|
||||
EncryptedPrivateKey = rSAKeyGenerate.EncryptedPrivateKey,
|
||||
EncryptionKey = rSAKeyGenerate.EncryptedKey,
|
||||
EncryptionIV = rSAKeyGenerate.EncryptionIV,
|
||||
UseCount = 0,
|
||||
ExpirationTime = BeijingTimeExtension.GetBeijingTime().AddDays(10),
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
await transaction.CommitAsync(cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await transaction.RollbackAsync(cancellationToken);
|
||||
// 根据需要处理异常,例如终止应用程序
|
||||
Console.WriteLine(ex.Message);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
39
LMS.service/Configuration/ServiceConfiguration.cs
Normal file
39
LMS.service/Configuration/ServiceConfiguration.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using LMS.DAO.MachineDAO;
|
||||
using LMS.DAO.PermissionDAO;
|
||||
using LMS.DAO.RoleDAO;
|
||||
using LMS.DAO.UserDAO;
|
||||
using LMS.service.Configuration;
|
||||
using LMS.service.Service;
|
||||
using LMS.service.Service.PermissionService;
|
||||
using LMS.service.Service.RoleService;
|
||||
using LMS.service.Service.UserService;
|
||||
|
||||
namespace Lai_server.Configuration
|
||||
{
|
||||
public static class ServiceConfiguration
|
||||
{
|
||||
public static void AddServices(this IServiceCollection services)
|
||||
{
|
||||
// 注入Service
|
||||
services.AddScoped<RsaConfigurattions>();
|
||||
|
||||
// 注入DDL
|
||||
services.AddScoped<LoginService>();
|
||||
services.AddScoped<SecurityService>();
|
||||
services.AddScoped<MachineService>();
|
||||
services.AddScoped<PermissionService>();
|
||||
services.AddScoped<PremissionValidationService>();
|
||||
services.AddScoped<RoleService>();
|
||||
services.AddScoped<UserService>();
|
||||
|
||||
|
||||
// 注入 DAO
|
||||
services.AddScoped<UserBasicDao>();
|
||||
services.AddScoped<RoleBasicDao>();
|
||||
services.AddScoped<MachineBasicDao>();
|
||||
services.AddScoped<PermissionBasicDao>();
|
||||
services.AddScoped<PermissionTypeDao>();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
31
LMS.service/Configuration/SwaggerConfiguration.cs
Normal file
31
LMS.service/Configuration/SwaggerConfiguration.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace Lai_server.Configuration
|
||||
{
|
||||
public static class SwaggerConfiguration
|
||||
{
|
||||
public static void AddSwaggerService(this IServiceCollection services)
|
||||
{
|
||||
services.AddSwaggerGen(c =>
|
||||
{
|
||||
var scheme = new OpenApiSecurityScheme()
|
||||
{
|
||||
Description = "Authorization header. \r\nExample: 'Bearer 12345abcdef'",
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.SecurityScheme,
|
||||
Id = "Authorization"
|
||||
},
|
||||
Scheme = "oauth2",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.ApiKey,
|
||||
};
|
||||
c.AddSecurityDefinition("Authorization", scheme);
|
||||
var requirement = new OpenApiSecurityRequirement();
|
||||
requirement[scheme] = new List<string>();
|
||||
c.AddSecurityRequirement(requirement);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
150
LMS.service/Controllers/MachineController.cs
Normal file
150
LMS.service/Controllers/MachineController.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using LMS.Repository.DTO;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.Models.Machine;
|
||||
using LMS.service.Service;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using static LMS.Common.Enums.MachineEnum;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
using static LMS.Repository.DTO.MachineResponse.MachineDto;
|
||||
|
||||
namespace LMS.service.Controllers
|
||||
{
|
||||
[Route("lms/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class MachineController(MachineService machineService) : ControllerBase
|
||||
{
|
||||
private readonly MachineService _machineService = machineService;
|
||||
|
||||
#region 获取指定机器码的状态
|
||||
/// <summary>
|
||||
/// 获取指定机器码的状态
|
||||
/// </summary>
|
||||
/// <param name="machineId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{machineId}")]
|
||||
public async Task<ActionResult<APIResponseModel<MachineStatusResponse>>> GetMachineStatus(string machineId)
|
||||
{
|
||||
return await _machineService.GetMachineStatus(machineId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 修改机器码数据
|
||||
/// <summary>
|
||||
/// 修改当前机器码
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("{id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> ModifyMachine(string id, [FromBody] MachineModel request)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _machineService.ModifyMachine(id, request, userId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 添加机器码
|
||||
/// <summary>
|
||||
/// 添加机器码
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> AddMachine([FromBody] MachineModel request)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _machineService.AddMachine(request, userId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取机器码列表
|
||||
|
||||
/// <summary>
|
||||
/// 通过查询条件获取机器码列表
|
||||
/// </summary>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="machineId"></param>
|
||||
/// <param name="CreatedUserName"></param>
|
||||
/// <param name="status"></param>
|
||||
/// <param name="useStatus"></param>
|
||||
/// <param name="Remark"></param>
|
||||
/// <param name="ownUserName"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<CollectionResponse<Machine>>>> QueryMachineCollection([Required] int page, [Required] int pageSize, string? machineId, string? createdUserName, MachineStatus? status, MachineUseStatus? useStatus, string? remark, string? ownUserName)
|
||||
{
|
||||
long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _machineService.QueryMachineCollection(page, pageSize, machineId, createdUserName, status, useStatus, remark, ownUserName, requestUserId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取指定的机器码详情
|
||||
|
||||
[HttpGet("{Id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<MachineDetailDto>>> GetMachineDetail(string Id)
|
||||
{
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _machineService.GetMachineDetail(Id, userId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 将机器码停用
|
||||
|
||||
[HttpPost("{Id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> DeactivateMachine(string Id)
|
||||
{
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _machineService.DeactivateMachine(Id, userId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 将机器码升级为永久使用
|
||||
|
||||
[HttpPost("{Id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> UpgradeMachine(string Id)
|
||||
{
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _machineService.UpgradeMachine(Id, userId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 删除机器码
|
||||
/// <summary>
|
||||
/// 删除机器码
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<object>>> DeleteMachine(string id)
|
||||
{
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _machineService.DeleteMachine(id, userId);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
134
LMS.service/Controllers/PermissionController.cs
Normal file
134
LMS.service/Controllers/PermissionController.cs
Normal file
@ -0,0 +1,134 @@
|
||||
using LMS.Repository.Models.Promission;
|
||||
using LMS.Repository.RequestModel.Permission;
|
||||
using LMS.service;
|
||||
using LMS.service.Service.PermissionService;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
|
||||
namespace Lai_server.Controllers
|
||||
{
|
||||
[Route("lms/[controller]/[action]")]
|
||||
[ApiController]
|
||||
public class PermissionController : ControllerBase
|
||||
{
|
||||
private readonly PermissionService _permissionService;
|
||||
public PermissionController(PermissionService permissionService)
|
||||
{
|
||||
_permissionService = permissionService;
|
||||
}
|
||||
|
||||
#region 权限类型
|
||||
|
||||
/// <summary>
|
||||
/// 创建权限类型
|
||||
/// </summary>
|
||||
/// <param name="permissionType"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<object>>> AddPermissionType([FromBody] PermissionTypeModel permissionType)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _permissionService.AddPermissionType(permissionType, userId);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 新增权限类型
|
||||
/// </summary>
|
||||
/// <param name="permissionType"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("{permissionId}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<object>>> ModifyPermissionType(string permissionId, [FromBody] PermissionTypeModel permissionType)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _permissionService.ModifyPermissionType(permissionId, permissionType, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除权限类型
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="relation"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{id}/{relation}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<object>>> DeletePermissionType(string id, bool relation)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _permissionService.DeletePermissionType(id, relation, userId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 权限
|
||||
|
||||
/// <summary>
|
||||
/// 添加对应的权限
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<object>>> AddPermission([FromBody] PermissionModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _permissionService.AddPermission(model, userId);
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 修改权限
|
||||
///// </summary>
|
||||
///// <param name="request"></param>
|
||||
///// <returns></returns>
|
||||
[HttpPost("{id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<object>>> ModfiyPermission(string id, [FromBody] PermissionModel request)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _permissionService.ModfiyPermission(id, request, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除权限
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> DeletePermission(string Id)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _permissionService.DeletePermission(Id, userId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
107
LMS.service/Controllers/RoleController.cs
Normal file
107
LMS.service/Controllers/RoleController.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using LMS.Repository.DTO;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.Role;
|
||||
using LMS.service.Service.RoleService;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
|
||||
namespace LMS.service.Controllers
|
||||
{
|
||||
[Route("lms/[controller]/[action]")]
|
||||
public class RoleController(RoleService roleService) : ControllerBase
|
||||
{
|
||||
private readonly RoleService _roleService = roleService;
|
||||
|
||||
/// <summary>
|
||||
/// 获取角色列表数据
|
||||
/// </summary>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="roleName"></param>
|
||||
/// <param name="roleId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<CollectionResponse<RoleDto>>>> QueryRoleCollection([Required] int page, [Required] int pageSize, string? roleName, long? roleId)
|
||||
{
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _roleService.QueryRoleCollection(page, pageSize, roleName, roleId, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有的角色的数据,对应的Name,用作下拉框的数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<List<string>>>> QueryRoleOption()
|
||||
{
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _roleService.QueryRoleOption(userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过指定Id获取角色
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{Id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<RoleDto>>> QueryRoleById(long Id)
|
||||
{
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _roleService.QueryRoleById(Id, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加角色
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> AddRole([FromBody] RoleModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _roleService.AddRole(model, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改角色
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost("{id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> UpdateRole(long id, [FromBody] RoleModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long userId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _roleService.UpdateRole(id, model, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除角色
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> DeleteRole(long id)
|
||||
{
|
||||
return await _roleService.DeleteRole(id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
15
LMS.service/Controllers/SoftWareController.cs
Normal file
15
LMS.service/Controllers/SoftWareController.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Reflection;
|
||||
|
||||
namespace LMS.service.Controllers
|
||||
{
|
||||
[Route("lms/[controller]/[action]")]
|
||||
public class SoftWareController : Controller
|
||||
{
|
||||
//public Index()
|
||||
//{
|
||||
// var version = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
// Console.WriteLine($"Version: {version}");
|
||||
//}
|
||||
}
|
||||
}
|
||||
225
LMS.service/Controllers/UserController.cs
Normal file
225
LMS.service/Controllers/UserController.cs
Normal file
@ -0,0 +1,225 @@
|
||||
using LMS.DAO;
|
||||
using LMS.Repository.DTO;
|
||||
using LMS.Repository.DTO.UserDto;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.Models.User;
|
||||
using LMS.Repository.User;
|
||||
using LMS.service.Service.UserService;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Concurrent;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
|
||||
namespace LMS.service.Controllers
|
||||
{
|
||||
[Route("lms/[controller]/[action]")]
|
||||
public class UserController(ApplicationDbContext context, UserManager<User> userManager, LoginService loginService, SecurityService securityService, UserService userService) : ControllerBase
|
||||
{
|
||||
private readonly ApplicationDbContext _context = context;
|
||||
private readonly UserManager<User> _userManager = userManager;
|
||||
public readonly LoginService _loginService = loginService;
|
||||
private readonly SecurityService _securityService = securityService;
|
||||
private readonly UserService _userService = userService;
|
||||
|
||||
/// <summary>
|
||||
/// 存储密钥的 ConcurrentDictionary
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<string, (string Key, DateTime Expiry)> _keyStore = new();
|
||||
|
||||
#region 获取公钥
|
||||
/// <summary>
|
||||
/// 获取公钥
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<APIResponseModel<PublicKeyResponse>>> GetPublicKey()
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<PublicKeyResponse>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
return await _securityService.GetPublicKey(_keyStore);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 登录
|
||||
/// <summary>
|
||||
/// 用户登录接口
|
||||
/// </summary>
|
||||
/// <param name="login"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<APIResponseModel<object>>> Login([FromBody] LoginModel login)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
|
||||
string? ip = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
}
|
||||
|
||||
APIResponseModel<object> apiResponse = await _loginService.UserLogin(login, ip, _keyStore);
|
||||
if (apiResponse.Code != 1)
|
||||
{
|
||||
return apiResponse;
|
||||
}
|
||||
|
||||
// 这个添加Cokkie
|
||||
|
||||
var cookieOptions = new CookieOptions
|
||||
{
|
||||
HttpOnly = true,
|
||||
Secure = false, // 如果使用 HTTPS
|
||||
SameSite = SameSiteMode.None,
|
||||
Expires = DateTime.UtcNow.AddDays(7),
|
||||
};
|
||||
Response.Cookies.Append("refreshToken", ((LoginService.LoginResponse)apiResponse.Data).RefreshToken, cookieOptions);
|
||||
return apiResponse;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 注册
|
||||
|
||||
/// <summary>
|
||||
/// 用户注册接口
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> Register([FromBody] RegisterModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _userService.Register(model, _keyStore);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 刷新token
|
||||
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> RefreshToken([FromBody] RefreshTokenModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
string? ip = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(ip))
|
||||
{
|
||||
ip = HttpContext.Connection.RemoteIpAddress?.ToString();
|
||||
}
|
||||
// 获取Cookie 的值
|
||||
string? refreshToken = model.refreshToken;
|
||||
if (string.IsNullOrWhiteSpace(refreshToken))
|
||||
{
|
||||
//Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
//await Response.WriteAsync("Access denied, RefreshToken is null");
|
||||
// 返回权限错误
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.RefreshTokenInvalid);
|
||||
}
|
||||
else
|
||||
{
|
||||
return await _loginService.RefreshToken(model, ip, refreshToken);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 退出登录
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取用户信息
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户信息
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<UserDto>>> GetUserInfo(long id)
|
||||
{
|
||||
long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _userService.GetUserInfo(id, requestUserId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取用户列表
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户列表,可以使用查询条件 userName, userId, nickName, phoneNumber, email, roleNames
|
||||
/// </summary>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="userName"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="nickName"></param>
|
||||
/// <param name="phoneNumber"></param>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="roleNames"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<CollectionResponse<UserCollectionDto>>>> QueryUserCollection([Required] int page, [Required] int pageSize, string userName, long? userId, string nickName, string phoneNumber, string email, string[] roleNames, long? parentId)
|
||||
{
|
||||
long reuqertUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _userService.QueryUserCollection(page, pageSize, userName, userId, nickName, phoneNumber, email, roleNames, parentId, reuqertUserId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 修改用户信息
|
||||
|
||||
[HttpPost("{id}")]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> UpdatedUser(long id, [FromBody] UpdatedUserModel userModel)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _userService.UpdatedUser(id, userModel, requestUserId);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 将用户升级为代理
|
||||
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<string>>> EnableAgent()
|
||||
{
|
||||
long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _loginService.EnableAgent(requestUserId);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 获取用户的代理信息
|
||||
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
public async Task<ActionResult<APIResponseModel<UserAgentInfoDto>>> GetUserAgentInfo()
|
||||
{
|
||||
long requestUserId = ConvertExtension.ObjectToLong(HttpContext.Items["UserId"] ?? 0);
|
||||
return await _userService.GetUserAgentInfo(requestUserId);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
299
LMS.service/Data/Migrations/20240912114032_inital.Designer.cs
generated
Normal file
299
LMS.service/Data/Migrations/20240912114032_inital.Designer.cs
generated
Normal file
@ -0,0 +1,299 @@
|
||||
// <auto-generated />
|
||||
using LMS.DAO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace LMS.service.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
[Migration("20240912114032_inital")]
|
||||
partial class inital
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.8")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("LMS.service.Models.UserModels.Role", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LMS.service.Models.UserModels.User", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("CreatedDate")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTime>("LastLoginDate")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
b.Property<string>("LastLoginDevice")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("LastLoginIp")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("NickName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTime>("UpdatedDate")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("RoleId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
|
||||
{
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<long>("RoleId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
|
||||
{
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LMS.service.Models.UserModels.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
265
LMS.service/Data/Migrations/20240912114032_inital.cs
Normal file
265
LMS.service/Data/Migrations/20240912114032_inital.cs
Normal file
@ -0,0 +1,265 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace LMS.service.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class inital : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterDatabase()
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoles",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Name = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
NormalizedName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
ConcurrencyStamp = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoles", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUsers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<long>(type: "bigint", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
NickName = table.Column<string>(type: "varchar(50)", maxLength: 50, nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
CreatedDate = table.Column<DateTime>(type: "datetime", nullable: false),
|
||||
UpdatedDate = table.Column<DateTime>(type: "datetime", nullable: false),
|
||||
LastLoginDate = table.Column<DateTime>(type: "datetime", nullable: false),
|
||||
LastLoginIp = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
LastLoginDevice = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
UserName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
NormalizedUserName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Email = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
NormalizedEmail = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
EmailConfirmed = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
PasswordHash = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
SecurityStamp = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
ConcurrencyStamp = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
PhoneNumber = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
PhoneNumberConfirmed = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
TwoFactorEnabled = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
LockoutEnd = table.Column<DateTimeOffset>(type: "datetime(6)", nullable: true),
|
||||
LockoutEnabled = table.Column<bool>(type: "tinyint(1)", nullable: false),
|
||||
AccessFailedCount = table.Column<int>(type: "int", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUsers", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetRoleClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
RoleId = table.Column<long>(type: "bigint", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
ClaimValue = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetRoleClaims_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserClaims",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
UserId = table.Column<long>(type: "bigint", nullable: false),
|
||||
ClaimType = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
ClaimValue = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserClaims", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserClaims_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserLogins",
|
||||
columns: table => new
|
||||
{
|
||||
LoginProvider = table.Column<string>(type: "varchar(255)", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
ProviderKey = table.Column<string>(type: "varchar(255)", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
ProviderDisplayName = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
UserId = table.Column<long>(type: "bigint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserLogins_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserRoles",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<long>(type: "bigint", nullable: false),
|
||||
RoleId = table.Column<long>(type: "bigint", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetRoles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalTable: "AspNetRoles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserRoles_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AspNetUserTokens",
|
||||
columns: table => new
|
||||
{
|
||||
UserId = table.Column<long>(type: "bigint", nullable: false),
|
||||
LoginProvider = table.Column<string>(type: "varchar(255)", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Name = table.Column<string>(type: "varchar(255)", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Value = table.Column<string>(type: "longtext", nullable: true)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name });
|
||||
table.ForeignKey(
|
||||
name: "FK_AspNetUserTokens_AspNetUsers_UserId",
|
||||
column: x => x.UserId,
|
||||
principalTable: "AspNetUsers",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetRoleClaims_RoleId",
|
||||
table: "AspNetRoleClaims",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "RoleNameIndex",
|
||||
table: "AspNetRoles",
|
||||
column: "NormalizedName",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserClaims_UserId",
|
||||
table: "AspNetUserClaims",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserLogins_UserId",
|
||||
table: "AspNetUserLogins",
|
||||
column: "UserId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_AspNetUserRoles_RoleId",
|
||||
table: "AspNetUserRoles",
|
||||
column: "RoleId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "EmailIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedEmail");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "UserNameIndex",
|
||||
table: "AspNetUsers",
|
||||
column: "NormalizedUserName",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoleClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserClaims");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserLogins");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUserTokens");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetRoles");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AspNetUsers");
|
||||
}
|
||||
}
|
||||
}
|
||||
300
LMS.service/Data/Migrations/ApplicationDbContextModelSnapshot.cs
Normal file
300
LMS.service/Data/Migrations/ApplicationDbContextModelSnapshot.cs
Normal file
@ -0,0 +1,300 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using LMS.DAO;
|
||||
using LMS.service.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace LMS.service.Data.Migrations
|
||||
{
|
||||
[DbContext(typeof(ApplicationDbContext))]
|
||||
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
|
||||
{
|
||||
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.8")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("LMS.service.Models.UserModels.Role", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("RoleNameIndex");
|
||||
|
||||
b.ToTable("AspNetRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("LMS.service.Models.UserModels.User", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<int>("AccessFailedCount")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ConcurrencyStamp")
|
||||
.IsConcurrencyToken()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("CreatedDate")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<bool>("EmailConfirmed")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTime>("LastLoginDate")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
b.Property<string>("LastLoginDevice")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("LastLoginIp")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("LockoutEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTimeOffset?>("LockoutEnd")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("NickName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("varchar(50)");
|
||||
|
||||
b.Property<string>("NormalizedEmail")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<string>("NormalizedUserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("PhoneNumber")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("PhoneNumberConfirmed")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("SecurityStamp")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("TwoFactorEnabled")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<DateTime>("UpdatedDate")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
b.Property<string>("UserName")
|
||||
.HasMaxLength(256)
|
||||
.HasColumnType("varchar(256)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("NormalizedEmail")
|
||||
.HasDatabaseName("EmailIndex");
|
||||
|
||||
b.HasIndex("NormalizedUserName")
|
||||
.IsUnique()
|
||||
.HasDatabaseName("UserNameIndex");
|
||||
|
||||
b.ToTable("AspNetUsers", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("RoleId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetRoleClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("ClaimType")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ClaimValue")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserClaims", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
|
||||
{
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<string>("ProviderKey")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<string>("ProviderDisplayName")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("LoginProvider", "ProviderKey");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("AspNetUserLogins", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
|
||||
{
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<long>("RoleId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasKey("UserId", "RoleId");
|
||||
|
||||
b.HasIndex("RoleId");
|
||||
|
||||
b.ToTable("AspNetUserRoles", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
|
||||
{
|
||||
b.Property<long>("UserId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<string>("LoginProvider")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("varchar(255)");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("UserId", "LoginProvider", "Name");
|
||||
|
||||
b.ToTable("AspNetUserTokens", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.Role", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("LMS.service.Models.UserModels.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
|
||||
{
|
||||
b.HasOne("LMS.service.Models.UserModels.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
31
LMS.service/Dockerfile
Normal file
31
LMS.service/Dockerfile
Normal file
@ -0,0 +1,31 @@
|
||||
#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
|
||||
USER app
|
||||
WORKDIR /app
|
||||
EXPOSE 8080
|
||||
EXPOSE 8081
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
WORKDIR /src
|
||||
# ¸´ÖÆËùÓеÄÏîÄ¿Îļþ
|
||||
COPY ["LMS.service/LMS.service.csproj", "LMS.service/"]
|
||||
COPY ["LMS.Common/LMS.Common.csproj", "LMS.Common/"]
|
||||
COPY ["LMS.DAO/LMS.DAO.csproj", "LMS.DAO/"]
|
||||
COPY ["LMS.Repository/LMS.Repository.csproj", "LMS.Repository/"]
|
||||
COPY ["LMS.Tools/LMS.Tools.csproj", "LMS.Tools/"]
|
||||
|
||||
RUN dotnet restore "LMS.service/LMS.service.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/LMS.service"
|
||||
RUN dotnet build "LMS.service.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
RUN dotnet publish "LMS.service.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "LMS.service.dll"]
|
||||
@ -0,0 +1,65 @@
|
||||
using LMS.service.Service.PermissionService;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace LMS.service.Extensions.Middleware
|
||||
{
|
||||
public class DynamicPermissionMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public DynamicPermissionMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context, PremissionValidationService _premissionValidationServices)
|
||||
{
|
||||
var endpoint = context.GetEndpoint();
|
||||
var userId = GetUserIdFromContext(context); // 从JWT token或session中获取用户ID
|
||||
if (userId == -1) // 判断用户ID是否有效
|
||||
{
|
||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||
await context.Response.WriteAsync("用户参数校验错误");
|
||||
return;
|
||||
}
|
||||
|
||||
if (endpoint != null)
|
||||
{
|
||||
var httpMethod = context.Request.Method;
|
||||
var path = (endpoint as RouteEndpoint)?.RoutePattern.RawText;
|
||||
|
||||
if (await _premissionValidationServices.HasPermissionForEndpoint(userId, httpMethod, path))
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
await context.Response.WriteAsync("Access denied");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
}
|
||||
|
||||
private long GetUserIdFromContext(HttpContext context)
|
||||
{
|
||||
var userIdClaim = context.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
|
||||
var userId = userIdClaim?.Value;
|
||||
if (!string.IsNullOrWhiteSpace(userId))
|
||||
{
|
||||
// 判断userId是否为数字
|
||||
if (!long.TryParse(userId, out var result))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
context.Items["UserId"] = userId;
|
||||
return Convert.ToInt64(userIdClaim?.Value);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
LMS.service/LMS.service.csproj
Normal file
43
LMS.service/LMS.service.csproj
Normal file
@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>ed64fb6f-9c93-43d0-b418-61f507f28420</UserSecretsId>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<DockerfileContext>.</DockerfileContext>
|
||||
<Version>1.0.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNet.Identity.Core" Version="2.2.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.8" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Data\Migrations\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\LMS.Common\LMS.Common.csproj" />
|
||||
<ProjectReference Include="..\LMS.DAO\LMS.DAO.csproj" />
|
||||
<ProjectReference Include="..\LMS.Repository\LMS.Repository.csproj" />
|
||||
<ProjectReference Include="..\LMS.Tools\LMS.Tools.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
6
LMS.service/LMS.service.http
Normal file
6
LMS.service/LMS.service.http
Normal file
@ -0,0 +1,6 @@
|
||||
@LMS.service_HostAddress = http://localhost:5181
|
||||
|
||||
GET {{LMS.service_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
49
LMS.service/LMS.service.sln
Normal file
49
LMS.service/LMS.service.sln
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.9.34622.214
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LMS.service", "LMS.service.csproj", "{E6EDD426-2283-40EA-93EA-2C718FBD66CB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LMS.Tools", "..\LMS.Tools\LMS.Tools.csproj", "{2551EC61-E4DA-4DF8-BCCC-2D0456D61424}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LMS.Common", "..\LMS.Common\LMS.Common.csproj", "{AB8D7E1E-2AA9-45C1-9C9A-A549C9FCA231}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LMS.Repository", "..\LMS.Repository\LMS.Repository.csproj", "{ABE14686-E9D8-4FCD-9D1F-767EC82D5538}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LMS.DAO", "..\LMS.DAO\LMS.DAO.csproj", "{CC297416-0545-4416-9E9A-EA738DA931B9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E6EDD426-2283-40EA-93EA-2C718FBD66CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E6EDD426-2283-40EA-93EA-2C718FBD66CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E6EDD426-2283-40EA-93EA-2C718FBD66CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E6EDD426-2283-40EA-93EA-2C718FBD66CB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2551EC61-E4DA-4DF8-BCCC-2D0456D61424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2551EC61-E4DA-4DF8-BCCC-2D0456D61424}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2551EC61-E4DA-4DF8-BCCC-2D0456D61424}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2551EC61-E4DA-4DF8-BCCC-2D0456D61424}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AB8D7E1E-2AA9-45C1-9C9A-A549C9FCA231}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AB8D7E1E-2AA9-45C1-9C9A-A549C9FCA231}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AB8D7E1E-2AA9-45C1-9C9A-A549C9FCA231}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AB8D7E1E-2AA9-45C1-9C9A-A549C9FCA231}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ABE14686-E9D8-4FCD-9D1F-767EC82D5538}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ABE14686-E9D8-4FCD-9D1F-767EC82D5538}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ABE14686-E9D8-4FCD-9D1F-767EC82D5538}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ABE14686-E9D8-4FCD-9D1F-767EC82D5538}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CC297416-0545-4416-9E9A-EA738DA931B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CC297416-0545-4416-9E9A-EA738DA931B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CC297416-0545-4416-9E9A-EA738DA931B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CC297416-0545-4416-9E9A-EA738DA931B9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {BD24726A-3AE2-4762-8EC5-1528B1A863E0}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
104
LMS.service/Program.cs
Normal file
104
LMS.service/Program.cs
Normal file
@ -0,0 +1,104 @@
|
||||
using Lai_server.Configuration;
|
||||
using LMS.DAO;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.service.Configuration;
|
||||
using LMS.service.Extensions.Middleware;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
builder.Services.AddControllers();
|
||||
|
||||
builder.Services.AddAuthentication();
|
||||
|
||||
// 添加跨域
|
||||
builder.Services.AddCorsServices();
|
||||
|
||||
// 配置注入自定义服务方法
|
||||
builder.Services.AddServices();
|
||||
|
||||
builder.Services.ConfigureApplicationCookie(options =>
|
||||
{
|
||||
options.Cookie.HttpOnly = true;
|
||||
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
|
||||
options.Cookie.SameSite = SameSiteMode.None;
|
||||
});
|
||||
|
||||
//配置JWT
|
||||
builder.Services.AddJWTAuthentication();
|
||||
builder.Services.AddAutoMapper(typeof(AutoMapperConfig));
|
||||
|
||||
builder.Services.AddDbContext<ApplicationDbContext>(options =>
|
||||
{
|
||||
string connectionString = $"server={Environment.GetEnvironmentVariable("DATABASE_SERVER")};port={Environment.GetEnvironmentVariable("DATABASE_PORT")};user={Environment.GetEnvironmentVariable("DATABASE_USER")};password={Environment.GetEnvironmentVariable("DATABASE_PASSWORD")};database={Environment.GetEnvironmentVariable("DATABASE_NAME")};ConvertZeroDateTime=True;SslMode={Environment.GetEnvironmentVariable("DATABASE_SSL_MODE") ?? "None"};";
|
||||
options.UseMySql(connectionString, ServerVersion.Parse("8.0.18-mysql"));
|
||||
});
|
||||
|
||||
builder.Services.AddIdentityCore<User>(options =>
|
||||
{
|
||||
options.SignIn.RequireConfirmedAccount = true; //已有账号才能登录
|
||||
options.SignIn.RequireConfirmedEmail = true; //
|
||||
options.Password.RequireDigit = true; // 数据库中至少有一个数字
|
||||
options.Password.RequireLowercase = true; // 数据库中至少有一个小写字母
|
||||
options.Password.RequireUppercase = true; // 数据库中至少有一个大写字母
|
||||
options.Password.RequireNonAlphanumeric = true; // 数据库中至少有一个特殊字符
|
||||
options.Password.RequiredLength = 8; // 密码长度最少8位
|
||||
|
||||
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5); // 锁定时间
|
||||
options.Lockout.MaxFailedAccessAttempts = 10; // 尝试次数
|
||||
options.Lockout.AllowedForNewUsers = true; // 新用户是否可以锁定
|
||||
|
||||
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+"; // 用户名允许的字符
|
||||
options.User.RequireUniqueEmail = true; // 允许重复邮箱
|
||||
//options.User.
|
||||
});
|
||||
|
||||
var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), builder.Services);
|
||||
idBuilder.AddEntityFrameworkStores<ApplicationDbContext>()
|
||||
.AddDefaultTokenProviders()
|
||||
.AddUserManager<UserManager<User>>()
|
||||
.AddRoleManager<RoleManager<Role>>();
|
||||
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
// 注入Swagger
|
||||
builder.Services.AddSwaggerService();
|
||||
|
||||
builder.Services.AddHostedService<RsaConfigurattions>();
|
||||
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseWhen(context => context.Request.Path.Value == "/", builder =>
|
||||
builder.Run(context =>
|
||||
{
|
||||
context.Response.Redirect("/swagger");
|
||||
return Task.CompletedTask;
|
||||
}));
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseRouting();
|
||||
app.UseCors("AllowAll");
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
|
||||
app.UseMiddleware<DynamicPermissionMiddleware>();
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
_ = endpoints.MapControllers();
|
||||
});
|
||||
|
||||
|
||||
app.Run();
|
||||
712
LMS.service/Service/MachineService.cs
Normal file
712
LMS.service/Service/MachineService.cs
Normal file
@ -0,0 +1,712 @@
|
||||
using AutoMapper;
|
||||
using LMS.DAO;
|
||||
using LMS.Repository.DTO;
|
||||
using LMS.Repository.DTO.UserDto;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.Models.Machine;
|
||||
using LMS.Tools;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static LMS.Common.Enums.MachineEnum;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
using static LMS.Repository.DTO.MachineResponse.MachineDto;
|
||||
using Machine = LMS.Repository.Models.DB.Machine;
|
||||
|
||||
namespace LMS.service.Service
|
||||
{
|
||||
public class MachineService
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public MachineService(ApplicationDbContext context, IMapper mapper, UserManager<User> userManager)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
_userManager = userManager;
|
||||
}
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前机器码所属的用户是不是可以添加永久机器码
|
||||
/// 检查用户是不是VIP用户
|
||||
/// 检查当前用户是不是已经拥有了最大的数量的机器码
|
||||
/// 检查当前用户是不是还有免费更换次数
|
||||
/// </summary>
|
||||
/// <param name="ownerUser"></param>
|
||||
/// <param name="machine"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<APIResponseModel<string>> CanAddPermanentMachine(User ownerUser, long userId, string? id, bool checkVip)
|
||||
{
|
||||
// 判断是不是VIP
|
||||
if (checkVip && !await _userManager.IsInRoleAsync(ownerUser, "Vip User"))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.UserNotVip);
|
||||
}
|
||||
|
||||
// 判断是不是已经有正在使用的机器码
|
||||
List<Machine> usingMachine = await _context.Machine.Where(x => x.UserID == userId && x.Status == MachineStatus.Active && (x.DeactivationTime == null || x.DeactivationTime >= BeijingTimeExtension.GetBeijingTime()) && (id == null || x.Id != id)).ToListAsync();
|
||||
|
||||
// 判断是不是超过了用户允许的最大机器码数量
|
||||
if ((usingMachine.Count + 1) > ownerUser.AllDeviceCount)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "当前用户正在绑定的机器码数量超过最大数量");
|
||||
}
|
||||
|
||||
// 判断免费更换次数
|
||||
if (ownerUser.FreeCount <= 0)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "当前用户更换机器码的次数已用完");
|
||||
}
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 添加机器码
|
||||
/// <summary>
|
||||
/// 添加机器码
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="reqId"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> AddMachine(MachineModel request, long reqId)
|
||||
{
|
||||
using var transaction = _context.Database.BeginTransaction();
|
||||
try
|
||||
{
|
||||
// 新增
|
||||
// 判断当前用户是否有新增和管理机器码的权限
|
||||
//if (!await _context.Permission.AnyAsync(x => x.UserId == reqId && (x.PermissionCode == SubPermissionType.ManageMachine || x.PermissionCode == SubPermissionType.AddMachine)))
|
||||
//{
|
||||
// return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
//}
|
||||
|
||||
// 请求方法的用户
|
||||
User? user = await _userManager.FindByIdAsync(reqId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// 判断当前机器码是否已经存在
|
||||
if (await _context.Machine.AnyAsync(x => x.MachineId == request.MachineId))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.MachineAlreadyExist);
|
||||
}
|
||||
|
||||
if (request.Status == MachineStatus.Frozen)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "新增机器码不能直接停用");
|
||||
}
|
||||
|
||||
if (request.UserId == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
// 判断OwnerUserId是不是还能添加
|
||||
User? ownerUser = await _userManager.FindByIdAsync(request.UserId.ToString());
|
||||
if (ownerUser == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// 判断是不是管理员,不是管理员,只能添加自己的机器码
|
||||
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(user, "Admin") || await _userManager.IsInRoleAsync(user, "Super Admin");
|
||||
if (!isAdminOrSuperAdmin && ownerUser.Id != reqId)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
|
||||
if (!EnumExtensions.IsValidPermissionType(typeof(MachineUseStatus), request.UseStatus))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "机器码使用状态不正确");
|
||||
}
|
||||
if (!EnumExtensions.IsValidPermissionType(typeof(MachineStatus), request.Status))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "机器码状态不正确");
|
||||
}
|
||||
|
||||
// 判断是不是VIP,不是VIP的话,判断之不是已经存在机器码
|
||||
if (!await _userManager.IsInRoleAsync(ownerUser, "VIP User"))
|
||||
{
|
||||
if (await _context.Machine.AnyAsync(x => x.UserID == ownerUser.Id))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "普通用户只能添加一个机器码");
|
||||
}
|
||||
}
|
||||
|
||||
if (request.UseStatus == MachineUseStatus.Trial)
|
||||
{
|
||||
var checkRes = await CanAddPermanentMachine(ownerUser, (long)request.UserId, null, false);
|
||||
if (checkRes.Code != 1)
|
||||
{
|
||||
return checkRes;
|
||||
}
|
||||
// 必传停用时间
|
||||
if (request.DeactivationTime == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "试用机器码必须传入停用时间");
|
||||
}
|
||||
request.DeactivationTime = request.DeactivationTime?.AddHours(8);
|
||||
|
||||
// 判断停用时间是不是少于当前的
|
||||
if (request.DeactivationTime < BeijingTimeExtension.GetBeijingTime())
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "到期时间不能小于当前时间");
|
||||
}
|
||||
Console.WriteLine(BeijingTimeExtension.GetBeijingTime().ToString());
|
||||
int s = (request.DeactivationTime - BeijingTimeExtension.GetBeijingTime()).Value.Days;
|
||||
// 判断当前时间和现在的时间差大于三天,报错
|
||||
if ((request.DeactivationTime - BeijingTimeExtension.GetBeijingTime()).Value.Days >= 3)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "到期时间不能超过三天");
|
||||
}
|
||||
// 先修改用户的免费更换次数
|
||||
ownerUser.FreeCount -= 1;
|
||||
_context.Users.Update(ownerUser);
|
||||
}
|
||||
else
|
||||
{
|
||||
var checkRes = await CanAddPermanentMachine(ownerUser, (long)request.UserId, null, true);
|
||||
if (checkRes.Code != 1)
|
||||
{
|
||||
return checkRes;
|
||||
}
|
||||
// 先修改用户的免费更换次数
|
||||
ownerUser.FreeCount -= 1;
|
||||
_context.Users.Update(ownerUser);
|
||||
request.DeactivationTime = null;
|
||||
}
|
||||
|
||||
//开始新增
|
||||
Machine machine = _mapper.Map<Machine>(request);
|
||||
machine.Id = Guid.NewGuid().ToString();
|
||||
machine.CreateId = reqId;
|
||||
machine.UpdateId = reqId;
|
||||
machine.CreateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
machine.UpdateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
|
||||
await _context.Machine.AddAsync(machine);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 删除机器码
|
||||
/// <summary>
|
||||
/// 删除机器码
|
||||
/// </summary>
|
||||
/// <param name="machineId"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<object>>> DeleteMachine(string id, long userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
Machine? machine = await _context.Machine.FirstOrDefaultAsync(x => x.Id == id);
|
||||
if (machine == null)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.FindMachineByIdFail);
|
||||
}
|
||||
|
||||
// 开始删除
|
||||
_context.Machine.Remove(machine);
|
||||
await _context.SaveChangesAsync();
|
||||
return APIResponseModel<object>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取机器码状态
|
||||
|
||||
/// <summary>
|
||||
/// 获取机器状态(是否停用和截至时间)
|
||||
/// </summary>
|
||||
/// <param name="machineId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal async Task<ActionResult<APIResponseModel<MachineStatusResponse>>> GetMachineStatus(string machineId)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取对应的machine
|
||||
var machine = await _context.Machine.FirstOrDefaultAsync(x =>
|
||||
x.MachineId == machineId &&
|
||||
((x.DeactivationTime == null && x.UseStatus == MachineUseStatus.Permanent && x.Status == MachineStatus.Active)
|
||||
|| (x.DeactivationTime != null && x.UseStatus == MachineUseStatus.Trial && DateTime.Now < x.DeactivationTime && x.Status == MachineStatus.Active)));
|
||||
|
||||
if (machine == null)
|
||||
{
|
||||
return APIResponseModel<MachineStatusResponse>.CreateErrorResponseModel(ResponseCode.MachineNotFound);
|
||||
}
|
||||
|
||||
MachineStatusResponse machineStatus = _mapper.Map<MachineStatusResponse>(machine);
|
||||
|
||||
return APIResponseModel<MachineStatusResponse>.CreateSuccessResponseModel(ResponseCode.Success, machineStatus);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<MachineStatusResponse>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 修改机器码数据
|
||||
/// <summary>
|
||||
/// 新增/修改机器状态
|
||||
/// </summary>
|
||||
/// <param name="request">请求体</param>
|
||||
/// <param name="reqId">请求ID</param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> ModifyMachine(string machineId, MachineModel request, long reqId)
|
||||
{
|
||||
using var transaction = _context.Database.BeginTransaction();
|
||||
try
|
||||
{
|
||||
// 修改
|
||||
// 判断当前用户是否有修改和管理机器码的权限
|
||||
//if (!await _context.Permission.AnyAsync(x => x.UserId == reqId && (x.PermissionCode == SubPermissionType.ManageMachine || x.PermissionCode == SubPermissionType.ModifyMachine)))
|
||||
//{
|
||||
// return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
//}
|
||||
// 判断传入的userId是否存在
|
||||
User? user = await _userManager.FindByIdAsync(reqId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// 判断当前ID是不是存在
|
||||
var machine = await _context.Machine.FirstOrDefaultAsync(x => x.Id == machineId);
|
||||
if (machine == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindMachineByIdFail);
|
||||
}
|
||||
|
||||
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(user, "Admin") || await _userManager.IsInRoleAsync(user, "Super Admin");
|
||||
if (!isAdminOrSuperAdmin)
|
||||
{
|
||||
if (reqId != machine.UserID || request.MachineId != machine.MachineId)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
if (machine.MachineId != request.MachineId)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "机器码不能修改");
|
||||
}
|
||||
}
|
||||
|
||||
// 判断当前修改后的机器码是否已经存在(不包含自己)
|
||||
if (await _context.Machine.AnyAsync(x => x.MachineId == request.MachineId && x.Id != machineId))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.MachineAlreadyExist);
|
||||
}
|
||||
|
||||
// 将标准时间转换为北京时间
|
||||
request.DeactivationTime = request.DeactivationTime?.AddHours(8);
|
||||
|
||||
// 判断是不是永久改试用
|
||||
if (machine.UseStatus == MachineUseStatus.Permanent && request.UseStatus == MachineUseStatus.Trial)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "机器码不能永久改试用");
|
||||
}
|
||||
|
||||
if (!isAdminOrSuperAdmin)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
|
||||
// 试用,除了管理员之外不能修改
|
||||
if (request.UseStatus == MachineUseStatus.Trial)
|
||||
{
|
||||
// 判断结束时间是不是少于当前的
|
||||
if (request.DeactivationTime != null && request.DeactivationTime < BeijingTimeExtension.GetBeijingTime())
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "到期时间不能小于当前时间");
|
||||
}
|
||||
|
||||
// 判断当前时间和现在的时间差大于三天,报错
|
||||
if (request.DeactivationTime != null && (request.DeactivationTime - BeijingTimeExtension.GetBeijingTime()).Value.Days > 3)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "到期时间不能超过三天");
|
||||
}
|
||||
}
|
||||
else if (request.UseStatus == MachineUseStatus.Permanent)
|
||||
{
|
||||
request.DeactivationTime = null;
|
||||
User? ownerUser = await _userManager.FindByIdAsync(machine.UserID.ToString());
|
||||
if (ownerUser == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
// 判断是不是充试用升级到永久,这边要添加一些判断
|
||||
if (machine.UseStatus == MachineUseStatus.Trial)
|
||||
{
|
||||
var checkRes = await CanAddPermanentMachine(ownerUser, machine.UserID, machine.Id, true);
|
||||
if (checkRes.Code != 1)
|
||||
{
|
||||
return checkRes;
|
||||
}
|
||||
// 先修改用户的免费更换次数
|
||||
ownerUser.FreeCount -= 1;
|
||||
await _userManager.UpdateAsync(ownerUser);
|
||||
}
|
||||
|
||||
// 判断是不是重新激活
|
||||
if (request.Status == MachineStatus.Active && machine.Status == MachineStatus.Frozen)
|
||||
{
|
||||
var checkRes = await CanAddPermanentMachine(ownerUser, machine.UserID, machine.Id, true);
|
||||
if (checkRes.Code != 1)
|
||||
{
|
||||
return checkRes;
|
||||
}
|
||||
// 先修改用户的免费更换次数
|
||||
ownerUser.FreeCount -= 1;
|
||||
await _userManager.UpdateAsync(ownerUser);
|
||||
}
|
||||
}
|
||||
|
||||
// 开始修改
|
||||
machine.UpdateId = reqId;
|
||||
machine.UpdateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
if (request.DeactivationTime != null)
|
||||
{
|
||||
machine.DeactivationTime = request.DeactivationTime;
|
||||
}
|
||||
if (request.Status == MachineStatus.Active && request.UseStatus == MachineUseStatus.Permanent)
|
||||
{
|
||||
machine.DeactivationTime = null;
|
||||
}
|
||||
machine.UseStatus = request.UseStatus;
|
||||
machine.MachineId = request.MachineId;
|
||||
machine.Status = request.Status;
|
||||
machine.Remark = request.Remark;
|
||||
_context.Machine.Update(machine);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 查询机器码列表
|
||||
/// <summary>
|
||||
/// 查询机器码列表
|
||||
/// </summary>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="machineId"></param>
|
||||
/// <param name="createdUserName"></param>
|
||||
/// <param name="status"></param>
|
||||
/// <param name="useStatus"></param>
|
||||
/// <param name="remark"></param>
|
||||
/// <param name="ownUserName"></param>
|
||||
/// <param name="requestUserId"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<CollectionResponse<Machine>>>> QueryMachineCollection(int page, int pageSize, string? machineId, string? createdUserName, MachineStatus? status, MachineUseStatus? useStatus, string? remark, string? ownUserName, long requestUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(requestUserId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<CollectionResponse<Machine>>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
bool isSuperAdmin = await _userManager.IsInRoleAsync(user, "Super Admin");
|
||||
bool isAdmin = await _userManager.IsInRoleAsync(user, "Admin");
|
||||
|
||||
IQueryable<Machine> query = _context.Machine;
|
||||
|
||||
if (isAdmin)
|
||||
{
|
||||
List<long> superAdminUserIds = ((List<User>)await _userManager.GetUsersInRoleAsync("Super Admin")).Select(x => x.Id).ToList();
|
||||
|
||||
//.Result.Select(x => x.Id).ToList();
|
||||
query = query.Where(x => !superAdminUserIds.Contains(x.UserID));
|
||||
}
|
||||
else if (!isSuperAdmin)
|
||||
{
|
||||
query = query.Where(x => x.UserID == requestUserId);
|
||||
}
|
||||
// 添加其他的查询条件
|
||||
if (!string.IsNullOrWhiteSpace(machineId))
|
||||
{
|
||||
query = query.Where(x => x.MachineId == machineId);
|
||||
}
|
||||
// 管理员和超级管理员可以使用该字段查询所有创建者的机器码
|
||||
if (!string.IsNullOrWhiteSpace(createdUserName) && (isAdmin || isSuperAdmin))
|
||||
{
|
||||
List<long> queryUserId = (await _userManager.Users.Where(x => x.UserName.Contains(createdUserName)).ToListAsync()).Select(x => x.Id).ToList();
|
||||
query = query.Where(x => queryUserId.Contains(x.CreateId));
|
||||
}
|
||||
// 普通用户只能查找自己创建的机器码
|
||||
else if (!string.IsNullOrWhiteSpace(createdUserName))
|
||||
{
|
||||
query = query.Where(x => x.CreateId == user.Id);
|
||||
}
|
||||
|
||||
if (status != null)
|
||||
{
|
||||
query = query.Where(x => x.Status == status);
|
||||
}
|
||||
if (useStatus != null)
|
||||
{
|
||||
query = query.Where(x => x.UseStatus == useStatus);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(remark))
|
||||
{
|
||||
query = query.Where(x => x.Remark.Contains(remark));
|
||||
}
|
||||
|
||||
// 管理员和超级管理员可以使用该字段查询所有的机器码的拥有者
|
||||
if (!string.IsNullOrWhiteSpace(ownUserName) && (isAdmin || isSuperAdmin))
|
||||
{
|
||||
List<long> queryUserId = (await _userManager.Users.Where(x => x.UserName.Contains(ownUserName)).ToListAsync()).Select(x => x.Id).ToList();
|
||||
query = query.Where(x => queryUserId.Contains(x.UserID));
|
||||
}
|
||||
// 普通用户只能查找自己拥有的机器码
|
||||
else if (!string.IsNullOrWhiteSpace(ownUserName))
|
||||
{
|
||||
query = query.Where(x => x.UserID == user.Id);
|
||||
}
|
||||
|
||||
int total = await query.CountAsync();
|
||||
|
||||
// 降序,取指定的条数的数据
|
||||
List<Machine> machines = await query.OrderByDescending(x => x.CreateTime).Skip((page - 1) * pageSize).Take(pageSize).ToListAsync();
|
||||
|
||||
return APIResponseModel<CollectionResponse<Machine>>.CreateSuccessResponseModel(ResponseCode.Success, new CollectionResponse<Machine>
|
||||
{
|
||||
Total = total,
|
||||
Collection = machines,
|
||||
Current = page
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<CollectionResponse<Machine>>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 将机器码升级为永久
|
||||
/// <summary>
|
||||
/// 将指定的机器码升级为永久使用
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> UpgradeMachine(string id, long requestUserId)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
User? requestUser = await _userManager.FindByIdAsync(requestUserId.ToString());
|
||||
if (requestUser == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
Machine? machine = await _context.Machine.FirstOrDefaultAsync(x => x.Id == id);
|
||||
if (machine == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindMachineByIdFail);
|
||||
}
|
||||
|
||||
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(requestUser, "Admin") || await _userManager.IsInRoleAsync(requestUser, "Super Admin");
|
||||
|
||||
if (!isAdminOrSuperAdmin && machine.UserID != requestUserId)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
|
||||
User? ownerUser = await _userManager.FindByIdAsync(machine.UserID.ToString());
|
||||
if (ownerUser == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// 判断当前用户是不是可以升级永久
|
||||
// 判断用户是不是VIP
|
||||
if (!await _userManager.IsInRoleAsync(ownerUser, "Vip User"))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.UserNotVip);
|
||||
}
|
||||
|
||||
// 判断是不是已经有正在使用的机器码
|
||||
List<Machine> usingMachine = await _context.Machine.Where(x => x.UserID == machine.UserID && x.Status == MachineStatus.Active && (x.DeactivationTime == null || x.DeactivationTime >= BeijingTimeExtension.GetBeijingTime()) && x.Id != machine.Id).ToListAsync();
|
||||
|
||||
// 判断是不是超过了用户允许的最大机器码数量
|
||||
if ((usingMachine.Count + 1) > ownerUser.AllDeviceCount)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "当前用户正在绑定的机器码数量超过最大数量");
|
||||
}
|
||||
|
||||
// 判断免费更换次数
|
||||
if (ownerUser.FreeCount <= 0)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "当前用户更换机器码的次数已用完");
|
||||
}
|
||||
|
||||
// 判断当前机器码是否已经是永久使用
|
||||
if (machine.Status == MachineStatus.Active && machine.UseStatus == MachineUseStatus.Permanent)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "当前机器码已是永久");
|
||||
}
|
||||
|
||||
// 先修改用户的免费更换次数
|
||||
ownerUser.FreeCount -= 1;
|
||||
await _userManager.UpdateAsync(ownerUser);
|
||||
|
||||
machine.UpdateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
machine.Status = MachineStatus.Active;
|
||||
machine.UseStatus = MachineUseStatus.Permanent;
|
||||
machine.DeactivationTime = null;
|
||||
_context.Machine.Update(machine);
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 将机器码停用
|
||||
/// <summary>
|
||||
/// 一键停用机器码,只有管理员和超级管理员可以操作,普通用户只能停用自己的机器码
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="requestUserId"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> DeactivateMachine(string id, long requestUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(requestUserId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(user, "Admin") || await _userManager.IsInRoleAsync(user, "Super Admin");
|
||||
|
||||
Machine? machine = await _context.Machine.FirstOrDefaultAsync(x => x.Id == id);
|
||||
if (machine == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindMachineByIdFail);
|
||||
}
|
||||
|
||||
if (!isAdminOrSuperAdmin && machine.UserID != requestUserId)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
|
||||
// 判断是不是已经停用
|
||||
if (machine.Status == MachineStatus.Frozen)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "该机器码已经被冻结,不能重复操作");
|
||||
}
|
||||
|
||||
// 开始冻结
|
||||
machine.Status = MachineStatus.Frozen;
|
||||
if (machine.DeactivationTime == null)
|
||||
{
|
||||
machine.DeactivationTime = BeijingTimeExtension.GetBeijingTime();
|
||||
}
|
||||
machine.UpdateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
machine.UpdateId = requestUserId;
|
||||
_context.Update(machine);
|
||||
await _context.SaveChangesAsync();
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取指定的机器码详情
|
||||
/// <summary>
|
||||
/// 获取指定的机器码详情
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal async Task<ActionResult<APIResponseModel<MachineDetailDto>>> GetMachineDetail(string id, long userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(userId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<MachineDetailDto>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
Machine? machine = await _context.Machine.FirstOrDefaultAsync(x => x.Id == id);
|
||||
if (machine == null)
|
||||
{
|
||||
return APIResponseModel<MachineDetailDto>.CreateErrorResponseModel(ResponseCode.FindMachineByIdFail);
|
||||
}
|
||||
|
||||
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(user, "Admin") || await _userManager.IsInRoleAsync(user, "Super Admin");
|
||||
if (!isAdminOrSuperAdmin && machine.UserID != userId)
|
||||
{
|
||||
return APIResponseModel<MachineDetailDto>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
|
||||
MachineDetailDto machineDetail = _mapper.Map<MachineDetailDto>(machine);
|
||||
User? createdUser = await _userManager.FindByIdAsync(machine.CreateId.ToString());
|
||||
User? updatedUser = await _userManager.FindByIdAsync(machine.UpdateId.ToString());
|
||||
User? ownUser = await _userManager.FindByIdAsync(machine.UserID.ToString());
|
||||
machineDetail.CreatedUser = _mapper.Map<UserBaseDto>(createdUser);
|
||||
machineDetail.UpdatedUser = _mapper.Map<UserBaseDto>(createdUser);
|
||||
machineDetail.OwnUser = _mapper.Map<UserBaseDto>(createdUser);
|
||||
|
||||
return APIResponseModel<MachineDetailDto>.CreateSuccessResponseModel(ResponseCode.Success, machineDetail);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<MachineDetailDto>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
460
LMS.service/Service/PermissionService/PermissionService.cs
Normal file
460
LMS.service/Service/PermissionService/PermissionService.cs
Normal file
@ -0,0 +1,460 @@
|
||||
using AutoMapper;
|
||||
using LMS.Common.Enums;
|
||||
using LMS.DAO;
|
||||
using LMS.DAO.MachineDAO;
|
||||
using LMS.DAO.PermissionDAO;
|
||||
using LMS.DAO.RoleDAO;
|
||||
using LMS.DAO.UserDAO;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.Models.Promission;
|
||||
using LMS.Repository.RequestModel.Permission;
|
||||
using LMS.service.Data;
|
||||
using LMS.Tools;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MySqlConnector;
|
||||
using OneOf;
|
||||
using static LMS.Common.Enums.PermissionEnum;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
using PermissionType = LMS.Repository.Models.DB.PermissionType;
|
||||
|
||||
namespace LMS.service.Service.PermissionService
|
||||
{
|
||||
public class PermissionService
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly UserBasicDao _userBasicDAO;
|
||||
private readonly RoleBasicDao _roleBasicDAO;
|
||||
private readonly MachineBasicDao _machineBasicDAO;
|
||||
private readonly PermissionBasicDao _permissionBasicDAO;
|
||||
private readonly PermissionTypeDao _permissionTypeDao;
|
||||
|
||||
public PermissionService(ApplicationDbContext context, IMapper mapper, UserManager<User> userManager, UserBasicDao userBasicDAO, RoleBasicDao roleBasicDAO, MachineBasicDao machineBasicDAO, PermissionBasicDao permissionBasicDao, PermissionTypeDao permissionTypeDao)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
_userManager = userManager;
|
||||
_userBasicDAO = userBasicDAO;
|
||||
_roleBasicDAO = roleBasicDAO;
|
||||
_machineBasicDAO = machineBasicDAO;
|
||||
_permissionBasicDAO = permissionBasicDao;
|
||||
_permissionTypeDao = permissionTypeDao;
|
||||
}
|
||||
|
||||
#region 权限类型
|
||||
|
||||
/// <summary>
|
||||
/// 添加权限类型数据
|
||||
/// </summary>
|
||||
/// <param name="permissionTypeReq"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ActionResult<APIResponseModel<object>>> AddPermissionType(PermissionTypeModel permissionTypeReq, long requestUserId)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// 添加数据
|
||||
PermissionType permissionType = _mapper.Map<PermissionType>(permissionTypeReq);
|
||||
permissionType.Id = Guid.NewGuid().ToString();
|
||||
|
||||
// 判断对应的类型是不是满足条件
|
||||
if (!EnumExtensions.IsValidPermissionType(typeof(PermissionEnum.PermissionType), (int)permissionTypeReq.Type))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
|
||||
// 判断名称,code是不是存在,存在报错
|
||||
if (await _context.PermissionType.AnyAsync(x => x.Name == permissionType.Name || x.Code == permissionType.Code))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.PermissionTypeExist);
|
||||
}
|
||||
|
||||
//// 判断当前用户是不是有新增权限的权限
|
||||
//if (!await _context.Permission.AnyAsync(x => x.UserId == permissionType.CreateUserId && (x.PermissionCode == SubPermissionType.AddAndDeletePermission || x.PermissionCode == SubPermissionType.ManagePermission)))
|
||||
//{
|
||||
// return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
//}
|
||||
|
||||
permissionType.CreateUserId = requestUserId;
|
||||
permissionType.UpdateUserId = requestUserId;
|
||||
permissionType.UpdateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
permissionType.CreateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
// 开始新增
|
||||
await _context.PermissionType.AddAsync(permissionType);
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<object>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 修改权限类型数据
|
||||
/// </summary>
|
||||
/// <param name="permissionId"></param>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="requestUserId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ActionResult<APIResponseModel<object>>> ModifyPermissionType(string permissionId, PermissionTypeModel model, long requestUserId)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// 修改数据
|
||||
PermissionType? permissionType = await _context.PermissionType.FirstOrDefaultAsync(x => x.Id == permissionId);
|
||||
if (permissionType == null)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.FindPermissionTypeByIdFail);
|
||||
}
|
||||
permissionType.Name = model.Name;
|
||||
permissionType.Code = model.Code;
|
||||
permissionType.Type = model.Type;
|
||||
permissionType.UpdateTime = DateTime.Now;
|
||||
|
||||
//// 判断当前用户是不是有修改和管理权限的权限
|
||||
//if (!await _context.Permission.AnyAsync(x => x.UserId == model.UpdateUserId && (x.PermissionCode == model.ModifyPermission || x.PermissionCode == SubPermissionType.ManagePermission)))
|
||||
//{
|
||||
// return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
//}
|
||||
|
||||
// 判断对应的类型是不是满足条件
|
||||
if (!EnumExtensions.IsValidPermissionType(typeof(PermissionEnum.PermissionType), (int)model.Type))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
|
||||
// 判断对应的COde和Name是不是存在,存在报错(不包含当前ID的)
|
||||
if (await _context.PermissionType.AnyAsync(x => x.Name == permissionType.Name && x.Code == permissionType.Code && x.Id != permissionType.Id))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.PermissionTypeExist);
|
||||
}
|
||||
|
||||
permissionType.UpdateUserId = requestUserId;
|
||||
permissionType.Remark = model.Remark;
|
||||
|
||||
_context.PermissionType.Update(permissionType);
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<object>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
transaction.Rollback();
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除权限类型数据
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<object>>> DeletePermissionType(string id, bool relation, long requestUserId)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
PermissionType? permissionType = await _context.PermissionType.FirstOrDefaultAsync(x => x.Id == id);
|
||||
// 判断当前权限类型是不是存在
|
||||
if (permissionType == null)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.FindPermissionTypeByIdFail);
|
||||
}
|
||||
|
||||
//// 判断当前用户是不是有删除权限的权限
|
||||
//if (!await _context.Permission.AnyAsync(x => x.UserId == permissionTypeRequest.UserId && (x.PermissionCode == SubPermissionType.AddAndDeletePermission || x.PermissionCode == SubPermissionType.ManagePermission)))
|
||||
//{
|
||||
// return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
//}
|
||||
|
||||
// 判断当前权限类型是不是有权限被使用
|
||||
var permissions = await _context.Permission
|
||||
.FromSqlRaw("SELECT * FROM Permission WHERE JSON_CONTAINS(PermissionTypeIds, JSON_ARRAY(@id))",
|
||||
new MySqlParameter("@id", id))
|
||||
.ToListAsync();
|
||||
foreach (var item in permissions)
|
||||
{
|
||||
// 判断是不是有,判断是不是要删除对应的关联权限
|
||||
if (relation)
|
||||
{
|
||||
List<string> permissionTypeIds = item.PermissionTypeIdsJson;
|
||||
await Console.Out.WriteLineAsync("1");
|
||||
// 删除对应的权限类型
|
||||
permissionTypeIds.Remove(permissionType.Id);
|
||||
if (permissionTypeIds.Count == 0)
|
||||
{
|
||||
// 删除
|
||||
_context.Permission.Remove(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 更新
|
||||
item.PermissionTypeIdsJson = permissionTypeIds;
|
||||
_context.Permission.Update(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.PermissionTypeExist, "当前权限有关联的子权限,不能直接删除");
|
||||
}
|
||||
}
|
||||
|
||||
// 删除权限类型
|
||||
_context.PermissionType.Remove(permissionType);
|
||||
|
||||
// 提交
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<object>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 权限
|
||||
|
||||
/// <summary>
|
||||
/// 检测不同的类型,判断对应的ID的数据是不是有传入
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<bool> CheckPermissionTypeAndId(PermissionModel model)
|
||||
{
|
||||
switch (model.Type)
|
||||
{
|
||||
case PType.User:
|
||||
if (model.MachineId != null || model.RoleId != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!await _userBasicDAO.CheckUserExistsByID(model.UserId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PType.Role:
|
||||
if (model.MachineId != null || model.UserId != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!await _roleBasicDAO.CheckRoleExistById(model.RoleId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case PType.Machine:
|
||||
if (model.UserId != null || model.RoleId != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (!await _machineBasicDAO.CheckMachineByMachineId(model.MachineId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测不同的类型,获取对应的ID数据
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
private static OneOf<string, long?> GetPermissionRelationIdByType(PermissionModel model)
|
||||
{
|
||||
return model.Type switch
|
||||
{
|
||||
PType.User => model.UserId,
|
||||
PType.Role => model.RoleId,
|
||||
PType.Machine => model.MachineId,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新建权限
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="requestUserId"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<object>>> AddPermission(PermissionModel model, long requestUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 判断Type是不是存在
|
||||
if (!EnumExtensions.IsValidPermissionType(typeof(PType), model.Type))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
|
||||
|
||||
// 检查对应的分类对应的ID是不是存在
|
||||
if (!await CheckPermissionTypeAndId(model))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
|
||||
// 获取对应的ID
|
||||
OneOf<string, long?> relationId = GetPermissionRelationIdByType(model);
|
||||
|
||||
// 判断对应的用户ID,角色ID,机器ID是不是存在相对应的权限,存在的话,不许新增,只能修改
|
||||
if (await _permissionBasicDAO.CheckPermissionByTypeAndId(model.Type, relationId))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.PermissionExist);
|
||||
}
|
||||
|
||||
// 判断传入的permissionTypeId是不是都存在
|
||||
if (!await _permissionTypeDao.CheckPermissionTypeIdsExist(model.PermissionTypeIds))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.FindPermissionTypeByIdFail);
|
||||
}
|
||||
|
||||
// 判断PermissionCode是不是重复
|
||||
if (await _permissionBasicDAO.CheckPermissionCodeExist(model.PermissionCode))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.PermissionCodeExist);
|
||||
}
|
||||
|
||||
// 开始新增
|
||||
Permission permission = _mapper.Map<Permission>(model);
|
||||
permission.Id = Guid.NewGuid().ToString();
|
||||
permission.UpdateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
permission.CreateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
permission.CreateUserId = requestUserId;
|
||||
permission.UpdateUserId = requestUserId;
|
||||
permission.PermissionTypeIdsJson = model.PermissionTypeIds;
|
||||
|
||||
await _context.Permission.AddAsync(permission);
|
||||
await _context.SaveChangesAsync();
|
||||
return APIResponseModel<object>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改权限
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal async Task<ActionResult<APIResponseModel<object>>> ModfiyPermission(string id, PermissionModel model, long requsetUserId)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
Permission? permission = await _context.Permission.FirstOrDefaultAsync(x => x.Id == id);
|
||||
if (permission == null)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.FindPermissionByIdFail);
|
||||
}
|
||||
|
||||
// 判断Type是不是存在
|
||||
if (!EnumExtensions.IsValidPermissionType(typeof(PType), model.Type))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
|
||||
|
||||
if (!await CheckPermissionTypeAndId(model))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.ParameterError);
|
||||
}
|
||||
|
||||
// 获取对应的ID
|
||||
OneOf<string, long?> relationId = GetPermissionRelationIdByType(model);
|
||||
|
||||
// 判断对应的关联ID是不是还有其他的权限,有的话不能修改
|
||||
if (await _permissionBasicDAO.CheckPermissionByTypeAndId(model.Type, relationId))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.PermissionExist);
|
||||
}
|
||||
|
||||
// 判断传入的permissionTypeIDs是不是存在
|
||||
if (!await _permissionTypeDao.CheckPermissionTypeIdsExist(model.PermissionTypeIds))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.FindPermissionTypeByIdFail);
|
||||
}
|
||||
|
||||
// 判断permissionCode是不是重复
|
||||
if (await _permissionBasicDAO.CheckPermissionCodeExist(model.PermissionCode, id))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.PermissionExist);
|
||||
}
|
||||
|
||||
// 开始修改
|
||||
permission.UserId = model.UserId;
|
||||
permission.RoleId = model.RoleId;
|
||||
permission.MachineId = model.MachineId;
|
||||
permission.UpdateUserId = requsetUserId;
|
||||
// 判断是不是有传权限code,没有要获取permissionType的code
|
||||
permission.PermissionCode = model.PermissionCode;
|
||||
|
||||
permission.UpdateTime = BeijingTimeExtension.GetBeijingTime();
|
||||
_context.Permission.Update(permission);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<object>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除权限
|
||||
/// </summary>
|
||||
/// <param name="Id"></param>
|
||||
/// <param name="requestUserId"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> DeletePermission(string Id, long requestUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 判断当前请求的ID是不是存在
|
||||
var permission = await _context.Permission.FirstOrDefaultAsync(x => x.Id == Id);
|
||||
if (permission == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindPermissionByIdFail);
|
||||
}
|
||||
|
||||
// 删除权限
|
||||
_context.Permission.Remove(permission);
|
||||
await _context.SaveChangesAsync();
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel(ResponseCode.Success);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
|
||||
using LMS.DAO;
|
||||
using LMS.service.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LMS.service.Service.PermissionService
|
||||
{
|
||||
public class PremissionValidationService
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
|
||||
public PremissionValidationService(ApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户的权限
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<List<int>> GetUserPermissions(int userId)
|
||||
{
|
||||
return null;
|
||||
//return await _context.UserRoles
|
||||
// .Where(ur => ur.UserId == userId)
|
||||
// .SelectMany(ur => ur.Role.RolePermissions.Select(rp => rp.PermissionId))
|
||||
// .Distinct()
|
||||
// .ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取接口需要的权限
|
||||
/// </summary>
|
||||
/// <param name="httpMethod"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<int?> GetRequiredPermissionForEndpoint(string httpMethod, string path)
|
||||
{
|
||||
return null;
|
||||
//var endpoint = await _context.ApiEndpoints
|
||||
// .FirstOrDefaultAsync(e => e.HttpMethod == httpMethod && e.Path == path);
|
||||
|
||||
//return endpoint?.RequiredPermissionId;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 判断用户权限是不是存在
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="httpMethod"></param>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<bool> HasPermissionForEndpoint(long userId, string httpMethod, object path)
|
||||
{
|
||||
return true;
|
||||
//var userPermissions = await GetUserPermissions(userId);
|
||||
//var requiredPermission = await GetRequiredPermissionForEndpoint(httpMethod, path);
|
||||
|
||||
//return userPermissions.Contains(requiredPermission);
|
||||
}
|
||||
}
|
||||
}
|
||||
296
LMS.service/Service/RoleService/RoleService.cs
Normal file
296
LMS.service/Service/RoleService/RoleService.cs
Normal file
@ -0,0 +1,296 @@
|
||||
using AutoMapper;
|
||||
using LMS.DAO;
|
||||
using LMS.Repository.DTO;
|
||||
using LMS.Repository.DTO.UserDto;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.Role;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
|
||||
namespace LMS.service.Service.RoleService
|
||||
{
|
||||
public class RoleService(RoleManager<Role> roleManager, ApplicationDbContext dbContext, UserManager<User> userManager, IMapper mapper)
|
||||
{
|
||||
private readonly RoleManager<Role> _roleManager = roleManager;
|
||||
private readonly ApplicationDbContext _context = dbContext;
|
||||
private readonly UserManager<User> _userManager = userManager;
|
||||
private readonly IMapper _mapper = mapper;
|
||||
|
||||
/// <summary>
|
||||
/// 创建角色数据
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ActionResult<APIResponseModel<string>>> AddRole(RoleModel model, long userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(model.Name))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError, "角色名不能为空");
|
||||
}
|
||||
|
||||
if (await _roleManager.RoleExistsAsync(model.Name))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.RoleNameExist);
|
||||
}
|
||||
|
||||
await _roleManager.CreateAsync(new Role
|
||||
{
|
||||
Name = model.Name,
|
||||
CreatedUserId = userId,
|
||||
UpdatedUserId = userId,
|
||||
CreatedTime = BeijingTimeExtension.GetBeijingTime(),
|
||||
UpdatedTime = BeijingTimeExtension.GetBeijingTime(),
|
||||
Remark = model.Remark
|
||||
});
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel("添加角色成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 修改角色数据
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> UpdateRole(long id, RoleModel model, long userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
Role? role = _roleManager.FindByIdAsync(id.ToString()).Result;
|
||||
if (role == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindRoleByIdFail);
|
||||
}
|
||||
|
||||
// 判断code是不是存在,不报错自己
|
||||
if (await _roleManager.Roles.FirstOrDefaultAsync(x => x.Name == model.Name && x.Id != id) != null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.RoleNameExist);
|
||||
}
|
||||
|
||||
// 修改
|
||||
role.Name = model.Name;
|
||||
role.Remark = model.Remark;
|
||||
role.UpdatedUserId = userId;
|
||||
role.UpdatedTime = BeijingTimeExtension.GetBeijingTime();
|
||||
await _roleManager.UpdateAsync(role);
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel("修改角色成功");
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除角色数据
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> DeleteRole(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
Role? role = await _roleManager.FindByIdAsync(id.ToString());
|
||||
if (role == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindRoleByIdFail);
|
||||
}
|
||||
if (await _context.UserRoles.AnyAsync(x => x.RoleId == id))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.RoleHasUser);
|
||||
}
|
||||
|
||||
await _roleManager.DeleteAsync(role);
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel("删除角色成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查询角色数据,返回集合
|
||||
/// </summary>
|
||||
/// <param name="page"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="roleName"></param>
|
||||
/// <param name="roleId"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal async Task<ActionResult<APIResponseModel<CollectionResponse<RoleDto>>>> QueryRoleCollection(int page, int pageSize, string? roleName, long? roleId, long requestUserId)
|
||||
{
|
||||
roleName = roleName == "null" ? null : roleName;
|
||||
roleId = roleId == null ? null : roleId;
|
||||
try
|
||||
{
|
||||
// 判断当前用户的角色
|
||||
User? user = await _userManager.FindByIdAsync(requestUserId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<CollectionResponse<RoleDto>>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// TODO
|
||||
//if (!await _userManager.IsInRoleAsync(user, "Super Admin"))
|
||||
//{
|
||||
// return APIResponseModel<CollectionResponse<RoleDto>>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
//}
|
||||
|
||||
// 查询数据,判断是不是传入了roleName和roleId,如果传入了就查询,如果没有就查询全部
|
||||
IQueryable<Role> rolesQueryable = _roleManager.Roles;
|
||||
if (!string.IsNullOrWhiteSpace(roleName))
|
||||
{
|
||||
rolesQueryable = rolesQueryable.Where(x => !string.IsNullOrEmpty(x.Name) && x.Name.Contains(roleName));
|
||||
}
|
||||
|
||||
if (roleId != null)
|
||||
{
|
||||
rolesQueryable = rolesQueryable.Where(x => x.Id == roleId);
|
||||
}
|
||||
// 将插叙出来的数据通过ID降序排序
|
||||
rolesQueryable = rolesQueryable.OrderByDescending(x => x.Id);
|
||||
|
||||
// 查询总数
|
||||
int total = await rolesQueryable.CountAsync();
|
||||
|
||||
// 分页
|
||||
rolesQueryable = rolesQueryable.Skip((page - 1) * pageSize).Take(pageSize);
|
||||
|
||||
|
||||
List<Role> roles = await rolesQueryable.ToListAsync();
|
||||
|
||||
List<RoleDto> roleDtos = roles.Select(x => new RoleDto
|
||||
{
|
||||
Id = x.Id,
|
||||
Name = x.Name ?? string.Empty,
|
||||
CreatedTime = x.CreatedTime,
|
||||
UpdatedTime = x.UpdatedTime,
|
||||
Remark = x.Remark ?? string.Empty,
|
||||
}).ToList();
|
||||
|
||||
for (int i = 0; i < roleDtos.Count; i++)
|
||||
{
|
||||
long createdUserId = roles[i].CreatedUserId;
|
||||
long updatedUserId = roles[i].UpdatedUserId;
|
||||
User? createdUser = await _userManager.FindByIdAsync(createdUserId.ToString());
|
||||
User? updatedUser = await _userManager.FindByIdAsync(updatedUserId.ToString());
|
||||
roleDtos[i].CreatedUser = _mapper.Map<UserBaseDto>(createdUser);
|
||||
roleDtos[i].UpdeatedUser = _mapper.Map<UserBaseDto>(updatedUser);
|
||||
}
|
||||
|
||||
CollectionResponse<RoleDto> collectionResponse = new()
|
||||
{
|
||||
Total = total,
|
||||
Collection = roleDtos,
|
||||
Current = page,
|
||||
};
|
||||
|
||||
return APIResponseModel<CollectionResponse<RoleDto>>.CreateSuccessResponseModel(collectionResponse);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return APIResponseModel<CollectionResponse<RoleDto>>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 查询角色数据,通过角色ID
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ActionResult<APIResponseModel<RoleDto>>> QueryRoleById(long id, long userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(userId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<RoleDto>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// 判断权限
|
||||
|
||||
// 开始查询
|
||||
Role? role = await _roleManager.FindByIdAsync(id.ToString());
|
||||
if (role == null)
|
||||
{
|
||||
return APIResponseModel<RoleDto>.CreateErrorResponseModel(ResponseCode.FindRoleByIdFail);
|
||||
}
|
||||
RoleDto roleDto = new()
|
||||
{
|
||||
Id = role.Id,
|
||||
Name = role.Name ?? string.Empty,
|
||||
CreatedTime = role.CreatedTime,
|
||||
UpdatedTime = role.UpdatedTime,
|
||||
Remark = role.Remark ?? string.Empty
|
||||
};
|
||||
|
||||
long createdUserId = role.CreatedUserId;
|
||||
long updatedUserId = role.UpdatedUserId;
|
||||
User? createdUser = await _userManager.FindByIdAsync(createdUserId.ToString());
|
||||
User? updatedUser = await _userManager.FindByIdAsync(updatedUserId.ToString());
|
||||
roleDto.CreatedUser = _mapper.Map<UserDto>(createdUser);
|
||||
roleDto.UpdeatedUser = _mapper.Map<UserDto>(updatedUser);
|
||||
|
||||
// 判断是不是超级管理员
|
||||
if (roleDto.UpdeatedUser != null && roleDto.CreatedUser != null && !await _userManager.IsInRoleAsync(user, "Super Admin"))
|
||||
{
|
||||
roleDto.UpdeatedUser.PhoneNumber = "***********";
|
||||
roleDto.CreatedUser.PhoneNumber = "***********";
|
||||
roleDto.UpdeatedUser.Email = "***********";
|
||||
roleDto.CreatedUser.Email = "***********";
|
||||
}
|
||||
return APIResponseModel<RoleDto>.CreateSuccessResponseModel(roleDto);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return APIResponseModel<RoleDto>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询角色数据,返回下拉框数据,只要Name
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task<ActionResult<APIResponseModel<List<string>>>> QueryRoleOption(long userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(userId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<List<string>>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// 开始查询
|
||||
List<string> roles = await _roleManager.Roles.Where(x => !string.IsNullOrWhiteSpace(x.Name)).Select(x => x.Name ?? string.Empty).ToListAsync();
|
||||
return APIResponseModel<List<string>>.CreateSuccessResponseModel(roles);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return APIResponseModel<List<string>>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
278
LMS.service/Service/UserService/LoginService.cs
Normal file
278
LMS.service/Service/UserService/LoginService.cs
Normal file
@ -0,0 +1,278 @@
|
||||
|
||||
using LMS.Common.RSAKey;
|
||||
using LMS.DAO;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.Models.User;
|
||||
using LMS.service.Data;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography.Xml;
|
||||
using System.Text;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
|
||||
namespace LMS.service.Service.UserService
|
||||
{
|
||||
public class LoginService
|
||||
{
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly SecurityService _securityService;
|
||||
|
||||
public LoginService(UserManager<User> userManager, ApplicationDbContext context, SecurityService securityService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_context = context;
|
||||
_securityService = securityService;
|
||||
}
|
||||
|
||||
public class LoginResponse
|
||||
{
|
||||
public string Token { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public long Id { get; set; }
|
||||
public string NickName { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成JWT
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public string GenerateJWT(User user)
|
||||
{
|
||||
var claims = new List<Claim>();
|
||||
claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));
|
||||
claims.Add(new Claim(ClaimTypes.Name, user.UserName));
|
||||
// 获取角色(目前只有管理员)
|
||||
claims.Add(new Claim(ClaimTypes.Role, "AdminUser"));
|
||||
//foreach (string role in roles)
|
||||
//{
|
||||
// claims.Add(new Claim(ClaimTypes.Role, role));
|
||||
//}
|
||||
//key是检查签名的密钥
|
||||
if (Environment.GetEnvironmentVariable("SecKey") == null)
|
||||
{
|
||||
throw new Exception("SecKey is not set in environment variables");
|
||||
}
|
||||
|
||||
string key = Environment.GetEnvironmentVariable("SecKey");
|
||||
|
||||
|
||||
//设置Token的过期时间
|
||||
DateTime expires = DateTime.Now.AddHours(1);
|
||||
byte[] secBytes = Encoding.UTF8.GetBytes(key);
|
||||
var secKey = new SymmetricSecurityKey(secBytes);
|
||||
|
||||
//生成数字签名
|
||||
var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);
|
||||
|
||||
//生成JWT中Token
|
||||
var tokenDescriptor = new JwtSecurityToken(claims: claims,
|
||||
expires: expires, signingCredentials: credentials);
|
||||
string jwt = new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
|
||||
return jwt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户登录的服务层方法
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<APIResponseModel<object>> UserLogin(LoginModel model, string ip, ConcurrentDictionary<string, (string Key, DateTime Expiry)> _keyStore)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
if (!_keyStore.TryRemove(model.TokenId, out var keyInfo)) // 没有找到对应的公钥
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.UserPasswordFail);
|
||||
}
|
||||
|
||||
if (BeijingTimeExtension.GetBeijingTime() > keyInfo.Expiry) // 公钥超时
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.UserPasswordFail);
|
||||
}
|
||||
|
||||
var rsaKeyId = keyInfo.Key;
|
||||
var privateKey = _securityService.DecryptWithAES(rsaKeyId);
|
||||
|
||||
string decryptedPassword = RsaKeyPairGenerator.Decrypt(privateKey, model.Password);
|
||||
|
||||
User? user = null;
|
||||
if ((int)(model.LoginType) == 1) //用户名密码登录
|
||||
{
|
||||
if (model.UserName == null)
|
||||
{
|
||||
throw new ArgumentNullException("UserName");
|
||||
}
|
||||
user = await _userManager.FindByNameAsync(model.UserName);
|
||||
}
|
||||
else if ((int)(model.LoginType) == 0) //邮箱登录
|
||||
{
|
||||
if (model.Email == null)
|
||||
{
|
||||
throw new ArgumentNullException("Email");
|
||||
}
|
||||
user = await _userManager.FindByEmailAsync(model.Email);
|
||||
}
|
||||
else
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.UndefinedLoginType);
|
||||
}
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.FindUserByNameFail);
|
||||
}
|
||||
|
||||
if (await _userManager.IsLockedOutAsync(user))
|
||||
{
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.UserIsLockedOut);
|
||||
}
|
||||
|
||||
var result = await _userManager.CheckPasswordAsync(user, decryptedPassword);
|
||||
if (!result)
|
||||
{
|
||||
// 失败计数器加1
|
||||
await _userManager.AccessFailedAsync(user);
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.UserPasswordFail);
|
||||
}
|
||||
// 密码正确,返回token
|
||||
string jwt = GenerateJWT(user);
|
||||
|
||||
// 生成一个刷新Token
|
||||
//var refreshToken = Guid.NewGuid().ToString();
|
||||
var securityService = new SecurityService(_context);
|
||||
RefreshTokens refreshTokens = await securityService.CreateRefreshTokenByUserId(user.Id, ip, model.DeviceInfo);
|
||||
await _context.RefreshTokens.AddAsync(refreshTokens);
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
|
||||
|
||||
return APIResponseModel<object>.CreateSuccessResponseModel(new LoginResponse()
|
||||
{
|
||||
Token = jwt,
|
||||
UserName = user.UserName,
|
||||
Id = user.Id,
|
||||
NickName = user.NickName,
|
||||
RefreshToken = refreshTokens.Token
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<object>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新token的方法
|
||||
/// </summary>
|
||||
/// <param name="refreshToken"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> RefreshToken(RefreshTokenModel model, string ip, string refreshToken)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
Boolean isValid = await _securityService.ValidateRefreshToken(refreshToken, model.UserId, model.DeviceInfo, ip);
|
||||
if (!isValid)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.RefreshTokenInvalid);
|
||||
}
|
||||
|
||||
// 开始生成token
|
||||
User? user = await _userManager.FindByIdAsync(model.UserId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// 这边修改ip
|
||||
|
||||
string jwt = GenerateJWT(user);
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel(jwt);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#region 将用户设置为代理
|
||||
/// <summary>
|
||||
/// 将用户设置为代理,要做一系列检查
|
||||
/// </summary>
|
||||
/// <param name="requestUserId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> EnableAgent(long requestUserId)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(requestUserId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// 判断当前用户是不是VIP,只有VIP才能成为代理
|
||||
if (!await _userManager.IsInRoleAsync(user, "VIP User"))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "当前用户不是VIP,不能成为代理");
|
||||
}
|
||||
|
||||
// 检查是否已经是代理
|
||||
if (await _userManager.IsInRoleAsync(user, "Agent User"))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidOptions, "当前用户已是代理,不能重复操作");
|
||||
}
|
||||
// 生成六位邀请码,并且不能重复
|
||||
string affiliateCode = "";
|
||||
do
|
||||
{
|
||||
affiliateCode = new Random().Next(100000, 999999).ToString("D6");
|
||||
} while (await _context.Users.AnyAsync(u => u.AffiliateCode == affiliateCode));
|
||||
|
||||
// 修改分成位默认
|
||||
user.AgentPercent = 0.50;
|
||||
// 开始修改数据库
|
||||
Role? role = await _context.Roles.FirstOrDefaultAsync(r => r.Name == "Agent User");
|
||||
if (role == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindRoleByIdFail);
|
||||
}
|
||||
await _context.UserRoles.AddAsync(new IdentityUserRole<long>
|
||||
{
|
||||
RoleId = role.Id,
|
||||
UserId = user.Id
|
||||
});
|
||||
|
||||
if (string.IsNullOrWhiteSpace(user.AffiliateCode))
|
||||
{
|
||||
user.AffiliateCode = affiliateCode;
|
||||
}
|
||||
await _userManager.UpdateAsync(user);
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel("用户已成功升级为代理");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
230
LMS.service/Service/UserService/SecurityService.cs
Normal file
230
LMS.service/Service/UserService/SecurityService.cs
Normal file
@ -0,0 +1,230 @@
|
||||
using LMS.Common.RSAKey;
|
||||
using LMS.DAO;
|
||||
using LMS.Repository.DB;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.User;
|
||||
using LMS.service.Data;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
|
||||
namespace LMS.service.Service.UserService
|
||||
{
|
||||
public class SecurityService
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
|
||||
public SecurityService(ApplicationDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
#region 刷新令牌
|
||||
|
||||
/// <summary>
|
||||
/// 生成刷新令牌
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GenerateRefreshToken()
|
||||
{
|
||||
var randomNumber = new byte[32];
|
||||
using (var rng = RandomNumberGenerator.Create())
|
||||
{
|
||||
rng.GetBytes(randomNumber);
|
||||
return Convert.ToBase64String(randomNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置令牌的刷新时间
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static DateTime GetRefreshTokenExpiryTime()
|
||||
{
|
||||
return BeijingTimeExtension.GetBeijingTime().AddDays(7); // 设置刷新令牌7天后过期
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证刷新令牌是否正确
|
||||
/// </summary>
|
||||
/// <param name="token">刷新token</param>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <param name="deviceInfo">设备信息</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> ValidateRefreshToken(string token, long userId, string deviceInfo, string ip)
|
||||
{
|
||||
RefreshTokens? refreshTokens = await _context.RefreshTokens.FirstOrDefaultAsync(x => x.Token == token && x.UserId == userId);
|
||||
if (refreshTokens == null)
|
||||
{
|
||||
return false; // 用户对应的令牌不存在
|
||||
}
|
||||
if (BeijingTimeExtension.GetBeijingTime() > refreshTokens.Expiration)
|
||||
{
|
||||
_context.Remove(refreshTokens);
|
||||
return false; // 刷新令牌过期
|
||||
}
|
||||
if (refreshTokens.DeviceInfo != deviceInfo)
|
||||
{
|
||||
_context.Remove(refreshTokens); // 不同的设备登录
|
||||
return false;
|
||||
}
|
||||
// 刷新令牌通过,修改当前ip
|
||||
refreshTokens.LastCheckIp = ip;
|
||||
await _context.SaveChangesAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 组合一个刷新令牌的实体类 用于存储到数据库
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
public async Task<RefreshTokens> CreateRefreshTokenByUserId(long userId, string ip, string deviceInfo)
|
||||
{
|
||||
// 判断当前用户是否已经有了刷新令牌,如果有则删除
|
||||
var oldRefreshToken = await _context.RefreshTokens.FirstOrDefaultAsync(x => x.UserId == userId);
|
||||
if (oldRefreshToken != null)
|
||||
{
|
||||
_context.RefreshTokens.Remove(oldRefreshToken);
|
||||
}
|
||||
// 创建新的刷新令牌
|
||||
var refreshToken = GenerateRefreshToken();
|
||||
var expiryTime = GetRefreshTokenExpiryTime();
|
||||
|
||||
// 添加刷新令牌到数据库
|
||||
RefreshTokens refreshTokens = new()
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
UserId = userId,
|
||||
Token = refreshToken,
|
||||
Expiration = expiryTime,
|
||||
Revoked = false,
|
||||
CreatedTime = BeijingTimeExtension.GetBeijingTime(),
|
||||
LastCheckIp = ip,
|
||||
DeviceInfo = deviceInfo
|
||||
};
|
||||
return refreshTokens;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 登录密码密钥生成和解密
|
||||
|
||||
/// <summary>
|
||||
/// 生成公钥
|
||||
/// </summary>
|
||||
/// <param name="_keyStore"></param>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<APIResponseModel<PublicKeyResponse>> GetPublicKey(ConcurrentDictionary<string, (string Key, DateTime Expiry)> _keyStore)
|
||||
{
|
||||
try
|
||||
{
|
||||
RsaKeys? rsa = await _context.RsaKeys.OrderBy(x => x.UseCount).FirstOrDefaultAsync();
|
||||
if (rsa == null)
|
||||
{
|
||||
return APIResponseModel<PublicKeyResponse>.CreateErrorResponseModel(ResponseCode.SystemError, "No RSA key found.");
|
||||
}
|
||||
|
||||
// 更新使用次数
|
||||
rsa.UseCount++;
|
||||
_context.Update(rsa);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
string token = Guid.NewGuid().ToString();
|
||||
|
||||
// 这边检查下所有超时的Key,删掉
|
||||
foreach (var item in _keyStore)
|
||||
{
|
||||
if (item.Value.Expiry < BeijingTimeExtension.GetBeijingTime())
|
||||
{
|
||||
_keyStore.TryRemove(item.Key, out _);
|
||||
}
|
||||
}
|
||||
|
||||
_keyStore[token] = (rsa.Id, BeijingTimeExtension.GetBeijingTime().AddSeconds(30));
|
||||
|
||||
PublicKeyResponse publicKeyResponse = new()
|
||||
{
|
||||
Token = token,
|
||||
PublicKey = rsa.PublicKey
|
||||
};
|
||||
return APIResponseModel<PublicKeyResponse>.CreateSuccessResponseModel(publicKeyResponse);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return APIResponseModel<PublicKeyResponse>.CreateErrorResponseModel(ResponseCode.SystemError, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private const int NonceSize = 12;
|
||||
private const int TagSize = 16;
|
||||
|
||||
/// <summary>
|
||||
/// 解码加密后的密码
|
||||
/// </summary>
|
||||
/// <param name="cipherText"></param>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
//public string DecryptWithAES(string cipherText, byte[] key)
|
||||
//{
|
||||
// if (key.Length != 32)
|
||||
// {
|
||||
// throw new ArgumentException("Invalid key length. Expected 32 bytes.", nameof(key));
|
||||
// }
|
||||
|
||||
// byte[] cipherData = Convert.FromBase64String(cipherText);
|
||||
|
||||
// if (cipherData.Length < NonceSize + TagSize)
|
||||
// {
|
||||
// throw new ArgumentException("Cipher text is too short", nameof(cipherText));
|
||||
// }
|
||||
|
||||
// byte[] nonce = new byte[NonceSize];
|
||||
// byte[] cipherTextWithTag = new byte[cipherData.Length - NonceSize];
|
||||
// Array.Copy(cipherData, nonce, NonceSize);
|
||||
// Array.Copy(cipherData, NonceSize, cipherTextWithTag, 0, cipherTextWithTag.Length);
|
||||
|
||||
// using var aes = new AesGcm(key, TagSize);
|
||||
|
||||
// byte[] plaintext = new byte[cipherTextWithTag.Length - TagSize];
|
||||
|
||||
// aes.Decrypt(nonce, cipherTextWithTag, null, plaintext, cipherTextWithTag.AsSpan(cipherTextWithTag.Length - TagSize));
|
||||
|
||||
// return Encoding.UTF8.GetString(plaintext);
|
||||
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 解密密钥
|
||||
/// </summary>
|
||||
/// <param name="cipherText"></param>
|
||||
/// <param name="rasKeyId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public string DecryptWithAES(string rasKeyId)
|
||||
{
|
||||
try
|
||||
{
|
||||
RsaKeys? rsa = _context.RsaKeys.FirstOrDefault(x => x.Id == rasKeyId) ?? throw new Exception("未找到对应的RSA密钥");
|
||||
|
||||
string secertIV = rsa.EncryptionIV;
|
||||
string secertKey = rsa.EncryptionKey;
|
||||
|
||||
byte[] key = ComplexKeyObfuscator.Deobfuscate(Convert.FromBase64String(secertKey));
|
||||
byte[] iv = ComplexKeyObfuscator.Deobfuscate(Convert.FromBase64String(secertIV));
|
||||
|
||||
string privateKey = AESGenerate.Decrypt(rsa.EncryptedPrivateKey, key, iv);
|
||||
return privateKey;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception("密码解密失败");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
482
LMS.service/Service/UserService/UserService.cs
Normal file
482
LMS.service/Service/UserService/UserService.cs
Normal file
@ -0,0 +1,482 @@
|
||||
using LMS.Common.RSAKey;
|
||||
using LMS.DAO;
|
||||
using LMS.Repository.DTO;
|
||||
using LMS.Repository.DTO.UserDto;
|
||||
using LMS.Repository.Models.DB;
|
||||
using LMS.Repository.Models.User;
|
||||
using LMS.Repository.User;
|
||||
using LMS.Tools.Extensions;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Collections.Concurrent;
|
||||
using static LMS.Common.Enums.ResponseCodeEnum;
|
||||
|
||||
namespace LMS.service.Service.UserService
|
||||
{
|
||||
public class UserService(UserManager<User> userManager, RoleManager<Role> roleManager, ApplicationDbContext context, SecurityService securityService)
|
||||
{
|
||||
private readonly UserManager<User> _userManager = userManager;
|
||||
private readonly RoleManager<Role> _roleManager = roleManager;
|
||||
private readonly ApplicationDbContext _context = context;
|
||||
private readonly SecurityService _securityService = securityService;
|
||||
|
||||
#region 获取用户信息
|
||||
/// <summary>
|
||||
/// 获取用户信息的方法
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="requestUserId"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<UserDto>>> GetUserInfo(long userId, long requestUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(userId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<UserDto>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
if (userId != requestUserId)
|
||||
{
|
||||
// 这边单独的判断是否有权限
|
||||
User? requertUser = await _userManager.FindByIdAsync(requestUserId.ToString());
|
||||
if (requertUser == null)
|
||||
{
|
||||
return APIResponseModel<UserDto>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(requertUser, "Super Admin") || await _userManager.IsInRoleAsync(requertUser, "Admin");
|
||||
|
||||
// 判断角色
|
||||
if (!isAdminOrSuperAdmin)
|
||||
{
|
||||
return APIResponseModel<UserDto>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
}
|
||||
|
||||
List<string>? roles = [.. (await _userManager.GetRolesAsync(user))];
|
||||
|
||||
UserDto userDto = new()
|
||||
{
|
||||
Id = user.Id,
|
||||
UserName = user.UserName ?? string.Empty,
|
||||
NickName = user.NickName,
|
||||
Email = user.Email ?? string.Empty,
|
||||
PhoneNumber = user.PhoneNumber ?? string.Empty,
|
||||
Avatar = string.Empty,
|
||||
RoleNames = roles,
|
||||
CreatedDate = user.CreatedDate,
|
||||
AllDeviceCount = user.AllDeviceCount,
|
||||
FreeCount = user.FreeCount,
|
||||
Options = user.OptionsJson,
|
||||
AgentPercent = user.AgentPercent,
|
||||
AffiliateCode = user.AffiliateCode,
|
||||
ParentId = user.ParentId ?? 0
|
||||
};
|
||||
return APIResponseModel<UserDto>.CreateSuccessResponseModel(userDto);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<UserDto>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 查询用户列表
|
||||
|
||||
internal async Task<ActionResult<APIResponseModel<CollectionResponse<UserCollectionDto>>>> QueryUserCollection(int page, int pageSize, string userName, long? userId, string nickName, string phoneNumber, string email, string[] roleNames, long? parentId, long reuqertUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(reuqertUserId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<CollectionResponse<UserCollectionDto>>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(user, "Super Admin") || await _userManager.IsInRoleAsync(user, "Admin");
|
||||
bool isSuperAdmin = await _userManager.IsInRoleAsync(user, "Super Admin");
|
||||
bool isAgent = !isAdminOrSuperAdmin && await _userManager.IsInRoleAsync(user, "Agent User");
|
||||
if (!isAdminOrSuperAdmin && !isAgent)
|
||||
{
|
||||
return APIResponseModel<CollectionResponse<UserCollectionDto>>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
|
||||
List<long> roleIds = [];
|
||||
List<long> userIds = [];
|
||||
// 先查询指定的角色名字对应的用户,再对用户进行筛选
|
||||
if (roleNames != null && roleNames.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < roleNames.Length; i++)
|
||||
{
|
||||
Role? role = await _roleManager.FindByNameAsync(roleNames[i]);
|
||||
if (role == null)
|
||||
{
|
||||
return APIResponseModel<CollectionResponse<UserCollectionDto>>.CreateErrorResponseModel(ResponseCode.FindRoleByIdFail);
|
||||
}
|
||||
roleIds.Add(role.Id);
|
||||
}
|
||||
// 找到和角色ID对应的用户ID
|
||||
userIds = await _context.UserRoles.Where(x => roleIds.Contains(x.RoleId)).Select(x => x.UserId).Distinct().ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
// 开始查询数据
|
||||
IQueryable<User>? query = _userManager.Users;
|
||||
|
||||
if (isAgent)
|
||||
{
|
||||
query = query.Where(x => x.ParentId == user.Id);
|
||||
}
|
||||
// 判断是不是管理员
|
||||
IList<User> superUsers = await _userManager.GetUsersInRoleAsync("Super Admin");
|
||||
List<long> superUserIds = superUsers.Select(x => x.Id).ToList();
|
||||
// 默认把自己排除
|
||||
//query = query.Where(x => x.Id != reuqertUserId);
|
||||
if (!isSuperAdmin)
|
||||
{
|
||||
// 不是草鸡管理员,就把超级管理员排除
|
||||
query = query.Where(x => reuqertUserId == x.Id || (!superUserIds.Contains(x.ParentId ?? 0) && !superUserIds.Contains(x.Id)));
|
||||
}
|
||||
|
||||
// 添加查询条件
|
||||
if (!string.IsNullOrWhiteSpace(userName))
|
||||
{
|
||||
query = query.Where(x => !string.IsNullOrWhiteSpace(x.UserName) && x.UserName.Contains(userName));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(nickName))
|
||||
{
|
||||
query = query.Where(x => !string.IsNullOrWhiteSpace(x.NickName) && x.NickName.Contains(nickName));
|
||||
}
|
||||
|
||||
if (userId != null)
|
||||
{
|
||||
query = query.Where(x => x.Id == userId);
|
||||
}
|
||||
|
||||
if (parentId != null)
|
||||
{
|
||||
query = query.Where(x => x.ParentId == parentId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(phoneNumber))
|
||||
{
|
||||
query = query.Where(x => !string.IsNullOrWhiteSpace(x.PhoneNumber) && x.PhoneNumber.Contains(phoneNumber));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(email))
|
||||
{
|
||||
query = query.Where(x => !string.IsNullOrWhiteSpace(x.Email) && x.Email.Contains(email));
|
||||
}
|
||||
|
||||
if (roleIds.Count > 0)
|
||||
{
|
||||
query = query.Where(x => userIds.Contains(x.Id));
|
||||
}
|
||||
|
||||
// 通过ID降序
|
||||
query = query.OrderByDescending(x => x.Id);
|
||||
|
||||
// 查询总数
|
||||
int total = await query.CountAsync();
|
||||
|
||||
// 分页
|
||||
query = query.Skip((page - 1) * pageSize).Take(pageSize);
|
||||
|
||||
List<User>? users = await query.ToListAsync();
|
||||
|
||||
List<UserCollectionDto>? userCollections = users.Select(x =>
|
||||
new UserCollectionDto
|
||||
{
|
||||
Id = x.Id,
|
||||
UserName = x.UserName ?? string.Empty,
|
||||
NickName = x.NickName,
|
||||
Email = x.Email ?? string.Empty,
|
||||
PhoneNumber = x.PhoneNumber ?? string.Empty,
|
||||
CreatedDate = x.CreatedDate,
|
||||
LastLoginDate = x.LastLoginDate,
|
||||
LastLoginIp = x.LastLoginIp,
|
||||
LastLoginDevice = x.LastLoginDevice,
|
||||
ParentId = x.ParentId ?? 0
|
||||
}).ToList();
|
||||
for (int i = 0; i < userCollections.Count; i++)
|
||||
{
|
||||
List<string>? roles = [.. (await _userManager.GetRolesAsync(users[i]))];
|
||||
userCollections[i].RoleNames = roles;
|
||||
if (!isAdminOrSuperAdmin)
|
||||
{
|
||||
userCollections[i].PhoneNumber = "***********";
|
||||
userCollections[i].Email = "***********";
|
||||
}
|
||||
}
|
||||
|
||||
return APIResponseModel<CollectionResponse<UserCollectionDto>>.CreateSuccessResponseModel(new CollectionResponse<UserCollectionDto>
|
||||
{
|
||||
Total = total,
|
||||
Collection = userCollections,
|
||||
Current = page,
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<CollectionResponse<UserCollectionDto>>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 修改用户信息
|
||||
/// <summary>
|
||||
/// 修改用户信息
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="userModel"></param>
|
||||
/// <param name="reuqertUserId"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task<ActionResult<APIResponseModel<string>>> UpdatedUser(long id, UpdatedUserModel userModel, long requestUserId)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(id.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
// 检查当前用户的权限
|
||||
User? requestUser = await _userManager.FindByIdAsync(requestUserId.ToString());
|
||||
if (requestUser == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(requestUser, "Super Admin") || await _userManager.IsInRoleAsync(requestUser, "Admin");
|
||||
if (requestUserId != id && !isAdminOrSuperAdmin)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
|
||||
// 开始修改用户信息
|
||||
if (userModel.AgentPercent != null)
|
||||
{
|
||||
user.AgentPercent = userModel.AgentPercent.Value;
|
||||
}
|
||||
if (userModel.AllDeviceCount != null)
|
||||
{
|
||||
user.AllDeviceCount = userModel.AllDeviceCount.Value;
|
||||
}
|
||||
if (userModel.FreeCount != null)
|
||||
{
|
||||
user.FreeCount = userModel.FreeCount.Value;
|
||||
}
|
||||
if (userModel.NickName != null)
|
||||
{
|
||||
user.NickName = userModel.NickName;
|
||||
}
|
||||
if (userModel.UserName != null)
|
||||
{
|
||||
user.UserName = userModel.UserName;
|
||||
user.NormalizedUserName = userModel.UserName.ToUpper();
|
||||
}
|
||||
if (userModel.Email != null)
|
||||
{
|
||||
user.Email = userModel.Email;
|
||||
user.NormalizedEmail = userModel.Email.ToUpper();
|
||||
}
|
||||
if (userModel.PhoneNumber != null)
|
||||
{
|
||||
user.PhoneNumber = userModel.PhoneNumber;
|
||||
}
|
||||
|
||||
// 只有管理员才能修改角色
|
||||
if (isAdminOrSuperAdmin)
|
||||
{
|
||||
// 开始删除之前的绑定关系
|
||||
List<IdentityUserRole<long>> userRoles = await _context.UserRoles.Where(x => x.UserId == id).ToListAsync();
|
||||
_context.UserRoles.RemoveRange(userRoles);
|
||||
|
||||
// 判断是不是所有的角色名都存在
|
||||
if (userModel.RoleNames != null && userModel.RoleNames.Count > 0)
|
||||
{
|
||||
// 将之前的绑定关系全部删掉,重新绑定
|
||||
List<long> roleIds = [];
|
||||
for (int i = 0; i < userModel.RoleNames.Count; i++)
|
||||
{
|
||||
Role? role = await _roleManager.FindByNameAsync(userModel.RoleNames[i]);
|
||||
if (role == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.FindRoleByIdFail);
|
||||
}
|
||||
roleIds.Add(role.Id);
|
||||
}
|
||||
|
||||
// 开始新增
|
||||
List<IdentityUserRole<long>> userRole = roleIds.Select(x => new IdentityUserRole<long>
|
||||
{
|
||||
UserId = id,
|
||||
RoleId = x
|
||||
}).ToList();
|
||||
|
||||
await _context.UserRoles.AddRangeAsync(userRole);
|
||||
}
|
||||
}
|
||||
_context.Update(user);
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel("修改成功");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 获取用户代理信息
|
||||
/// <summary>
|
||||
/// 获取用户代理信息
|
||||
/// </summary>
|
||||
/// <param name="requestUserId"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<UserAgentInfoDto>>> GetUserAgentInfo(long requestUserId)
|
||||
{
|
||||
try
|
||||
{
|
||||
User? user = await _userManager.FindByIdAsync(requestUserId.ToString());
|
||||
if (user == null)
|
||||
{
|
||||
return APIResponseModel<UserAgentInfoDto>.CreateErrorResponseModel(ResponseCode.FindUserByIdFail);
|
||||
}
|
||||
|
||||
bool isAdminOrSuperAdmin = await _userManager.IsInRoleAsync(user, "Super Admin") || await _userManager.IsInRoleAsync(user, "Admin");
|
||||
|
||||
// 判断当前用户是不是代理
|
||||
if (!isAdminOrSuperAdmin && !await _userManager.IsInRoleAsync(user, "Agent User"))
|
||||
{
|
||||
return APIResponseModel<UserAgentInfoDto>.CreateErrorResponseModel(ResponseCode.NotPermissionAction);
|
||||
}
|
||||
|
||||
// 查询所有用户,判断他的parentId是不是当前用户
|
||||
int allUserCount = await _context.Users.Where(x => x.ParentId == requestUserId).CountAsync();
|
||||
// 查询所有在VIP User角色中的用户
|
||||
Role? role = await _roleManager.FindByNameAsync("VIP User");
|
||||
if (role == null)
|
||||
{
|
||||
return APIResponseModel<UserAgentInfoDto>.CreateErrorResponseModel(ResponseCode.FindRoleByIdFail);
|
||||
}
|
||||
int vipUserCount = await _context.UserRoles
|
||||
.Where(ur => ur.RoleId == role.Id)
|
||||
.Join(_context.Users,
|
||||
ur => ur.UserId,
|
||||
u => u.Id,
|
||||
(ur, u) => u)
|
||||
.CountAsync(u => u.ParentId == requestUserId);
|
||||
|
||||
UserAgentInfoDto userAgentInfoDto = new()
|
||||
{
|
||||
UserId = user.Id,
|
||||
UserName = user.UserName ?? string.Empty,
|
||||
NickName = user.NickName,
|
||||
AffiliateCode = user.AffiliateCode,
|
||||
AgentPercent = user.AgentPercent,
|
||||
AffiliateNumber = allUserCount,
|
||||
AffiliateVIPNumber = vipUserCount,
|
||||
AffiliateMoney = 0
|
||||
};
|
||||
return APIResponseModel<UserAgentInfoDto>.CreateSuccessResponseModel(userAgentInfoDto);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return APIResponseModel<UserAgentInfoDto>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 用户注册
|
||||
|
||||
/// <summary>
|
||||
/// 用户注册
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="_keyStore"></param>
|
||||
/// <returns></returns>
|
||||
internal async Task<ActionResult<APIResponseModel<string>>> Register(RegisterModel model, ConcurrentDictionary<string, (string Key, DateTime Expiry)> _keyStore)
|
||||
{
|
||||
using var transaction = await _context.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
if (!_keyStore.TryRemove(model.TokenId, out var keyInfo)) // 没有找到对应的公钥
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.UserPasswordFail);
|
||||
}
|
||||
|
||||
if (BeijingTimeExtension.GetBeijingTime() > keyInfo.Expiry) // 公钥超时
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.UserPasswordFail);
|
||||
}
|
||||
|
||||
// 判断邀请码是不是存在
|
||||
if (string.IsNullOrWhiteSpace(model.AffiliateCode))
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.ParameterError, "邀请码必填");
|
||||
}
|
||||
User? affiliateUser = await _userManager.Users.FirstOrDefaultAsync(x => x.AffiliateCode == model.AffiliateCode);
|
||||
if (affiliateUser == null)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.InvalidAffiliateCode);
|
||||
}
|
||||
|
||||
var rsaKeyId = keyInfo.Key;
|
||||
var privateKey = _securityService.DecryptWithAES(rsaKeyId);
|
||||
|
||||
string decryptedPassword = RsaKeyPairGenerator.Decrypt(privateKey, model.Password);
|
||||
|
||||
var user = new User { UserName = model.UserName, Email = model.Email ?? string.Empty, NickName = model.UserName };
|
||||
|
||||
var result = await _userManager.CreateAsync(user, decryptedPassword);
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
foreach (var s in result.Errors)
|
||||
{
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.UserRegisterFial, s.Description);
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
await _userManager.AddToRoleAsync(user, "Simple User");
|
||||
// 给用户设置初始值
|
||||
user.AllDeviceCount = 1;
|
||||
user.AgentPercent = 0.50;
|
||||
user.FreeCount = 10;
|
||||
user.ParentId = affiliateUser.Id;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// 如果添加角色失败,删除用户
|
||||
await _userManager.DeleteAsync(user);
|
||||
throw;
|
||||
}
|
||||
await _userManager.UpdateAsync(user);
|
||||
await _context.SaveChangesAsync();
|
||||
await transaction.CommitAsync();
|
||||
return APIResponseModel<string>.CreateSuccessResponseModel(ResponseCode.Success, "User Register Success");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
await transaction.RollbackAsync();
|
||||
return APIResponseModel<string>.CreateErrorResponseModel(ResponseCode.SystemError, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
8
LMS.service/appsettings.Development.json
Normal file
8
LMS.service/appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
LMS.service/appsettings.json
Normal file
9
LMS.service/appsettings.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
1
docker.txt
Normal file
1
docker.txt
Normal file
@ -0,0 +1 @@
|
||||
docker build -t lms-service .
|
||||
Loading…
x
Reference in New Issue
Block a user