Compare commits
3 commits
v2
...
Applicatio
Author | SHA1 | Date | |
---|---|---|---|
2b85ffd93b | |||
c0533d78fb | |||
8dc1130d2a |
8
.gitattributes
vendored
8
.gitattributes
vendored
|
@ -1,2 +1,10 @@
|
||||||
# Auto detect text files and perform LF normalization
|
# Auto detect text files and perform LF normalization
|
||||||
* text=auto
|
* text=auto
|
||||||
|
Moonlight/wwwroot/** linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/js/scripts.bundle.js linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/js/widgets.bundle.js linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/js/theme.js linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/css/boxicons.min.css linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/css/style.bundle.css linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/plugins/** linguist-vendored
|
||||||
|
Moonlight/wwwroot/assets/fonts/** linguist-vendored
|
||||||
|
|
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
|
@ -1,2 +0,0 @@
|
||||||
# These are supported funding model platforms
|
|
||||||
ko_fi: masuowo
|
|
87
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
87
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
|
@ -1,87 +0,0 @@
|
||||||
name: Bug Report
|
|
||||||
description: Something isn't working quite right in the software.
|
|
||||||
labels: [not confirmed]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Bug reports should only be used for reporting issues with how the software works. For assistance installing this software, as well as debugging issues with dependencies, please use our [Discord server](https://discord.gg/TJaspT7A8p).
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Current Behavior
|
|
||||||
description: Please provide a clear & concise description of the issue.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Expected Behavior
|
|
||||||
description: Please describe what you expected to happen.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Steps to Reproduce
|
|
||||||
description: Please be as detailed as possible when providing steps to reproduce, failure to provide steps will result in this issue being closed.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: panel-version
|
|
||||||
attributes:
|
|
||||||
label: Panel Version
|
|
||||||
description: Version number of your Panel (latest is not a version)
|
|
||||||
placeholder: v2 EA
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: daemon-version
|
|
||||||
attributes:
|
|
||||||
label: Daemon Version
|
|
||||||
description: Version number of your Daemon (latest is not a version)
|
|
||||||
placeholder: v2 EA
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: image-details
|
|
||||||
attributes:
|
|
||||||
label: Games and/or Images Affected
|
|
||||||
description: Please include the specific game(s) or Image(s) you are running into this bug with.
|
|
||||||
placeholder: Minecraft (Paper), Minecraft (Forge)
|
|
||||||
|
|
||||||
- type: input
|
|
||||||
id: docker-image
|
|
||||||
attributes:
|
|
||||||
label: Docker Image
|
|
||||||
description: The specific Docker image you are using for the game(s) above.
|
|
||||||
placeholder: ghcr.io/xxx/yolks:java_17
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
id: panel-logs
|
|
||||||
attributes:
|
|
||||||
label: Error Logs
|
|
||||||
description: |
|
|
||||||
Run the following command to collect logs on your system.
|
|
||||||
|
|
||||||
Panel: `docker logs moonlight`
|
|
||||||
Wings: `sudo wings diagnostics`
|
|
||||||
placeholder: logs here
|
|
||||||
render: bash
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Is there an existing issue for this?
|
|
||||||
description: Please [search here](https://github.com/Moonlight-Panel/Moonlight/issues) to see if an issue already exists for your problem.
|
|
||||||
options:
|
|
||||||
- label: I have searched the existing issues before opening this issue.
|
|
||||||
required: true
|
|
||||||
- label: I have provided all relevant details, including the specific game and Docker images I am using if this issue is related to running a server.
|
|
||||||
required: true
|
|
||||||
- label: I have checked in the Discord server and believe this is a bug with the software, and not a configuration issue with my specific system.
|
|
||||||
required: true
|
|
8
.github/ISSUE_TEMPLATE/config.yml
vendored
8
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -1,8 +0,0 @@
|
||||||
blank_issues_enabled: true
|
|
||||||
contact_links:
|
|
||||||
- name: Installation Help
|
|
||||||
url: https://discord.gg/TJaspT7A8p
|
|
||||||
about: Please visit our Discord for help with your installation.
|
|
||||||
- name: General Question
|
|
||||||
url: https://discord.gg/TJaspT7A8p
|
|
||||||
about: Please visit our Discord for general questions about Moonlight Panel.
|
|
32
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
32
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
|
@ -1,32 +0,0 @@
|
||||||
name: Feature Request
|
|
||||||
description: Suggest a new feature or improvement for the software.
|
|
||||||
labels: [feature request]
|
|
||||||
body:
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Is there an existing feature request for this?
|
|
||||||
description: Please [search here](https://github.com/Moonlight-Panel/Moonlight/issues?q=is%3Aissue) to see if someone else has already suggested this.
|
|
||||||
options:
|
|
||||||
- label: I have searched the existing issues before opening this feature request.
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Describe the feature you would like to see.
|
|
||||||
description: "A clear & concise description of the feature you'd like to have added, and what issues it would solve."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Describe the solution you'd like.
|
|
||||||
description: "You must explain how you'd like to see this feature implemented. Technical implementation details are not necessary, rather an idea of how you'd like to see this feature used."
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Additional context to this request.
|
|
||||||
description: "Add any other context or screenshots about the feature request."
|
|
||||||
validations:
|
|
||||||
required: false
|
|
430
.gitignore
vendored
430
.gitignore
vendored
|
@ -1,404 +1,44 @@
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
Common IntelliJ Platform excludes
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
##
|
# User specific
|
||||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
**/.idea/**/workspace.xml
|
||||||
|
**/.idea/**/tasks.xml
|
||||||
|
**/.idea/shelf/*
|
||||||
|
**/.idea/dictionaries
|
||||||
|
**/.idea/httpRequests/
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
**/.idea/**/dataSources/
|
||||||
|
**/.idea/**/dataSources.ids
|
||||||
|
**/.idea/**/dataSources.xml
|
||||||
|
**/.idea/**/dataSources.local.xml
|
||||||
|
**/.idea/**/sqlDataSources.xml
|
||||||
|
**/.idea/**/dynamic.xml
|
||||||
|
|
||||||
|
# Rider
|
||||||
|
# Rider auto-generates .iml files, and contentModel.xml
|
||||||
|
**/.idea/**/*.iml
|
||||||
|
**/.idea/**/contentModel.xml
|
||||||
|
**/.idea/**/modules.xml
|
||||||
|
|
||||||
|
|
||||||
|
Moonlight/[Bb]in/
|
||||||
|
Moonlight/[Oo]bj/
|
||||||
|
Moonlight/_UpgradeReport_Files/
|
||||||
|
Moonlight/[Pp]ackages/
|
||||||
|
|
||||||
# User-specific files
|
|
||||||
*.rsuser
|
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
*.userosscache
|
.vs/
|
||||||
*.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/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
[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
|
|
||||||
*.tlog
|
|
||||||
*.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/
|
_UpgradeReport_Files/
|
||||||
Backup*/
|
[Pp]ackages/
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
Thumbs.db
|
||||||
*.mdf
|
Desktop.ini
|
||||||
*.ldf
|
.DS_Store
|
||||||
*.ndf
|
.idea/.idea.Moonlight/.idea/discord.xml
|
||||||
|
|
||||||
# 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 6 auto-generated project file (contains which files were open etc.)
|
|
||||||
*.vbp
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
|
||||||
*.dsw
|
|
||||||
*.dsp
|
|
||||||
|
|
||||||
# Visual Studio 6 technical files
|
|
||||||
*.ncb
|
|
||||||
*.aps
|
|
||||||
|
|
||||||
# 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/
|
|
||||||
|
|
||||||
# Visual Studio History (VSHistory) files
|
|
||||||
.vshistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
|
||||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
|
||||||
MigrationBackup/
|
|
||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
|
||||||
.ionide/
|
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
|
||||||
FodyWeavers.xsd
|
|
||||||
|
|
||||||
# VS Code files for those working on multiple tools
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
*.code-workspace
|
|
||||||
|
|
||||||
# Local History for Visual Studio Code
|
|
||||||
.history/
|
|
||||||
|
|
||||||
# Windows Installer files from build outputs
|
|
||||||
*.cab
|
|
||||||
*.msi
|
|
||||||
*.msix
|
|
||||||
*.msm
|
|
||||||
*.msp
|
|
||||||
|
|
||||||
# JetBrains Rider
|
|
||||||
*.sln.iml
|
|
||||||
|
|
||||||
storage/
|
|
||||||
.idea/.idea.Moonlight/.idea/dataSources.xml
|
|
||||||
Moonlight/wwwroot/css/theme.css
|
Moonlight/wwwroot/css/theme.css
|
||||||
Moonlight/wwwroot/css/theme.css.map
|
Moonlight/wwwroot/css/theme.css.map
|
||||||
.idea/.idea.Moonlight/.idea/discord.xml
|
storage/
|
||||||
|
|
13
.idea/.idea.Moonlight/.idea/.gitignore
vendored
13
.idea/.idea.Moonlight/.idea/.gitignore
vendored
|
@ -1,13 +0,0 @@
|
||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Rider ignored files
|
|
||||||
/modules.xml
|
|
||||||
/contentModel.xml
|
|
||||||
/projectSettingsUpdater.xml
|
|
||||||
/.idea.Moonlight.iml
|
|
||||||
# Editor-based HTTP Client requests
|
|
||||||
/httpRequests/
|
|
||||||
# Datasource local storage ignored files
|
|
||||||
/dataSources/
|
|
||||||
/dataSources.local.xml
|
|
|
@ -1,12 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DiscordProjectSettings">
|
|
||||||
<option name="show" value="PROJECT_FILES" />
|
|
||||||
<option name="description" value="" />
|
|
||||||
<option name="theme" value="material" />
|
|
||||||
<option name="button1Title" value="" />
|
|
||||||
<option name="button1Url" value="" />
|
|
||||||
<option name="button2Title" value="" />
|
|
||||||
<option name="button2Url" value="" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
21
.idea/.idea.Moonlight/.idea/efCoreCommonOptions.xml
Normal file
21
.idea/.idea.Moonlight/.idea/efCoreCommonOptions.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="EfCoreCommonOptions">
|
||||||
|
<option name="migrationsToStartupProjects">
|
||||||
|
<map>
|
||||||
|
<entry key="691e5ec2-4b4f-4bd1-9cbc-7d3c6efc12da" value="691e5ec2-4b4f-4bd1-9cbc-7d3c6efc12da" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="solutionLevelOptions">
|
||||||
|
<map>
|
||||||
|
<entry key="migrationsProject" value="691e5ec2-4b4f-4bd1-9cbc-7d3c6efc12da" />
|
||||||
|
<entry key="startupProject" value="691e5ec2-4b4f-4bd1-9cbc-7d3c6efc12da" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
<option name="startupToMigrationsProjects">
|
||||||
|
<map>
|
||||||
|
<entry key="691e5ec2-4b4f-4bd1-9cbc-7d3c6efc12da" value="691e5ec2-4b4f-4bd1-9cbc-7d3c6efc12da" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
14
.idea/.idea.Moonlight/.idea/efCoreDialogsState.xml
Normal file
14
.idea/.idea.Moonlight/.idea/efCoreDialogsState.xml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="EfCoreDialogsState">
|
||||||
|
<option name="keyValueStorage">
|
||||||
|
<map>
|
||||||
|
<entry key="Common:691e5ec2-4b4f-4bd1-9cbc-7d3c6efc12da:dbContext" value="Moonlight.App.Database.DataContext" />
|
||||||
|
<entry key="Common:buildConfiguration" value="Debug" />
|
||||||
|
<entry key="Common:noBuild" value="false" />
|
||||||
|
<entry key="Common:outputFolder" value="App/Database/Migrations" />
|
||||||
|
<entry key="Common:useDefaultConnection" value="true" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -1,13 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="MaterialThemeProjectNewConfig">
|
|
||||||
<option name="metadata">
|
|
||||||
<MTProjectMetadataState>
|
|
||||||
<option name="migrated" value="true" />
|
|
||||||
<option name="pristineConfig" value="false" />
|
|
||||||
<option name="userId" value="52a374ed:18c1029d858:-8000" />
|
|
||||||
<option name="version" value="8.13.2" />
|
|
||||||
</MTProjectMetadataState>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
6
.idea/.idea.Moonlight/.idea/projectSettingsUpdater.xml
Normal file
6
.idea/.idea.Moonlight/.idea/projectSettingsUpdater.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="RiderProjectSettingsUpdater">
|
||||||
|
<option name="vcsConfiguration" value="2" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
121
LICENSE
121
LICENSE
|
@ -1,121 +0,0 @@
|
||||||
Creative Commons Legal Code
|
|
||||||
|
|
||||||
CC0 1.0 Universal
|
|
||||||
|
|
||||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
|
||||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
|
||||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
|
||||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
|
||||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
|
||||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
|
||||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
|
||||||
HEREUNDER.
|
|
||||||
|
|
||||||
Statement of Purpose
|
|
||||||
|
|
||||||
The laws of most jurisdictions throughout the world automatically confer
|
|
||||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
|
||||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
|
||||||
authorship and/or a database (each, a "Work").
|
|
||||||
|
|
||||||
Certain owners wish to permanently relinquish those rights to a Work for
|
|
||||||
the purpose of contributing to a commons of creative, cultural and
|
|
||||||
scientific works ("Commons") that the public can reliably and without fear
|
|
||||||
of later claims of infringement build upon, modify, incorporate in other
|
|
||||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
|
||||||
and for any purposes, including without limitation commercial purposes.
|
|
||||||
These owners may contribute to the Commons to promote the ideal of a free
|
|
||||||
culture and the further production of creative, cultural and scientific
|
|
||||||
works, or to gain reputation or greater distribution for their Work in
|
|
||||||
part through the use and efforts of others.
|
|
||||||
|
|
||||||
For these and/or other purposes and motivations, and without any
|
|
||||||
expectation of additional consideration or compensation, the person
|
|
||||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
|
||||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
|
||||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
|
||||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
|
||||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
|
||||||
|
|
||||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
|
||||||
protected by copyright and related or neighboring rights ("Copyright and
|
|
||||||
Related Rights"). Copyright and Related Rights include, but are not
|
|
||||||
limited to, the following:
|
|
||||||
|
|
||||||
i. the right to reproduce, adapt, distribute, perform, display,
|
|
||||||
communicate, and translate a Work;
|
|
||||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
|
||||||
iii. publicity and privacy rights pertaining to a person's image or
|
|
||||||
likeness depicted in a Work;
|
|
||||||
iv. rights protecting against unfair competition in regards to a Work,
|
|
||||||
subject to the limitations in paragraph 4(a), below;
|
|
||||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
|
||||||
in a Work;
|
|
||||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
|
||||||
European Parliament and of the Council of 11 March 1996 on the legal
|
|
||||||
protection of databases, and under any national implementation
|
|
||||||
thereof, including any amended or successor version of such
|
|
||||||
directive); and
|
|
||||||
vii. other similar, equivalent or corresponding rights throughout the
|
|
||||||
world based on applicable law or treaty, and any national
|
|
||||||
implementations thereof.
|
|
||||||
|
|
||||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
|
||||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
|
||||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
|
||||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
|
||||||
of action, whether now known or unknown (including existing as well as
|
|
||||||
future claims and causes of action), in the Work (i) in all territories
|
|
||||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
|
||||||
treaty (including future time extensions), (iii) in any current or future
|
|
||||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
|
||||||
including without limitation commercial, advertising or promotional
|
|
||||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
|
||||||
member of the public at large and to the detriment of Affirmer's heirs and
|
|
||||||
successors, fully intending that such Waiver shall not be subject to
|
|
||||||
revocation, rescission, cancellation, termination, or any other legal or
|
|
||||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
|
||||||
as contemplated by Affirmer's express Statement of Purpose.
|
|
||||||
|
|
||||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
|
||||||
be judged legally invalid or ineffective under applicable law, then the
|
|
||||||
Waiver shall be preserved to the maximum extent permitted taking into
|
|
||||||
account Affirmer's express Statement of Purpose. In addition, to the
|
|
||||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
|
||||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
|
||||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
|
||||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
|
||||||
maximum duration provided by applicable law or treaty (including future
|
|
||||||
time extensions), (iii) in any current or future medium and for any number
|
|
||||||
of copies, and (iv) for any purpose whatsoever, including without
|
|
||||||
limitation commercial, advertising or promotional purposes (the
|
|
||||||
"License"). The License shall be deemed effective as of the date CC0 was
|
|
||||||
applied by Affirmer to the Work. Should any part of the License for any
|
|
||||||
reason be judged legally invalid or ineffective under applicable law, such
|
|
||||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
|
||||||
of the License, and in such case Affirmer hereby affirms that he or she
|
|
||||||
will not (i) exercise any of his or her remaining Copyright and Related
|
|
||||||
Rights in the Work or (ii) assert any associated claims and causes of
|
|
||||||
action with respect to the Work, in either case contrary to Affirmer's
|
|
||||||
express Statement of Purpose.
|
|
||||||
|
|
||||||
4. Limitations and Disclaimers.
|
|
||||||
|
|
||||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
|
||||||
surrendered, licensed or otherwise affected by this document.
|
|
||||||
b. Affirmer offers the Work as-is and makes no representations or
|
|
||||||
warranties of any kind concerning the Work, express, implied,
|
|
||||||
statutory or otherwise, including without limitation warranties of
|
|
||||||
title, merchantability, fitness for a particular purpose, non
|
|
||||||
infringement, or the absence of latent or other defects, accuracy, or
|
|
||||||
the present or absence of errors, whether or not discoverable, all to
|
|
||||||
the greatest extent permissible under applicable law.
|
|
||||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
|
||||||
that may apply to the Work or any use thereof, including without
|
|
||||||
limitation any person's Copyright and Related Rights in the Work.
|
|
||||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
|
||||||
consents, permissions or other rights required for any use of the
|
|
||||||
Work.
|
|
||||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
|
||||||
party to this document and has no duty or obligation with respect to
|
|
||||||
this CC0 or use of the Work.
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight", "Moonlight\Moonlight.csproj", "{B9AD26D2-AAA7-4C57-884D-5AACAA54D5B6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight", "Moonlight\Moonlight.csproj", "{691E5EC2-4B4F-4BD1-9CBC-7D3C6EFC12DA}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -8,11 +8,9 @@ Global
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{B9AD26D2-AAA7-4C57-884D-5AACAA54D5B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{691E5EC2-4B4F-4BD1-9CBC-7D3C6EFC12DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{B9AD26D2-AAA7-4C57-884D-5AACAA54D5B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{691E5EC2-4B4F-4BD1-9CBC-7D3C6EFC12DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{B9AD26D2-AAA7-4C57-884D-5AACAA54D5B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{691E5EC2-4B4F-4BD1-9CBC-7D3C6EFC12DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{B9AD26D2-AAA7-4C57-884D-5AACAA54D5B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
{691E5EC2-4B4F-4BD1-9CBC-7D3C6EFC12DA}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(NestedProjects) = preSolution
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
6
Moonlight/.idea/.gitignore
vendored
Normal file
6
Moonlight/.idea/.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
1
Moonlight/.idea/.name
Normal file
1
Moonlight/.idea/.name
Normal file
|
@ -0,0 +1 @@
|
||||||
|
data.sqlite
|
6
Moonlight/.idea/vcs.xml
Normal file
6
Moonlight/.idea/vcs.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -1,26 +0,0 @@
|
||||||
@using Moonlight.Core.UI.Layouts
|
|
||||||
@using Moonlight.Core.Services
|
|
||||||
|
|
||||||
@inject FeatureService FeatureService
|
|
||||||
|
|
||||||
@{
|
|
||||||
var assemblies = FeatureService.UiContext.RouteAssemblies;
|
|
||||||
var firstAssembly = assemblies.First();
|
|
||||||
var additionalAssemblies = assemblies.Skip(1).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
<Router AppAssembly="@firstAssembly" AdditionalAssemblies="@additionalAssemblies">
|
|
||||||
<Found Context="routeData">
|
|
||||||
<CascadingValue TValue="Type" Name="TargetPageType" Value="@routeData.PageType">
|
|
||||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
|
||||||
</CascadingValue>
|
|
||||||
</Found>
|
|
||||||
<NotFound>
|
|
||||||
<PageTitle>Not found</PageTitle>
|
|
||||||
<LayoutView Layout="@typeof(MainLayout)">
|
|
||||||
<IconAlert Title="Unknown page" Icon="bx-search">
|
|
||||||
The address you are trying to access is not associated with any page. To resume please go back or to the <a href="/">homepage</a>
|
|
||||||
</IconAlert>
|
|
||||||
</LayoutView>
|
|
||||||
</NotFound>
|
|
||||||
</Router>
|
|
22
Moonlight/App/Actions/Dummy/DummyActions.cs
Normal file
22
Moonlight/App/Actions/Dummy/DummyActions.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using Moonlight.App.Database.Entities.Store;
|
||||||
|
using Moonlight.App.Models.Abstractions;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Actions.Dummy;
|
||||||
|
|
||||||
|
public class DummyActions : ServiceActions
|
||||||
|
{
|
||||||
|
public override Task Create(IServiceProvider provider, Service service)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task Update(IServiceProvider provider, Service service)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task Delete(IServiceProvider provider, Service service)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
10
Moonlight/App/Api/AbstractRequest.cs
Normal file
10
Moonlight/App/Api/AbstractRequest.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Moonlight.App.Api;
|
||||||
|
|
||||||
|
public abstract class AbstractRequest
|
||||||
|
{
|
||||||
|
public IServiceProvider ServiceProvider { get; set; }
|
||||||
|
public ApiUserContext? Context { get; set; }
|
||||||
|
public abstract void ReadData(RequestDataContext dataContext);
|
||||||
|
public abstract Task ProcessRequest();
|
||||||
|
public abstract ResponseDataBuilder CreateResponse(ResponseDataBuilder builder);
|
||||||
|
}
|
63
Moonlight/App/Api/ApiManagementService.cs
Normal file
63
Moonlight/App/Api/ApiManagementService.cs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Api;
|
||||||
|
|
||||||
|
public class ApiManagementService
|
||||||
|
{
|
||||||
|
public Dictionary<int, Type> Requests;
|
||||||
|
public List<ApiUserContext> Contexts;
|
||||||
|
private readonly IServiceProvider ServiceProvider;
|
||||||
|
|
||||||
|
public ApiManagementService(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
Requests = new Dictionary<int, Type>();
|
||||||
|
Contexts = new List<ApiUserContext>();
|
||||||
|
ServiceProvider = serviceProvider;
|
||||||
|
|
||||||
|
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||||
|
|
||||||
|
foreach (var assembly in assemblies)
|
||||||
|
{
|
||||||
|
var types = assembly.ExportedTypes;
|
||||||
|
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
var attribute = type.GetCustomAttribute<ApiRequestAttribute>();
|
||||||
|
|
||||||
|
if(attribute == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var id = attribute.Id;
|
||||||
|
Requests[id] = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractRequest GetRequest(int id, ApiUserContext context)
|
||||||
|
{
|
||||||
|
var type = Requests[id];
|
||||||
|
var obj = Activator.CreateInstance(type) as AbstractRequest;
|
||||||
|
obj!.Context = context;
|
||||||
|
obj!.ServiceProvider = ServiceProvider.CreateScope().ServiceProvider;
|
||||||
|
|
||||||
|
return obj!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleRequest(ApiUserContext context, byte[] data)
|
||||||
|
{
|
||||||
|
var rqd = new RequestDataContext(data);
|
||||||
|
var id = rqd.ReadInt();
|
||||||
|
var request = GetRequest(id, context);
|
||||||
|
|
||||||
|
request.ReadData(rqd);
|
||||||
|
await request.ProcessRequest();
|
||||||
|
|
||||||
|
var rbd = new ResponseDataBuilder();
|
||||||
|
rbd = request.CreateResponse(rbd);
|
||||||
|
|
||||||
|
CancellationToken t = new CancellationToken();
|
||||||
|
var bytes = rbd.ToBytes();
|
||||||
|
await context.WebSocket.SendAsync(bytes, WebSocketMessageType.Binary, true, t);
|
||||||
|
}
|
||||||
|
}
|
11
Moonlight/App/Api/ApiRequestAttribute.cs
Normal file
11
Moonlight/App/Api/ApiRequestAttribute.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Moonlight.App.Api;
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
|
||||||
|
public sealed class ApiRequestAttribute : Attribute
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public ApiRequestAttribute(int id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
}
|
15
Moonlight/App/Api/ApiUserContext.cs
Normal file
15
Moonlight/App/Api/ApiUserContext.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Api;
|
||||||
|
|
||||||
|
public class ApiUserContext
|
||||||
|
{
|
||||||
|
public ApiUserContext(WebSocket webSocket)
|
||||||
|
{
|
||||||
|
WebSocket = webSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User? User { get; set; }
|
||||||
|
public WebSocket WebSocket { get; }
|
||||||
|
}
|
51
Moonlight/App/Api/RequestDataContext.cs
Normal file
51
Moonlight/App/Api/RequestDataContext.cs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
using System.Buffers.Binary;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Api;
|
||||||
|
|
||||||
|
public class RequestDataContext
|
||||||
|
{
|
||||||
|
private List<byte> Data;
|
||||||
|
|
||||||
|
public RequestDataContext(byte[] data)
|
||||||
|
{
|
||||||
|
Data = data.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReadInt()
|
||||||
|
{
|
||||||
|
var bytes = Data.Take(4).ToList();
|
||||||
|
Data.RemoveRange(0, 4);
|
||||||
|
|
||||||
|
if (BitConverter.IsLittleEndian) // because of java (the app needing the api is written in java/kotlin) we need to use big endian
|
||||||
|
{
|
||||||
|
bytes.Reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return BitConverter.ToInt32(bytes.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte ReadByte()
|
||||||
|
{
|
||||||
|
var b = Data[0];
|
||||||
|
Data.RemoveAt(0);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ReadBoolean()
|
||||||
|
{
|
||||||
|
var b = ReadByte();
|
||||||
|
|
||||||
|
return b == 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String ReadString()
|
||||||
|
{
|
||||||
|
var len = ReadInt();
|
||||||
|
|
||||||
|
var bytes = Data.Take(len).ToList();
|
||||||
|
Data.RemoveRange(0, len);
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetString(bytes.ToArray());
|
||||||
|
}
|
||||||
|
}
|
141
Moonlight/App/Api/Requests/Auth/CredentialBasedLoginRequest.cs
Normal file
141
Moonlight/App/Api/Requests/Auth/CredentialBasedLoginRequest.cs
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Exceptions;
|
||||||
|
using Moonlight.App.Helpers;
|
||||||
|
using Moonlight.App.Models.Abstractions;
|
||||||
|
using Moonlight.App.Models.Enums;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Services.Utils;
|
||||||
|
using OtpNet;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Api.Requests.Auth;
|
||||||
|
|
||||||
|
[ApiRequest(3)]
|
||||||
|
public class CredentialBasedLoginRequest : AbstractRequest
|
||||||
|
{
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
public string Code { get; set; }
|
||||||
|
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public bool RequireTotp { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// 0: all fine
|
||||||
|
/// 1: wrong credentials
|
||||||
|
/// 2: Totp enabled
|
||||||
|
/// 3: TotpKey missing
|
||||||
|
/// 4: wrong totp code
|
||||||
|
/// </summary>
|
||||||
|
public int ErrorId { get; set; }
|
||||||
|
public string Token { get; set; } = "";
|
||||||
|
public override ResponseDataBuilder CreateResponse(ResponseDataBuilder builder)
|
||||||
|
{
|
||||||
|
builder.WriteBoolean(Success);
|
||||||
|
builder.WriteBoolean(RequireTotp);
|
||||||
|
builder.WriteInt(ErrorId);
|
||||||
|
builder.WriteString(Token);
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task ProcessRequest()
|
||||||
|
{
|
||||||
|
var userRepository = ServiceProvider.GetService<Repository<User>>();
|
||||||
|
|
||||||
|
var user = userRepository
|
||||||
|
.Get()
|
||||||
|
.FirstOrDefault(x => x.Email == Email);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
Success = false;
|
||||||
|
RequireTotp = false;
|
||||||
|
ErrorId = 1;
|
||||||
|
Token = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HashHelper.Verify(Password, user.Password))
|
||||||
|
{
|
||||||
|
Success = false;
|
||||||
|
RequireTotp = false;
|
||||||
|
ErrorId = 1;
|
||||||
|
Token = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var flags = new FlagStorage(user.Flags); // Construct FlagStorage to check for 2fa
|
||||||
|
|
||||||
|
if (!flags[UserFlag.TotpEnabled])
|
||||||
|
{
|
||||||
|
// No 2fa found on this user so were done here
|
||||||
|
Success = true;
|
||||||
|
RequireTotp = false;
|
||||||
|
ErrorId = 0;
|
||||||
|
Token = await GenerateToken(user);
|
||||||
|
Context!.User = user;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we reach this point, 2fa is enabled so we need to continue validating
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(Code))
|
||||||
|
{
|
||||||
|
// This will show an additional 2fa login field
|
||||||
|
Success = false;
|
||||||
|
RequireTotp = true;
|
||||||
|
ErrorId = 2;
|
||||||
|
Token = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.TotpKey == null)
|
||||||
|
{
|
||||||
|
// Hopefully we will never fulfill this check ;)
|
||||||
|
Success = false;
|
||||||
|
RequireTotp = false;
|
||||||
|
ErrorId = 3;
|
||||||
|
Token = "";
|
||||||
|
return;
|
||||||
|
throw new DisplayException("2FA key is missing. Please contact the support to fix your account");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate server side code
|
||||||
|
var totp = new Totp(Base32Encoding.ToBytes(user.TotpKey));
|
||||||
|
var codeServerSide = totp.ComputeTotp();
|
||||||
|
|
||||||
|
if (codeServerSide == Code)
|
||||||
|
{
|
||||||
|
Success = true;
|
||||||
|
RequireTotp = false;
|
||||||
|
ErrorId = 0;
|
||||||
|
Token = await GenerateToken(user);
|
||||||
|
Context!.User = user;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Success = false;
|
||||||
|
RequireTotp = false;
|
||||||
|
ErrorId = 4;
|
||||||
|
Token = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GenerateToken(User user)
|
||||||
|
{
|
||||||
|
var jwtService = ServiceProvider.GetService<JwtService>();
|
||||||
|
|
||||||
|
var token = await jwtService.Create(data =>
|
||||||
|
{
|
||||||
|
data.Add("userId", user.Id.ToString());
|
||||||
|
data.Add("issuedAt", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString());
|
||||||
|
}, TimeSpan.FromDays(365));
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadData(RequestDataContext dataContext)
|
||||||
|
{
|
||||||
|
Email = dataContext.ReadString();
|
||||||
|
Password = dataContext.ReadString();
|
||||||
|
Code = dataContext.ReadString();
|
||||||
|
}
|
||||||
|
}
|
50
Moonlight/App/Api/Requests/Auth/IsEmailVerifiedRequest.cs
Normal file
50
Moonlight/App/Api/Requests/Auth/IsEmailVerifiedRequest.cs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Models.Enums;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
using Moonlight.App.Services.Users;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Api.Requests.Auth;
|
||||||
|
|
||||||
|
[ApiRequest(5)]
|
||||||
|
public class IsEmailVerifiedRequest : AbstractRequest
|
||||||
|
{
|
||||||
|
public bool SendMail { get; set; }
|
||||||
|
public bool MailVerified { get; set; }
|
||||||
|
|
||||||
|
public override async Task ProcessRequest()
|
||||||
|
{
|
||||||
|
if(Context.User == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var userRepository = ServiceProvider.GetRequiredService<Repository<User>>();
|
||||||
|
Context.User = userRepository.Get().Where(x => x.Id == Context.User.Id).ToArray()[0];
|
||||||
|
|
||||||
|
if (SendMail && Context.User != null)
|
||||||
|
{
|
||||||
|
var userAuthService = ServiceProvider.GetRequiredService<UserAuthService>();
|
||||||
|
await userAuthService.SendVerification(Context!.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
var configService = ServiceProvider.GetRequiredService<ConfigService>();
|
||||||
|
var reqEmailVerify = configService.Get().Security.EnableEmailVerify;
|
||||||
|
if (Context?.User?.Flags!.Contains(UserFlag.MailVerified.ToString()) ?? false)
|
||||||
|
MailVerified = true;
|
||||||
|
else
|
||||||
|
MailVerified = !reqEmailVerify;
|
||||||
|
|
||||||
|
await Task.Delay(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ResponseDataBuilder CreateResponse(ResponseDataBuilder builder)
|
||||||
|
{
|
||||||
|
builder.WriteBoolean(MailVerified);
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadData(RequestDataContext dataContext)
|
||||||
|
{
|
||||||
|
SendMail = dataContext.ReadBoolean();
|
||||||
|
}
|
||||||
|
}
|
181
Moonlight/App/Api/Requests/Auth/RegisterRequest.cs
Normal file
181
Moonlight/App/Api/Requests/Auth/RegisterRequest.cs
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Reflection;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Event;
|
||||||
|
using Moonlight.App.Exceptions;
|
||||||
|
using Moonlight.App.Extensions;
|
||||||
|
using Moonlight.App.Helpers;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
using Moonlight.App.Services.Utils;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Api.Requests.Auth;
|
||||||
|
|
||||||
|
[ApiRequest(4)]
|
||||||
|
public class RegisterRequest: AbstractRequest
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "9")]
|
||||||
|
[EmailAddress(ErrorMessage = "10")]
|
||||||
|
public string Email { get; set; } = "";
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "8")]
|
||||||
|
[MinLength(7, ErrorMessage = "7")]
|
||||||
|
[MaxLength(20, ErrorMessage = "7")]
|
||||||
|
[RegularExpression("^[a-z][a-z0-9]*$", ErrorMessage = "6")]
|
||||||
|
public string Username { get; set; } = "";
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "4")]
|
||||||
|
[MinLength(8, ErrorMessage = "5")]
|
||||||
|
[MaxLength(256, ErrorMessage = "5")]
|
||||||
|
public string Password { get; set; } = "";
|
||||||
|
public string PasswordConfirm { get; set; } = "";
|
||||||
|
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public bool RequireEmailVerify { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Error Codes:
|
||||||
|
/// - 0 all successful
|
||||||
|
/// - 1 email exists
|
||||||
|
/// - 2 username exists
|
||||||
|
/// - 3 passwords do not match
|
||||||
|
/// - 4 password needs to be provided
|
||||||
|
/// - 5 password needs to be between 8 and 256 characters
|
||||||
|
/// - 6 Usernames can only contain lowercase characters and numbers
|
||||||
|
/// - 7 username has to be between 7 and 20 chars
|
||||||
|
/// - 8 username required
|
||||||
|
/// - 9 email required
|
||||||
|
/// - 10 email invalid
|
||||||
|
/// </summary>
|
||||||
|
public int ErrorCode { get; set; }
|
||||||
|
public string Token { get; set; } = "";
|
||||||
|
public override ResponseDataBuilder CreateResponse(ResponseDataBuilder builder)
|
||||||
|
{
|
||||||
|
builder.WriteBoolean(Success);
|
||||||
|
builder.WriteBoolean(RequireEmailVerify);
|
||||||
|
builder.WriteInt(ErrorCode);
|
||||||
|
builder.WriteString(Token);
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadData(RequestDataContext dataContext)
|
||||||
|
{
|
||||||
|
Email = dataContext.ReadString();
|
||||||
|
Username = dataContext.ReadString();
|
||||||
|
Password = dataContext.ReadString();
|
||||||
|
PasswordConfirm = dataContext.ReadString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task ProcessRequest()
|
||||||
|
{
|
||||||
|
var userRepository = ServiceProvider.GetRequiredService<Repository<User>>();
|
||||||
|
var configService = ServiceProvider.GetRequiredService<ConfigService>();
|
||||||
|
|
||||||
|
var reqEmailVerify = configService.Get().Security.EnableEmailVerify;
|
||||||
|
// Event though we have form validation i want to
|
||||||
|
// ensure that at least these basic formatting things are done
|
||||||
|
Email = Email.ToLower().Trim();
|
||||||
|
Username = Username.ToLower().Trim();
|
||||||
|
|
||||||
|
if (PasswordConfirm != Password)
|
||||||
|
{
|
||||||
|
Token = "";
|
||||||
|
Success = false;
|
||||||
|
RequireEmailVerify = false;
|
||||||
|
ErrorCode = 3;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsPropertyValid(this.GetProperty(x => x.Email)!, out var errorCd))
|
||||||
|
{
|
||||||
|
Token = "";
|
||||||
|
Success = false;
|
||||||
|
RequireEmailVerify = false;
|
||||||
|
ErrorCode = errorCd;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsPropertyValid(this.GetProperty(x => x.Password)!, out var errorCd1))
|
||||||
|
{
|
||||||
|
Token = "";
|
||||||
|
Success = false;
|
||||||
|
RequireEmailVerify = false;
|
||||||
|
ErrorCode = errorCd1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsPropertyValid(this.GetProperty(x => x.Username)!, out var errorCd2))
|
||||||
|
{
|
||||||
|
Token = "";
|
||||||
|
Success = false;
|
||||||
|
RequireEmailVerify = false;
|
||||||
|
ErrorCode = errorCd2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent duplication or username and/or email
|
||||||
|
if (userRepository.Get().Any(x => x.Email == Email))
|
||||||
|
{
|
||||||
|
Token = "";
|
||||||
|
Success = false;
|
||||||
|
RequireEmailVerify = false;
|
||||||
|
ErrorCode = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userRepository.Get().Any(x => x.Username == Username))
|
||||||
|
{
|
||||||
|
Token = "";
|
||||||
|
Success = false;
|
||||||
|
RequireEmailVerify = false;
|
||||||
|
ErrorCode = 2;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = new User()
|
||||||
|
{
|
||||||
|
Username = Username,
|
||||||
|
Email = Email,
|
||||||
|
Password = HashHelper.HashToString(Password)
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = userRepository.Add(user);
|
||||||
|
|
||||||
|
await Events.OnUserRegistered.InvokeAsync(result);
|
||||||
|
|
||||||
|
Token = await GenerateToken(user);
|
||||||
|
Success = true;
|
||||||
|
RequireEmailVerify = reqEmailVerify;
|
||||||
|
ErrorCode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GenerateToken(User user)
|
||||||
|
{
|
||||||
|
var jwtService = ServiceProvider.GetService<JwtService>();
|
||||||
|
|
||||||
|
var token = await jwtService.Create(data =>
|
||||||
|
{
|
||||||
|
data.Add("userId", user.Id.ToString());
|
||||||
|
data.Add("issuedAt", DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString());
|
||||||
|
}, TimeSpan.FromDays(365));
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsPropertyValid(PropertyInfo property, out int errorCode)
|
||||||
|
{
|
||||||
|
var attribs = property.GetCustomAttributes<ValidationAttribute>();
|
||||||
|
|
||||||
|
foreach (var a in attribs)
|
||||||
|
{
|
||||||
|
if (!a.IsValid(property.GetValue(this)))
|
||||||
|
{
|
||||||
|
errorCode = int.Parse(a.ErrorMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errorCode = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
65
Moonlight/App/Api/Requests/Auth/TokenBasedLoginRequest.cs
Normal file
65
Moonlight/App/Api/Requests/Auth/TokenBasedLoginRequest.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Services.Utils;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Api.Requests.Auth;
|
||||||
|
|
||||||
|
[ApiRequest(2)]
|
||||||
|
public class TokenBasedLoginRequest: AbstractRequest
|
||||||
|
{
|
||||||
|
private String Token { get; set; }
|
||||||
|
private bool Success { get; set; } = false;
|
||||||
|
public override ResponseDataBuilder CreateResponse(ResponseDataBuilder builder)
|
||||||
|
{
|
||||||
|
builder.WriteBoolean(Success);
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task ProcessRequest()
|
||||||
|
{
|
||||||
|
var jwtService = ServiceProvider.GetRequiredService<JwtService>();
|
||||||
|
var userRepository = ServiceProvider.GetRequiredService<Repository<User>>();
|
||||||
|
if (string.IsNullOrEmpty(Token))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!await jwtService.Validate(Token))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var data = await jwtService.Decode(Token);
|
||||||
|
|
||||||
|
if (!data.ContainsKey("userId"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var userId = int.Parse(data["userId"]);
|
||||||
|
|
||||||
|
var user = userRepository
|
||||||
|
.Get()
|
||||||
|
.FirstOrDefault(x => x.Id == userId);
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!data.ContainsKey("issuedAt"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var issuedAt = long.Parse(data["issuedAt"]);
|
||||||
|
var issuedAtDateTime = DateTimeOffset.FromUnixTimeSeconds(issuedAt).DateTime;
|
||||||
|
|
||||||
|
// If the valid time is newer then when the token was issued, the token is not longer valid
|
||||||
|
if (user.TokenValidTimestamp > issuedAtDateTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Context!.User = user;
|
||||||
|
|
||||||
|
if (Context.User == null) // If the current user is null, stop loading additional data
|
||||||
|
return;
|
||||||
|
|
||||||
|
Success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadData(RequestDataContext dataContext)
|
||||||
|
{
|
||||||
|
Token = dataContext.ReadString();
|
||||||
|
}
|
||||||
|
}
|
21
Moonlight/App/Api/Requests/PingRequest.cs
Normal file
21
Moonlight/App/Api/Requests/PingRequest.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
namespace Moonlight.App.Api.Requests;
|
||||||
|
|
||||||
|
[ApiRequest(1)]
|
||||||
|
public class PingRequest : AbstractRequest
|
||||||
|
{
|
||||||
|
public override void ReadData(RequestDataContext dataContext)
|
||||||
|
{
|
||||||
|
var chunk = dataContext.ReadInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ResponseDataBuilder CreateResponse(ResponseDataBuilder builder)
|
||||||
|
{
|
||||||
|
builder.WriteInt(10324);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task ProcessRequest()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
49
Moonlight/App/Api/ResponseDataBuilder.cs
Normal file
49
Moonlight/App/Api/ResponseDataBuilder.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Api;
|
||||||
|
|
||||||
|
public class ResponseDataBuilder
|
||||||
|
{
|
||||||
|
private List<byte> Data;
|
||||||
|
|
||||||
|
public ResponseDataBuilder()
|
||||||
|
{
|
||||||
|
Data = new List<byte>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteInt(int data)
|
||||||
|
{
|
||||||
|
var bytes = BitConverter.GetBytes(data);
|
||||||
|
|
||||||
|
if (BitConverter.IsLittleEndian) // because of java (the app needing th api is written in java/kotlin) we need to use big endian
|
||||||
|
{
|
||||||
|
bytes = bytes.Reverse().ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
Data.AddRange(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteByte(byte data)
|
||||||
|
{
|
||||||
|
Data.Add(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteBoolean(bool data)
|
||||||
|
{
|
||||||
|
WriteByte(data ? (byte)255 : (byte)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteString(String data)
|
||||||
|
{
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(data);
|
||||||
|
var len = bytes.Length;
|
||||||
|
|
||||||
|
WriteInt(len);
|
||||||
|
Data.AddRange(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] ToBytes()
|
||||||
|
{
|
||||||
|
return Data.ToArray();
|
||||||
|
}
|
||||||
|
}
|
73
Moonlight/App/Configuration/ConfigV1.cs
Normal file
73
Moonlight/App/Configuration/ConfigV1.cs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Moonlight.App.Helpers;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Configuration;
|
||||||
|
|
||||||
|
public class ConfigV1
|
||||||
|
{
|
||||||
|
[JsonProperty("AppUrl")]
|
||||||
|
[Description("The url with which moonlight is accessible from the internet. It must not end with a /")]
|
||||||
|
public string AppUrl { get; set; } = "http://your-moonlight-instance-without-slash.owo";
|
||||||
|
|
||||||
|
[JsonProperty("Security")] public SecurityData Security { get; set; } = new();
|
||||||
|
[JsonProperty("Database")] public DatabaseData Database { get; set; } = new();
|
||||||
|
[JsonProperty("MailServer")] public MailServerData MailServer { get; set; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("Store")] public StoreData Store { get; set; } = new();
|
||||||
|
|
||||||
|
public class StoreData
|
||||||
|
{
|
||||||
|
[JsonProperty("Currency")]
|
||||||
|
[Description("A string value representing the currency which will be shown to a user")]
|
||||||
|
public string Currency { get; set; } = "€";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SecurityData
|
||||||
|
{
|
||||||
|
[JsonProperty("Token")]
|
||||||
|
[Description("The security token helio will use to encrypt various things like tokens")]
|
||||||
|
public string Token { get; set; } = Guid.NewGuid().ToString().Replace("-", "");
|
||||||
|
|
||||||
|
[JsonProperty("EnableEmailVerify")]
|
||||||
|
[Description("This will users force to verify their email address if they havent already")]
|
||||||
|
public bool EnableEmailVerify { get; set; } = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DatabaseData
|
||||||
|
{
|
||||||
|
[JsonProperty("UseSqlite")]
|
||||||
|
public bool UseSqlite { get; set; } = false;
|
||||||
|
|
||||||
|
[JsonProperty("SqlitePath")]
|
||||||
|
public string SqlitePath { get; set; } = PathBuilder.File("storage", "data.sqlite");
|
||||||
|
|
||||||
|
[JsonProperty("Host")]
|
||||||
|
public string Host { get; set; } = "your.db.host";
|
||||||
|
|
||||||
|
[JsonProperty("Port")]
|
||||||
|
public int Port { get; set; } = 3306;
|
||||||
|
|
||||||
|
[JsonProperty("Username")]
|
||||||
|
public string Username { get; set; } = "moonlight_user";
|
||||||
|
|
||||||
|
[JsonProperty("Password")]
|
||||||
|
public string Password { get; set; } = "s3cr3t";
|
||||||
|
|
||||||
|
[JsonProperty("Database")]
|
||||||
|
public string Database { get; set; } = "moonlight_db";
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MailServerData
|
||||||
|
{
|
||||||
|
[JsonProperty("Host")] public string Host { get; set; } = "your.email.host";
|
||||||
|
|
||||||
|
[JsonProperty("Port")] public int Port { get; set; } = 465;
|
||||||
|
|
||||||
|
[JsonProperty("Email")] public string Email { get; set; } = "noreply@your.email.host";
|
||||||
|
|
||||||
|
[JsonProperty("Password")] public string Password { get; set; } = "s3cr3t";
|
||||||
|
|
||||||
|
[JsonProperty("UseSsl")] public bool UseSsl { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
65
Moonlight/App/Database/DataContext.cs
Normal file
65
Moonlight/App/Database/DataContext.cs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Database.Entities.Community;
|
||||||
|
using Moonlight.App.Database.Entities.Store;
|
||||||
|
using Moonlight.App.Database.Entities.Tickets;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database;
|
||||||
|
|
||||||
|
public class DataContext : DbContext
|
||||||
|
{
|
||||||
|
private readonly ConfigService ConfigService;
|
||||||
|
|
||||||
|
public DbSet<User> Users { get; set; }
|
||||||
|
//public DbSet<Ticket> Tickets { get; set; }
|
||||||
|
//public DbSet<TicketMessage> TicketMessages { get; set; }
|
||||||
|
|
||||||
|
// Store
|
||||||
|
public DbSet<Category> Categories { get; set; }
|
||||||
|
public DbSet<Product> Products { get; set; }
|
||||||
|
public DbSet<Service> Services { get; set; }
|
||||||
|
public DbSet<ServiceShare> ServiceShares { get; set; }
|
||||||
|
|
||||||
|
public DbSet<GiftCode> GiftCodes { get; set; }
|
||||||
|
public DbSet<GiftCodeUse> GiftCodeUses { get; set; }
|
||||||
|
|
||||||
|
public DbSet<Coupon> Coupons { get; set; }
|
||||||
|
public DbSet<CouponUse> CouponUses { get; set; }
|
||||||
|
|
||||||
|
// Community
|
||||||
|
public DbSet<Post> Posts { get; set; }
|
||||||
|
public DbSet<PostComment> PostComments { get; set; }
|
||||||
|
public DbSet<PostLike> PostLikes { get; set; }
|
||||||
|
public DbSet<WordFilter> WordFilters { get; set; }
|
||||||
|
|
||||||
|
public DataContext(ConfigService configService)
|
||||||
|
{
|
||||||
|
ConfigService = configService;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
|
{
|
||||||
|
if (!optionsBuilder.IsConfigured)
|
||||||
|
{
|
||||||
|
var config = ConfigService.Get().Database;
|
||||||
|
|
||||||
|
if (config.UseSqlite)
|
||||||
|
optionsBuilder.UseSqlite($"Data Source={config.SqlitePath}");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var connectionString = $"host={config.Host};" +
|
||||||
|
$"port={config.Port};" +
|
||||||
|
$"database={config.Database};" +
|
||||||
|
$"uid={config.Username};" +
|
||||||
|
$"pwd={config.Password}";
|
||||||
|
|
||||||
|
optionsBuilder.UseMySql(
|
||||||
|
connectionString,
|
||||||
|
ServerVersion.AutoDetect(connectionString),
|
||||||
|
builder => builder.EnableRetryOnFailure(5)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
Moonlight/App/Database/Entities/Community/Post.cs
Normal file
16
Moonlight/App/Database/Entities/Community/Post.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using Moonlight.App.Database.Enums;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Entities.Community;
|
||||||
|
|
||||||
|
public class Post
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Title { get; set; } = "";
|
||||||
|
public string Content { get; set; } = "";
|
||||||
|
public User Author { get; set; }
|
||||||
|
public PostType Type { get; set; }
|
||||||
|
public List<PostComment> Comments { get; set; } = new();
|
||||||
|
public List<PostLike> Likes { get; set; } = new();
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
10
Moonlight/App/Database/Entities/Community/PostComment.cs
Normal file
10
Moonlight/App/Database/Entities/Community/PostComment.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Community;
|
||||||
|
|
||||||
|
public class PostComment
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Content { get; set; } = "";
|
||||||
|
public User Author { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
8
Moonlight/App/Database/Entities/Community/PostLike.cs
Normal file
8
Moonlight/App/Database/Entities/Community/PostLike.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Community;
|
||||||
|
|
||||||
|
public class PostLike
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public User User { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
7
Moonlight/App/Database/Entities/Community/WordFilter.cs
Normal file
7
Moonlight/App/Database/Entities/Community/WordFilter.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Community;
|
||||||
|
|
||||||
|
public class WordFilter
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Filter { get; set; } = "";
|
||||||
|
}
|
9
Moonlight/App/Database/Entities/Store/Category.cs
Normal file
9
Moonlight/App/Database/Entities/Store/Category.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
public class Category
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
public string Slug { get; set; } = "";
|
||||||
|
}
|
9
Moonlight/App/Database/Entities/Store/Coupon.cs
Normal file
9
Moonlight/App/Database/Entities/Store/Coupon.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
public class Coupon
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Code { get; set; } = "";
|
||||||
|
public int Percent { get; set; }
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
7
Moonlight/App/Database/Entities/Store/CouponUse.cs
Normal file
7
Moonlight/App/Database/Entities/Store/CouponUse.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
public class CouponUse
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public Coupon Coupon { get; set; }
|
||||||
|
}
|
9
Moonlight/App/Database/Entities/Store/GiftCode.cs
Normal file
9
Moonlight/App/Database/Entities/Store/GiftCode.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
public class GiftCode
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Code { get; set; } = "";
|
||||||
|
public double Value { get; set; }
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
7
Moonlight/App/Database/Entities/Store/GiftCodeUse.cs
Normal file
7
Moonlight/App/Database/Entities/Store/GiftCodeUse.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
public class GiftCodeUse
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public GiftCode GiftCode { get; set; }
|
||||||
|
}
|
23
Moonlight/App/Database/Entities/Store/Product.cs
Normal file
23
Moonlight/App/Database/Entities/Store/Product.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
using Moonlight.App.Database.Enums;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
public class Product
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public Category Category { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
public string Slug { get; set; } = "";
|
||||||
|
|
||||||
|
public double Price { get; set; }
|
||||||
|
public int Stock { get; set; }
|
||||||
|
public int MaxPerUser { get; set; }
|
||||||
|
public int Duration { get; set; }
|
||||||
|
|
||||||
|
public ServiceType Type { get; set; }
|
||||||
|
public string ConfigJson { get; set; } = "{}";
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
18
Moonlight/App/Database/Entities/Store/Service.cs
Normal file
18
Moonlight/App/Database/Entities/Store/Service.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
public class Service
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string? Nickname { get; set; }
|
||||||
|
|
||||||
|
public bool Suspended { get; set; } = false;
|
||||||
|
|
||||||
|
public Product Product { get; set; }
|
||||||
|
public string? ConfigJsonOverride { get; set; }
|
||||||
|
|
||||||
|
public User Owner { get; set; }
|
||||||
|
public List<ServiceShare> Shares { get; set; } = new();
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public DateTime RenewAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
7
Moonlight/App/Database/Entities/Store/ServiceShare.cs
Normal file
7
Moonlight/App/Database/Entities/Store/ServiceShare.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
public class ServiceShare
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public User User { get; set; }
|
||||||
|
}
|
8
Moonlight/App/Database/Entities/Store/Transaction.cs
Normal file
8
Moonlight/App/Database/Entities/Store/Transaction.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
public class Transaction
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public double Price { get; set; }
|
||||||
|
public string Text { get; set; } = "";
|
||||||
|
}
|
18
Moonlight/App/Database/Entities/Tickets/Ticket.cs
Normal file
18
Moonlight/App/Database/Entities/Tickets/Ticket.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
using Moonlight.App.Database.Enums;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Entities.Tickets;
|
||||||
|
|
||||||
|
public class Ticket
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public User Creator { get; set; }
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
public string Tries { get; set; } = "";
|
||||||
|
public TicketPriority Priority { get; set; } = TicketPriority.Low;
|
||||||
|
public bool Open { get; set; } = true;
|
||||||
|
|
||||||
|
public List<TicketMessage> Messages = new();
|
||||||
|
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
11
Moonlight/App/Database/Entities/Tickets/TicketMessage.cs
Normal file
11
Moonlight/App/Database/Entities/Tickets/TicketMessage.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Moonlight.App.Database.Entities.Tickets;
|
||||||
|
|
||||||
|
public class TicketMessage
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public User? Sender { get; set; }
|
||||||
|
public bool IsSupport { get; set; }
|
||||||
|
public string Content { get; set; } = "";
|
||||||
|
public string? Attachment { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
}
|
28
Moonlight/App/Database/Entities/User.cs
Normal file
28
Moonlight/App/Database/Entities/User.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
public class User
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Email { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
public string? Avatar { get; set; } = null;
|
||||||
|
public string? TotpKey { get; set; } = null;
|
||||||
|
|
||||||
|
// Store
|
||||||
|
public double Balance { get; set; }
|
||||||
|
public List<Transaction> Transactions { get; set; } = new();
|
||||||
|
|
||||||
|
public List<CouponUse> CouponUses { get; set; } = new();
|
||||||
|
public List<GiftCodeUse> GiftCodeUses { get; set; } = new();
|
||||||
|
|
||||||
|
// Meta data
|
||||||
|
public string Flags { get; set; } = "";
|
||||||
|
public int Permissions { get; set; } = 0;
|
||||||
|
|
||||||
|
// Timestamps
|
||||||
|
public DateTime TokenValidTimestamp { get; set; } = DateTime.UtcNow.AddMinutes(-10);
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
}
|
8
Moonlight/App/Database/Enums/PostType.cs
Normal file
8
Moonlight/App/Database/Enums/PostType.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Moonlight.App.Database.Enums;
|
||||||
|
|
||||||
|
public enum PostType
|
||||||
|
{
|
||||||
|
Project = 0,
|
||||||
|
Announcement = 1,
|
||||||
|
Event = 2
|
||||||
|
}
|
9
Moonlight/App/Database/Enums/ServiceType.cs
Normal file
9
Moonlight/App/Database/Enums/ServiceType.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Moonlight.App.Database.Enums;
|
||||||
|
|
||||||
|
public enum ServiceType
|
||||||
|
{
|
||||||
|
Server,
|
||||||
|
Webspace,
|
||||||
|
Database,
|
||||||
|
Domain
|
||||||
|
}
|
9
Moonlight/App/Database/Enums/TicketPriority.cs
Normal file
9
Moonlight/App/Database/Enums/TicketPriority.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace Moonlight.App.Database.Enums;
|
||||||
|
|
||||||
|
public enum TicketPriority
|
||||||
|
{
|
||||||
|
Low,
|
||||||
|
Medium,
|
||||||
|
High,
|
||||||
|
Critical
|
||||||
|
}
|
67
Moonlight/App/Database/Migrations/20231013200303_AddedUser.Designer.cs
generated
Normal file
67
Moonlight/App/Database/Migrations/20231013200303_AddedUser.Designer.cs
generated
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20231013200303_AddedUser")]
|
||||||
|
partial class AddedUser
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Avatar")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flags")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Permissions")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TokenValidTimestamp")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TotpKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedUser : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Users",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Username = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Email = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Password = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Avatar = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
TotpKey = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
Flags = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Permissions = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
TokenValidTimestamp = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Users", x => x.Id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Users");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
341
Moonlight/App/Database/Migrations/20231017075519_AddStoreModels.Designer.cs
generated
Normal file
341
Moonlight/App/Database/Migrations/20231017075519_AddStoreModels.Designer.cs
generated
Normal file
|
@ -0,0 +1,341 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20231017075519_AddStoreModels")]
|
||||||
|
partial class AddStoreModels
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Categories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Coupon", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Percent")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Coupons");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CouponId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CouponId");
|
||||||
|
|
||||||
|
b.ToTable("CouponUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GiftCodeId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GiftCodeId");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodeUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("CategoryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJson")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Duration")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MaxPerUser")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Stock")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CategoryId");
|
||||||
|
|
||||||
|
b.ToTable("Products");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJsonOverride")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Nickname")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProductId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RenewAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Suspended")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("Services");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("ServiceId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServiceId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("ServiceShares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Avatar")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flags")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Permissions")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TokenValidTimestamp")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TotpKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Coupon", "Coupon")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CouponId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Coupon");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.GiftCode", "GiftCode")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GiftCodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("GiftCode");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Category", "Category")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoryId");
|
||||||
|
|
||||||
|
b.Navigation("Category");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Product", "Product")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Service", null)
|
||||||
|
.WithMany("Shares")
|
||||||
|
.HasForeignKey("ServiceId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Shares");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,245 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddStoreModels : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Categories",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Description = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Slug = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Categories", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Coupons",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Code = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Percent = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Amount = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Coupons", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "GiftCodes",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Code = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Value = table.Column<double>(type: "REAL", nullable: false),
|
||||||
|
Amount = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_GiftCodes", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Products",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
CategoryId = table.Column<int>(type: "INTEGER", nullable: true),
|
||||||
|
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Description = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Slug = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Price = table.Column<double>(type: "REAL", nullable: false),
|
||||||
|
Stock = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
MaxPerUser = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Duration = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Type = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
ConfigJson = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Products", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Products_Categories_CategoryId",
|
||||||
|
column: x => x.CategoryId,
|
||||||
|
principalTable: "Categories",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "CouponUses",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
CouponId = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_CouponUses", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_CouponUses_Coupons_CouponId",
|
||||||
|
column: x => x.CouponId,
|
||||||
|
principalTable: "Coupons",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "GiftCodeUses",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
GiftCodeId = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_GiftCodeUses", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_GiftCodeUses_GiftCodes_GiftCodeId",
|
||||||
|
column: x => x.GiftCodeId,
|
||||||
|
principalTable: "GiftCodes",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Services",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Nickname = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
Suspended = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
ProductId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
ConfigJsonOverride = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
OwnerId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
RenewAt = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Services", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Services_Products_ProductId",
|
||||||
|
column: x => x.ProductId,
|
||||||
|
principalTable: "Products",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Services_Users_OwnerId",
|
||||||
|
column: x => x.OwnerId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ServiceShares",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
UserId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
ServiceId = table.Column<int>(type: "INTEGER", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ServiceShares", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ServiceShares_Services_ServiceId",
|
||||||
|
column: x => x.ServiceId,
|
||||||
|
principalTable: "Services",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ServiceShares_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_CouponUses_CouponId",
|
||||||
|
table: "CouponUses",
|
||||||
|
column: "CouponId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_GiftCodeUses_GiftCodeId",
|
||||||
|
table: "GiftCodeUses",
|
||||||
|
column: "GiftCodeId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Products_CategoryId",
|
||||||
|
table: "Products",
|
||||||
|
column: "CategoryId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Services_OwnerId",
|
||||||
|
table: "Services",
|
||||||
|
column: "OwnerId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Services_ProductId",
|
||||||
|
table: "Services",
|
||||||
|
column: "ProductId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ServiceShares_ServiceId",
|
||||||
|
table: "ServiceShares",
|
||||||
|
column: "ServiceId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ServiceShares_UserId",
|
||||||
|
table: "ServiceShares",
|
||||||
|
column: "UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "CouponUses");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "GiftCodeUses");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ServiceShares");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Coupons");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "GiftCodes");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Services");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Products");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Categories");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
371
Moonlight/App/Database/Migrations/20231018203522_AddedUserStoreData.Designer.cs
generated
Normal file
371
Moonlight/App/Database/Migrations/20231018203522_AddedUserStoreData.Designer.cs
generated
Normal file
|
@ -0,0 +1,371 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20231018203522_AddedUserStoreData")]
|
||||||
|
partial class AddedUserStoreData
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Categories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Coupon", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Percent")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Coupons");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CouponId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CouponId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("CouponUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GiftCodeId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GiftCodeId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodeUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CategoryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJson")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Duration")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MaxPerUser")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Stock")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CategoryId");
|
||||||
|
|
||||||
|
b.ToTable("Products");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJsonOverride")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Nickname")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProductId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RenewAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Suspended")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("Services");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("ServiceId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServiceId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("ServiceShares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Avatar")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Balance")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flags")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Permissions")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TokenValidTimestamp")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TotpKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Coupon", "Coupon")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CouponId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("CouponUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("Coupon");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.GiftCode", "GiftCode")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GiftCodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("GiftCodeUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("GiftCode");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Category", "Category")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Category");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Product", "Product")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Service", null)
|
||||||
|
.WithMany("Shares")
|
||||||
|
.HasForeignKey("ServiceId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Shares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("CouponUses");
|
||||||
|
|
||||||
|
b.Navigation("GiftCodeUses");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedUserStoreData : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Products_Categories_CategoryId",
|
||||||
|
table: "Products");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<double>(
|
||||||
|
name: "Balance",
|
||||||
|
table: "Users",
|
||||||
|
type: "REAL",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0.0);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "CategoryId",
|
||||||
|
table: "Products",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "INTEGER",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "UserId",
|
||||||
|
table: "GiftCodeUses",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "UserId",
|
||||||
|
table: "CouponUses",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_GiftCodeUses_UserId",
|
||||||
|
table: "GiftCodeUses",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_CouponUses_UserId",
|
||||||
|
table: "CouponUses",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_CouponUses_Users_UserId",
|
||||||
|
table: "CouponUses",
|
||||||
|
column: "UserId",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_GiftCodeUses_Users_UserId",
|
||||||
|
table: "GiftCodeUses",
|
||||||
|
column: "UserId",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Products_Categories_CategoryId",
|
||||||
|
table: "Products",
|
||||||
|
column: "CategoryId",
|
||||||
|
principalTable: "Categories",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_CouponUses_Users_UserId",
|
||||||
|
table: "CouponUses");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_GiftCodeUses_Users_UserId",
|
||||||
|
table: "GiftCodeUses");
|
||||||
|
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Products_Categories_CategoryId",
|
||||||
|
table: "Products");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_GiftCodeUses_UserId",
|
||||||
|
table: "GiftCodeUses");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_CouponUses_UserId",
|
||||||
|
table: "CouponUses");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Balance",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "UserId",
|
||||||
|
table: "GiftCodeUses");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "UserId",
|
||||||
|
table: "CouponUses");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "CategoryId",
|
||||||
|
table: "Products",
|
||||||
|
type: "INTEGER",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "INTEGER");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Products_Categories_CategoryId",
|
||||||
|
table: "Products",
|
||||||
|
column: "CategoryId",
|
||||||
|
principalTable: "Categories",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
403
Moonlight/App/Database/Migrations/20231018204737_AddedTransactions.Designer.cs
generated
Normal file
403
Moonlight/App/Database/Migrations/20231018204737_AddedTransactions.Designer.cs
generated
Normal file
|
@ -0,0 +1,403 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20231018204737_AddedTransactions")]
|
||||||
|
partial class AddedTransactions
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Categories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Coupon", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Percent")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Coupons");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CouponId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CouponId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("CouponUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GiftCodeId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GiftCodeId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodeUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CategoryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJson")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Duration")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MaxPerUser")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Stock")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CategoryId");
|
||||||
|
|
||||||
|
b.ToTable("Products");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJsonOverride")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Nickname")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProductId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RenewAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Suspended")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("Services");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("ServiceId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServiceId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("ServiceShares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Transaction");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Avatar")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Balance")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flags")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Permissions")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TokenValidTimestamp")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TotpKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Coupon", "Coupon")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CouponId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("CouponUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("Coupon");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.GiftCode", "GiftCode")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GiftCodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("GiftCodeUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("GiftCode");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Category", "Category")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Category");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Product", "Product")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Service", null)
|
||||||
|
.WithMany("Shares")
|
||||||
|
.HasForeignKey("ServiceId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("Transactions")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Shares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("CouponUses");
|
||||||
|
|
||||||
|
b.Navigation("GiftCodeUses");
|
||||||
|
|
||||||
|
b.Navigation("Transactions");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedTransactions : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Transaction",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Price = table.Column<double>(type: "REAL", nullable: false),
|
||||||
|
Text = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
UserId = table.Column<int>(type: "INTEGER", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Transaction", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Transaction_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Transaction_UserId",
|
||||||
|
table: "Transaction",
|
||||||
|
column: "UserId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Transaction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
539
Moonlight/App/Database/Migrations/20231027105412_AddPostsModels.Designer.cs
generated
Normal file
539
Moonlight/App/Database/Migrations/20231027105412_AddPostsModels.Designer.cs
generated
Normal file
|
@ -0,0 +1,539 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20231027105412_AddPostsModels")]
|
||||||
|
partial class AddPostsModels
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AuthorId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AuthorId");
|
||||||
|
|
||||||
|
b.ToTable("Posts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AuthorId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PostId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AuthorId");
|
||||||
|
|
||||||
|
b.HasIndex("PostId");
|
||||||
|
|
||||||
|
b.ToTable("PostComments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PostId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PostId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("PostLikes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Categories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Coupon", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Percent")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Coupons");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CouponId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CouponId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("CouponUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GiftCodeId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GiftCodeId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodeUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CategoryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJson")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Duration")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MaxPerUser")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Stock")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CategoryId");
|
||||||
|
|
||||||
|
b.ToTable("Products");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJsonOverride")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Nickname")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProductId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RenewAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Suspended")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("Services");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("ServiceId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServiceId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("ServiceShares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Transaction");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Avatar")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Balance")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flags")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Permissions")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TokenValidTimestamp")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TotpKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AuthorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Author");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AuthorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
|
||||||
|
.WithMany("Comments")
|
||||||
|
.HasForeignKey("PostId");
|
||||||
|
|
||||||
|
b.Navigation("Author");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
|
||||||
|
.WithMany("Likes")
|
||||||
|
.HasForeignKey("PostId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Coupon", "Coupon")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CouponId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("CouponUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("Coupon");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.GiftCode", "GiftCode")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GiftCodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("GiftCodeUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("GiftCode");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Category", "Category")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Category");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Product", "Product")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Service", null)
|
||||||
|
.WithMany("Shares")
|
||||||
|
.HasForeignKey("ServiceId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("Transactions")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Comments");
|
||||||
|
|
||||||
|
b.Navigation("Likes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Shares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("CouponUses");
|
||||||
|
|
||||||
|
b.Navigation("GiftCodeUses");
|
||||||
|
|
||||||
|
b.Navigation("Transactions");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddPostsModels : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Posts",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Title = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Content = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
AuthorId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
Type = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Posts", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Posts_Users_AuthorId",
|
||||||
|
column: x => x.AuthorId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PostComments",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Content = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
AuthorId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
PostId = table.Column<int>(type: "INTEGER", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PostComments", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PostComments_Posts_PostId",
|
||||||
|
column: x => x.PostId,
|
||||||
|
principalTable: "Posts",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PostComments_Users_AuthorId",
|
||||||
|
column: x => x.AuthorId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "PostLikes",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
UserId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: false),
|
||||||
|
PostId = table.Column<int>(type: "INTEGER", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_PostLikes", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PostLikes_Posts_PostId",
|
||||||
|
column: x => x.PostId,
|
||||||
|
principalTable: "Posts",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_PostLikes_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PostComments_AuthorId",
|
||||||
|
table: "PostComments",
|
||||||
|
column: "AuthorId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PostComments_PostId",
|
||||||
|
table: "PostComments",
|
||||||
|
column: "PostId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PostLikes_PostId",
|
||||||
|
table: "PostLikes",
|
||||||
|
column: "PostId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_PostLikes_UserId",
|
||||||
|
table: "PostLikes",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Posts_AuthorId",
|
||||||
|
table: "Posts",
|
||||||
|
column: "AuthorId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PostComments");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "PostLikes");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Posts");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
554
Moonlight/App/Database/Migrations/20231028214520_AddedWordFilter.Designer.cs
generated
Normal file
554
Moonlight/App/Database/Migrations/20231028214520_AddedWordFilter.Designer.cs
generated
Normal file
|
@ -0,0 +1,554 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
[Migration("20231028214520_AddedWordFilter")]
|
||||||
|
partial class AddedWordFilter
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AuthorId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AuthorId");
|
||||||
|
|
||||||
|
b.ToTable("Posts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AuthorId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PostId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AuthorId");
|
||||||
|
|
||||||
|
b.HasIndex("PostId");
|
||||||
|
|
||||||
|
b.ToTable("PostComments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PostId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PostId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("PostLikes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.WordFilter", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Filter")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("WordFilters");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Categories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Coupon", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Percent")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Coupons");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CouponId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CouponId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("CouponUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GiftCodeId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GiftCodeId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodeUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CategoryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJson")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Duration")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MaxPerUser")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Stock")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CategoryId");
|
||||||
|
|
||||||
|
b.ToTable("Products");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJsonOverride")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Nickname")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProductId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RenewAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Suspended")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("Services");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("ServiceId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServiceId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("ServiceShares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Transaction");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Avatar")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Balance")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flags")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Permissions")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TokenValidTimestamp")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TotpKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AuthorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Author");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AuthorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
|
||||||
|
.WithMany("Comments")
|
||||||
|
.HasForeignKey("PostId");
|
||||||
|
|
||||||
|
b.Navigation("Author");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
|
||||||
|
.WithMany("Likes")
|
||||||
|
.HasForeignKey("PostId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Coupon", "Coupon")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CouponId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("CouponUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("Coupon");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.GiftCode", "GiftCode")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GiftCodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("GiftCodeUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("GiftCode");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Category", "Category")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Category");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Product", "Product")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Service", null)
|
||||||
|
.WithMany("Shares")
|
||||||
|
.HasForeignKey("ServiceId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("Transactions")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Comments");
|
||||||
|
|
||||||
|
b.Navigation("Likes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Shares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("CouponUses");
|
||||||
|
|
||||||
|
b.Navigation("GiftCodeUses");
|
||||||
|
|
||||||
|
b.Navigation("Transactions");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedWordFilter : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "WordFilters",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Filter = table.Column<string>(type: "TEXT", nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_WordFilters", x => x.Id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "WordFilters");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
551
Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs
Normal file
551
Moonlight/App/Database/Migrations/DataContextModelSnapshot.cs
Normal file
|
@ -0,0 +1,551 @@
|
||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using Moonlight.App.Database;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Moonlight.App.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DataContext))]
|
||||||
|
partial class DataContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder.HasAnnotation("ProductVersion", "7.0.2");
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AuthorId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Title")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AuthorId");
|
||||||
|
|
||||||
|
b.ToTable("Posts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AuthorId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Content")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PostId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AuthorId");
|
||||||
|
|
||||||
|
b.HasIndex("PostId");
|
||||||
|
|
||||||
|
b.ToTable("PostComments");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("PostId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("PostId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("PostLikes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.WordFilter", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Filter")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("WordFilters");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Category", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Categories");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Coupon", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Percent")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Coupons");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CouponId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CouponId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("CouponUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCode", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Amount")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Code")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Value")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("GiftCodeId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GiftCodeId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("GiftCodeUses");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("CategoryId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJson")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Description")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Duration")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("MaxPerUser")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Slug")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Stock")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("Type")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("CategoryId");
|
||||||
|
|
||||||
|
b.ToTable("Products");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("ConfigJsonOverride")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Nickname")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("OwnerId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("ProductId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RenewAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("Suspended")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("OwnerId");
|
||||||
|
|
||||||
|
b.HasIndex("ProductId");
|
||||||
|
|
||||||
|
b.ToTable("Services");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int?>("ServiceId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServiceId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("ServiceShares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<double>("Price")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<string>("Text")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int?>("UserId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Transaction");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Avatar")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<double>("Balance")
|
||||||
|
.HasColumnType("REAL");
|
||||||
|
|
||||||
|
b.Property<DateTime>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Email")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Flags")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("Permissions")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TokenValidTimestamp")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("TotpKey")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AuthorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Author");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostComment", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Author")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AuthorId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
|
||||||
|
.WithMany("Comments")
|
||||||
|
.HasForeignKey("PostId");
|
||||||
|
|
||||||
|
b.Navigation("Author");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.PostLike", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Community.Post", null)
|
||||||
|
.WithMany("Likes")
|
||||||
|
.HasForeignKey("PostId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.CouponUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Coupon", "Coupon")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CouponId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("CouponUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("Coupon");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.GiftCodeUse", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.GiftCode", "GiftCode")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("GiftCodeId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("GiftCodeUses")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
|
||||||
|
b.Navigation("GiftCode");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Product", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Category", "Category")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoryId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Category");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OwnerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Product", "Product")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ProductId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Owner");
|
||||||
|
|
||||||
|
b.Navigation("Product");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.ServiceShare", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.Store.Service", null)
|
||||||
|
.WithMany("Shares")
|
||||||
|
.HasForeignKey("ServiceId");
|
||||||
|
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Transaction", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Moonlight.App.Database.Entities.User", null)
|
||||||
|
.WithMany("Transactions")
|
||||||
|
.HasForeignKey("UserId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Community.Post", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Comments");
|
||||||
|
|
||||||
|
b.Navigation("Likes");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.Store.Service", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Shares");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Moonlight.App.Database.Entities.User", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("CouponUses");
|
||||||
|
|
||||||
|
b.Navigation("GiftCodeUses");
|
||||||
|
|
||||||
|
b.Navigation("Transactions");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
Moonlight/App/Event/Args/MailVerificationEventArgs.cs
Normal file
9
Moonlight/App/Event/Args/MailVerificationEventArgs.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Event.Args;
|
||||||
|
|
||||||
|
public class MailVerificationEventArgs
|
||||||
|
{
|
||||||
|
public User User { get; set; }
|
||||||
|
public string Jwt { get; set; }
|
||||||
|
}
|
10
Moonlight/App/Event/Args/TransactionCreatedEventArgs.cs
Normal file
10
Moonlight/App/Event/Args/TransactionCreatedEventArgs.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Event.Args;
|
||||||
|
|
||||||
|
public class TransactionCreatedEventArgs
|
||||||
|
{
|
||||||
|
public Transaction Transaction { get; set; }
|
||||||
|
public User User { get; set; }
|
||||||
|
}
|
22
Moonlight/App/Event/Events.cs
Normal file
22
Moonlight/App/Event/Events.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Database.Entities.Community;
|
||||||
|
using Moonlight.App.Database.Entities.Store;
|
||||||
|
using Moonlight.App.Event.Args;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Event;
|
||||||
|
|
||||||
|
public class Events
|
||||||
|
{
|
||||||
|
public static EventHandler<User> OnUserRegistered;
|
||||||
|
public static EventHandler<User> OnUserPasswordChanged;
|
||||||
|
public static EventHandler<User> OnUserTotpSet;
|
||||||
|
public static EventHandler<MailVerificationEventArgs> OnUserMailVerify;
|
||||||
|
public static EventHandler<Service> OnServiceOrdered;
|
||||||
|
public static EventHandler<TransactionCreatedEventArgs> OnTransactionCreated;
|
||||||
|
public static EventHandler<Post> OnPostCreated;
|
||||||
|
public static EventHandler<Post> OnPostUpdated;
|
||||||
|
public static EventHandler<Post> OnPostDeleted;
|
||||||
|
public static EventHandler<Post> OnPostLiked;
|
||||||
|
public static EventHandler<PostComment> OnPostCommentCreated;
|
||||||
|
public static EventHandler<PostComment> OnPostCommentDeleted;
|
||||||
|
}
|
16
Moonlight/App/Exceptions/DisplayException.cs
Normal file
16
Moonlight/App/Exceptions/DisplayException.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
namespace Moonlight.App.Exceptions;
|
||||||
|
|
||||||
|
public class DisplayException : Exception
|
||||||
|
{
|
||||||
|
public DisplayException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public DisplayException(string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using Moonlight.App.Models.Enums;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Extensions.Attributes;
|
||||||
|
|
||||||
|
public class RequirePermissionAttribute : Attribute
|
||||||
|
{
|
||||||
|
public int PermissionInteger = 0;
|
||||||
|
|
||||||
|
public RequirePermissionAttribute(){}
|
||||||
|
|
||||||
|
public RequirePermissionAttribute(int perms)
|
||||||
|
{
|
||||||
|
PermissionInteger = perms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequirePermissionAttribute(Permission permission)
|
||||||
|
{
|
||||||
|
PermissionInteger = (int)permission;
|
||||||
|
}
|
||||||
|
}
|
8
Moonlight/App/Extensions/Attributes/SelectorAttribute.cs
Normal file
8
Moonlight/App/Extensions/Attributes/SelectorAttribute.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Moonlight.App.Extensions.Attributes;
|
||||||
|
|
||||||
|
public class SelectorAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string SelectorProp { get; set; } = "";
|
||||||
|
public string DisplayProp { get; set; } = "";
|
||||||
|
public bool UseDropdown { get; set; } = false;
|
||||||
|
}
|
13
Moonlight/App/Extensions/ConfigurationBuilderExtensions.cs
Normal file
13
Moonlight/App/Extensions/ConfigurationBuilderExtensions.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Extensions;
|
||||||
|
|
||||||
|
public static class ConfigurationBuilderExtensions
|
||||||
|
{
|
||||||
|
public static IConfigurationBuilder AddJsonString(this IConfigurationBuilder configurationBuilder, string json)
|
||||||
|
{
|
||||||
|
var bytes = Encoding.UTF8.GetBytes(json);
|
||||||
|
var stream = new MemoryStream(bytes);
|
||||||
|
return configurationBuilder.AddJsonStream(stream);
|
||||||
|
}
|
||||||
|
}
|
37
Moonlight/App/Extensions/EventHandlerExtensions.cs
Normal file
37
Moonlight/App/Extensions/EventHandlerExtensions.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
namespace Moonlight.App.Extensions;
|
||||||
|
|
||||||
|
public static class EventHandlerExtensions
|
||||||
|
{
|
||||||
|
public static async Task InvokeAsync(this EventHandler handler)
|
||||||
|
{
|
||||||
|
var tasks = handler
|
||||||
|
.GetInvocationList()
|
||||||
|
.Select(x => new Task(() => x.DynamicInvoke(null, null)))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var task in tasks)
|
||||||
|
{
|
||||||
|
task.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(tasks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task InvokeAsync<T>(this EventHandler<T>? handler, T? data = default(T))
|
||||||
|
{
|
||||||
|
if(handler == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var tasks = handler
|
||||||
|
.GetInvocationList()
|
||||||
|
.Select(x => new Task(() => x.DynamicInvoke(null, data)))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach (var task in tasks)
|
||||||
|
{
|
||||||
|
task.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(tasks);
|
||||||
|
}
|
||||||
|
}
|
17
Moonlight/App/Extensions/TypeExtension.cs
Normal file
17
Moonlight/App/Extensions/TypeExtension.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Extensions;
|
||||||
|
|
||||||
|
public static class TypeExtensions
|
||||||
|
{
|
||||||
|
public static PropertyInfo? GetProperty<T, TValue>(this T type, Expression<Func<T, TValue>> selector)
|
||||||
|
where T : class
|
||||||
|
{
|
||||||
|
Expression expression = selector.Body;
|
||||||
|
|
||||||
|
return expression.NodeType == ExpressionType.MemberAccess
|
||||||
|
? (PropertyInfo) ((MemberExpression) expression).Member
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
}
|
12
Moonlight/App/Helpers/ComponentHelper.cs
Normal file
12
Moonlight/App/Helpers/ComponentHelper.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public static class ComponentHelper
|
||||||
|
{
|
||||||
|
public static RenderFragment FromType(Type type) => builder =>
|
||||||
|
{
|
||||||
|
builder.OpenComponent(0, type);
|
||||||
|
builder.CloseComponent();
|
||||||
|
};
|
||||||
|
}
|
280
Moonlight/App/Helpers/Formatter.cs
Normal file
280
Moonlight/App/Helpers/Formatter.cs
Normal file
|
@ -0,0 +1,280 @@
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public static class Formatter
|
||||||
|
{
|
||||||
|
public static string GenerateString(int length)
|
||||||
|
{
|
||||||
|
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
var stringBuilder = new StringBuilder();
|
||||||
|
var random = new Random();
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
stringBuilder.Append(chars[random.Next(chars.Length)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stringBuilder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string IntToStringWithLeadingZeros(int number, int n)
|
||||||
|
{
|
||||||
|
string result = number.ToString();
|
||||||
|
int length = result.Length;
|
||||||
|
|
||||||
|
for (int i = length; i < n; i++)
|
||||||
|
{
|
||||||
|
result = "0" + result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CapitalizeFirstCharacter(string input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
{
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
char firstChar = char.ToUpper(input[0]);
|
||||||
|
string restOfString = input.Substring(1);
|
||||||
|
|
||||||
|
return firstChar + restOfString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CutInHalf(string input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
return input;
|
||||||
|
|
||||||
|
int length = input.Length;
|
||||||
|
int halfLength = length / 2;
|
||||||
|
|
||||||
|
return input.Substring(0, halfLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool EndsInOneOf(string suffix, IEnumerable<string> strings)
|
||||||
|
{
|
||||||
|
foreach (string str in strings)
|
||||||
|
{
|
||||||
|
if (suffix.EndsWith(str))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsOneOf(string textToSearch, IEnumerable<string> strings, out string foundText)
|
||||||
|
{
|
||||||
|
foreach (string str in strings)
|
||||||
|
{
|
||||||
|
if (textToSearch.Contains(str))
|
||||||
|
{
|
||||||
|
foundText = str;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foundText = "";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool ContainsOneOf(string textToSearch, IEnumerable<string> strings)
|
||||||
|
{
|
||||||
|
return ContainsOneOf(textToSearch, strings, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FormatSize(long bytes)
|
||||||
|
{
|
||||||
|
var i = Math.Abs(bytes) / 1024D;
|
||||||
|
if (i < 1)
|
||||||
|
{
|
||||||
|
return bytes + " B";
|
||||||
|
}
|
||||||
|
else if (i / 1024D < 1)
|
||||||
|
{
|
||||||
|
return i.Round(2) + " KB";
|
||||||
|
}
|
||||||
|
else if (i / (1024D * 1024D) < 1)
|
||||||
|
{
|
||||||
|
return (i / 1024D).Round(2) + " MB";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (i / (1024D * 1024D)).Round(2) + " GB";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double Round(this double d, int decimals)
|
||||||
|
{
|
||||||
|
return Math.Round(d, decimals);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ReplaceEnd(string input, string substringToReplace, string newSubstring)
|
||||||
|
{
|
||||||
|
int lastIndexOfSubstring = input.LastIndexOf(substringToReplace);
|
||||||
|
if (lastIndexOfSubstring >= 0)
|
||||||
|
{
|
||||||
|
input = input.Remove(lastIndexOfSubstring, substringToReplace.Length)
|
||||||
|
.Insert(lastIndexOfSubstring, newSubstring);
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ConvertCamelCaseToSpaces(string input)
|
||||||
|
{
|
||||||
|
StringBuilder output = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (char c in input)
|
||||||
|
{
|
||||||
|
if (char.IsUpper(c))
|
||||||
|
{
|
||||||
|
output.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
output.Append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.ToString().Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FormatUptime(double uptime)
|
||||||
|
{
|
||||||
|
TimeSpan t = TimeSpan.FromMilliseconds(uptime);
|
||||||
|
|
||||||
|
return FormatUptime(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FormatUptime(TimeSpan t)
|
||||||
|
{
|
||||||
|
if (t.Days > 0)
|
||||||
|
{
|
||||||
|
return $"{t.Days}d {t.Hours}h {t.Minutes}m {t.Seconds}s";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $"{t.Hours}h {t.Minutes}m {t.Seconds}s";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FormatDate(DateTime e)
|
||||||
|
{
|
||||||
|
string i2s(int i)
|
||||||
|
{
|
||||||
|
if (i.ToString().Length < 2)
|
||||||
|
return "0" + i;
|
||||||
|
return i.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{i2s(e.Day)}.{i2s(e.Month)}.{e.Year} {i2s(e.Hour)}:{i2s(e.Minute)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FormatDateOnly(DateTime e)
|
||||||
|
{
|
||||||
|
string i2s(int i)
|
||||||
|
{
|
||||||
|
if (i.ToString().Length < 2)
|
||||||
|
return "0" + i;
|
||||||
|
return i.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{i2s(e.Day)}.{i2s(e.Month)}.{e.Year}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FormatSize(double bytes)
|
||||||
|
{
|
||||||
|
var i = Math.Abs(bytes) / 1024D;
|
||||||
|
if (i < 1)
|
||||||
|
{
|
||||||
|
return bytes + " B";
|
||||||
|
}
|
||||||
|
else if (i / 1024D < 1)
|
||||||
|
{
|
||||||
|
return i.Round(2) + " KB";
|
||||||
|
}
|
||||||
|
else if (i / (1024D * 1024D) < 1)
|
||||||
|
{
|
||||||
|
return (i / 1024D).Round(2) + " MB";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (i / (1024D * 1024D)).Round(2) + " GB";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RenderFragment FormatLineBreaks(string content)
|
||||||
|
{
|
||||||
|
return builder =>
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
var arr = content.Split("\n");
|
||||||
|
|
||||||
|
foreach (var line in arr)
|
||||||
|
{
|
||||||
|
builder.AddContent(i, line);
|
||||||
|
if (i++ != arr.Length - 1)
|
||||||
|
{
|
||||||
|
builder.AddMarkupContent(i, "<br/>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string FormatAgoFromDateTime(DateTime dt)
|
||||||
|
{
|
||||||
|
TimeSpan timeSince = DateTime.UtcNow.Subtract(dt);
|
||||||
|
|
||||||
|
if (timeSince.TotalMilliseconds < 1)
|
||||||
|
return "just now";
|
||||||
|
|
||||||
|
if (timeSince.TotalMinutes < 1)
|
||||||
|
return "less than a minute ago";
|
||||||
|
|
||||||
|
if (timeSince.TotalMinutes < 2)
|
||||||
|
return "1 minute ago";
|
||||||
|
|
||||||
|
if (timeSince.TotalMinutes < 60)
|
||||||
|
return Math.Round(timeSince.TotalMinutes) + " minutes ago";
|
||||||
|
|
||||||
|
if (timeSince.TotalHours < 2)
|
||||||
|
return "1 hour ago";
|
||||||
|
|
||||||
|
if (timeSince.TotalHours < 24)
|
||||||
|
return Math.Round(timeSince.TotalHours) + " hours ago";
|
||||||
|
|
||||||
|
if (timeSince.TotalDays < 2)
|
||||||
|
return "1 day ago";
|
||||||
|
|
||||||
|
return Math.Round(timeSince.TotalDays) + " days ago";
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will replace every placeholder with the respective value if specified in the model
|
||||||
|
// For example:
|
||||||
|
// A instance of the user model has been passed in the 'models' parameter of the function.
|
||||||
|
// So the placeholder {{User.Email}} will be replaced by the value of the Email property of the model
|
||||||
|
public static string ProcessTemplating(string text, params object[] models)
|
||||||
|
{
|
||||||
|
foreach (var model in models)
|
||||||
|
{
|
||||||
|
foreach (var property in model.GetType().GetProperties())
|
||||||
|
{
|
||||||
|
var value = property.GetValue(model);
|
||||||
|
|
||||||
|
if(value == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var placeholder = "{{" + $"{model.GetType().Name}.{property.Name}" + "}}";
|
||||||
|
|
||||||
|
text = text.Replace(placeholder, value.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
172
Moonlight/App/Helpers/HashHelper.cs
Normal file
172
Moonlight/App/Helpers/HashHelper.cs
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
// Src: https://codereview.stackexchange.com/questions/176697/net-core-mvc-future-proof-hashing-of-passwords
|
||||||
|
public static class HashHelper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The default number of Iterations
|
||||||
|
/// </summary>
|
||||||
|
private const int DefaultIterations = 10000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides Information about a specific Hash Version
|
||||||
|
/// </summary>
|
||||||
|
private class HashVersion
|
||||||
|
{
|
||||||
|
public short Version { get; set; }
|
||||||
|
public int SaltSize { get; set; }
|
||||||
|
public int HashSize { get; set; }
|
||||||
|
public KeyDerivationPrf KeyDerivation { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds all possible Hash Versions
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<short, HashVersion> _versions = new Dictionary<short, HashVersion>
|
||||||
|
{
|
||||||
|
{
|
||||||
|
1, new HashVersion
|
||||||
|
{
|
||||||
|
Version = 1,
|
||||||
|
KeyDerivation = KeyDerivationPrf.HMACSHA512,
|
||||||
|
HashSize = 256 / 8,
|
||||||
|
SaltSize = 128 / 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default Hash Version, which should be used, if a new Hash is Created
|
||||||
|
/// </summary>
|
||||||
|
private static HashVersion DefaultVersion => _versions[1];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a given hash uses the latest version
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The hash</param>
|
||||||
|
/// <returns>Is the hash of the latest version?</returns>
|
||||||
|
public static bool IsLatestHashVersion(byte[] data)
|
||||||
|
{
|
||||||
|
var version = BitConverter.ToInt16(data, 0);
|
||||||
|
return version == DefaultVersion.Version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if a given hash uses the latest version
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The hash</param>
|
||||||
|
/// <returns>Is the hash of the latest version?</returns>
|
||||||
|
public static bool IsLatestHashVersion(string data)
|
||||||
|
{
|
||||||
|
var dataBytes = Convert.FromBase64String(data);
|
||||||
|
return IsLatestHashVersion(dataBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a random byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="length">The length of the byte array</param>
|
||||||
|
/// <returns>The random byte array</returns>
|
||||||
|
public static byte[] GetRandomBytes(int length)
|
||||||
|
{
|
||||||
|
var data = new byte[length];
|
||||||
|
using (var randomNumberGenerator = RandomNumberGenerator.Create())
|
||||||
|
{
|
||||||
|
randomNumberGenerator.GetBytes(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a Hash of a clear text
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clearText">the clear text</param>
|
||||||
|
/// <param name="iterations">the number of iteration the hash alogrythm should run</param>
|
||||||
|
/// <returns>the Hash</returns>
|
||||||
|
public static byte[] Hash(string clearText, int iterations = DefaultIterations)
|
||||||
|
{
|
||||||
|
//get current version
|
||||||
|
var currentVersion = DefaultVersion;
|
||||||
|
|
||||||
|
//get the byte arrays of the hash and meta information
|
||||||
|
var saltBytes = GetRandomBytes(currentVersion.SaltSize);
|
||||||
|
var versionBytes = BitConverter.GetBytes(currentVersion.Version);
|
||||||
|
var iterationBytes = BitConverter.GetBytes(iterations);
|
||||||
|
var hashBytes = KeyDerivation.Pbkdf2(clearText, saltBytes, currentVersion.KeyDerivation, iterations,
|
||||||
|
currentVersion.HashSize);
|
||||||
|
|
||||||
|
//calculate the indexes for the combined hash
|
||||||
|
var indexVersion = 0;
|
||||||
|
var indexIteration = indexVersion + 2;
|
||||||
|
var indexSalt = indexIteration + 4;
|
||||||
|
var indexHash = indexSalt + currentVersion.SaltSize;
|
||||||
|
|
||||||
|
//combine all data to one result hash
|
||||||
|
var resultBytes = new byte[2 + 4 + currentVersion.SaltSize + currentVersion.HashSize];
|
||||||
|
Array.Copy(versionBytes, 0, resultBytes, indexVersion, 2);
|
||||||
|
Array.Copy(iterationBytes, 0, resultBytes, indexIteration, 4);
|
||||||
|
Array.Copy(saltBytes, 0, resultBytes, indexSalt, currentVersion.SaltSize);
|
||||||
|
Array.Copy(hashBytes, 0, resultBytes, indexHash, currentVersion.HashSize);
|
||||||
|
return resultBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a Hash of a clear text and convert it to a Base64 String representation
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clearText">the clear text</param>
|
||||||
|
/// <param name="iterations">the number of iteration the hash alogrythm should run</param>
|
||||||
|
/// <returns>the Hash</returns>
|
||||||
|
public static string HashToString(string clearText, int iterations = DefaultIterations)
|
||||||
|
{
|
||||||
|
var data = Hash(clearText, iterations);
|
||||||
|
return Convert.ToBase64String(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies a given clear Text against a hash
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clearText">The clear text</param>
|
||||||
|
/// <param name="data">The hash</param>
|
||||||
|
/// <returns>Is the hash equal to the clear text?</returns>
|
||||||
|
public static bool Verify(string clearText, byte[] data)
|
||||||
|
{
|
||||||
|
//Get the current version and number of iterations
|
||||||
|
var currentVersion = _versions[BitConverter.ToInt16(data, 0)];
|
||||||
|
var iteration = BitConverter.ToInt32(data, 2);
|
||||||
|
|
||||||
|
//Create the byte arrays for the salt and hash
|
||||||
|
var saltBytes = new byte[currentVersion.SaltSize];
|
||||||
|
var hashBytes = new byte[currentVersion.HashSize];
|
||||||
|
|
||||||
|
//Calculate the indexes of the salt and the hash
|
||||||
|
var indexSalt = 2 + 4; // Int16 (Version) and Int32 (Iteration)
|
||||||
|
var indexHash = indexSalt + currentVersion.SaltSize;
|
||||||
|
|
||||||
|
//Fill the byte arrays with salt and hash
|
||||||
|
Array.Copy(data, indexSalt, saltBytes, 0, currentVersion.SaltSize);
|
||||||
|
Array.Copy(data, indexHash, hashBytes, 0, currentVersion.HashSize);
|
||||||
|
|
||||||
|
//Hash the current clearText with the parameters given via the data
|
||||||
|
var verificationHashBytes = KeyDerivation.Pbkdf2(clearText, saltBytes, currentVersion.KeyDerivation, iteration,
|
||||||
|
currentVersion.HashSize);
|
||||||
|
|
||||||
|
//Check if generated hashes are equal
|
||||||
|
return hashBytes.SequenceEqual(verificationHashBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies a given clear Text against a hash
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clearText">The clear text</param>
|
||||||
|
/// <param name="data">The hash</param>
|
||||||
|
/// <returns>Is the hash equal to the clear text?</returns>
|
||||||
|
public static bool Verify(string clearText, string data)
|
||||||
|
{
|
||||||
|
var dataBytes = Convert.FromBase64String(data);
|
||||||
|
return Verify(clearText, dataBytes);
|
||||||
|
}
|
||||||
|
}
|
11
Moonlight/App/Helpers/LogMigrator/LogMigrateProvider.cs
Normal file
11
Moonlight/App/Helpers/LogMigrator/LogMigrateProvider.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
namespace Moonlight.App.Helpers.LogMigrator;
|
||||||
|
|
||||||
|
public class LogMigrateProvider : ILoggerProvider
|
||||||
|
{
|
||||||
|
public void Dispose() {}
|
||||||
|
|
||||||
|
public ILogger CreateLogger(string categoryName)
|
||||||
|
{
|
||||||
|
return new MigrateLogger();
|
||||||
|
}
|
||||||
|
}
|
53
Moonlight/App/Helpers/LogMigrator/MigrateLogger.cs
Normal file
53
Moonlight/App/Helpers/LogMigrator/MigrateLogger.cs
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
namespace Moonlight.App.Helpers.LogMigrator;
|
||||||
|
|
||||||
|
public class MigrateLogger : ILogger
|
||||||
|
{
|
||||||
|
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
|
||||||
|
|
||||||
|
public bool IsEnabled(LogLevel logLevel)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
||||||
|
{
|
||||||
|
switch (logLevel)
|
||||||
|
{
|
||||||
|
case LogLevel.Critical:
|
||||||
|
Logger.Fatal(formatter(state, exception));
|
||||||
|
|
||||||
|
if(exception != null)
|
||||||
|
Logger.Fatal(exception);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LogLevel.Warning:
|
||||||
|
Logger.Warn(formatter(state, exception));
|
||||||
|
|
||||||
|
if(exception != null)
|
||||||
|
Logger.Warn(exception);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LogLevel.Debug:
|
||||||
|
Logger.Debug(formatter(state, exception));
|
||||||
|
|
||||||
|
if(exception != null)
|
||||||
|
Logger.Debug(exception);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LogLevel.Error:
|
||||||
|
Logger.Error(formatter(state, exception));
|
||||||
|
|
||||||
|
if(exception != null)
|
||||||
|
Logger.Error(exception);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LogLevel.Information:
|
||||||
|
Logger.Info(formatter(state, exception));
|
||||||
|
|
||||||
|
if(exception != null)
|
||||||
|
Logger.Info(exception);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
112
Moonlight/App/Helpers/Logger.cs
Normal file
112
Moonlight/App/Helpers/Logger.cs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Reflection;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public class Logger
|
||||||
|
{
|
||||||
|
#region String logger
|
||||||
|
public static void Verbose(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Verbose("{Message}", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Info(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Information("{Message}", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Debug(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Debug("{Message}", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Error(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Error("{Message}", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Warn(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Warning("{Message}", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fatal(string message, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Fatal("{Message}", message);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Exception method calls
|
||||||
|
|
||||||
|
public static void Verbose(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Verbose(exception, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Info(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Information(exception, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Debug(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Debug(exception, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Error(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Error(exception, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Warn(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Warning(exception, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Fatal(Exception exception, string channel = "default")
|
||||||
|
{
|
||||||
|
Log.ForContext("SourceContext", GetNameOfCallingClass())
|
||||||
|
.Fatal(exception, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private static string GetNameOfCallingClass(int skipFrames = 4)
|
||||||
|
{
|
||||||
|
string fullName;
|
||||||
|
Type declaringType;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
MethodBase method = new StackFrame(skipFrames, false).GetMethod();
|
||||||
|
declaringType = method.DeclaringType;
|
||||||
|
if (declaringType == null)
|
||||||
|
{
|
||||||
|
return method.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
skipFrames++;
|
||||||
|
if (declaringType.Name.Contains("<"))
|
||||||
|
fullName = declaringType.ReflectedType.Name;
|
||||||
|
else
|
||||||
|
fullName = declaringType.Name;
|
||||||
|
} while (declaringType.Module.Name.Equals("mscorlib.dll", StringComparison.OrdinalIgnoreCase) |
|
||||||
|
fullName.Contains("Logger"));
|
||||||
|
|
||||||
|
return fullName;
|
||||||
|
}
|
||||||
|
}
|
34
Moonlight/App/Helpers/PathBuilder.cs
Normal file
34
Moonlight/App/Helpers/PathBuilder.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public static class PathBuilder
|
||||||
|
{
|
||||||
|
public static string Dir(params string[] parts)
|
||||||
|
{
|
||||||
|
var res = "";
|
||||||
|
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
res += part + Path.DirectorySeparatorChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Replace(
|
||||||
|
$"{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}",
|
||||||
|
$"{Path.DirectorySeparatorChar}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string File(params string[] parts)
|
||||||
|
{
|
||||||
|
var res = "";
|
||||||
|
|
||||||
|
foreach (var part in parts)
|
||||||
|
{
|
||||||
|
res += part + (part == parts.Last() ? "" : Path.DirectorySeparatorChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Replace(
|
||||||
|
$"{Path.DirectorySeparatorChar}{Path.DirectorySeparatorChar}",
|
||||||
|
$"{Path.DirectorySeparatorChar}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
57
Moonlight/App/Helpers/PropBinder.cs
Normal file
57
Moonlight/App/Helpers/PropBinder.cs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Helpers;
|
||||||
|
|
||||||
|
public class PropBinder<T>
|
||||||
|
{
|
||||||
|
private PropertyInfo PropertyInfo;
|
||||||
|
private object DataObject;
|
||||||
|
|
||||||
|
public PropBinder(PropertyInfo propertyInfo, object dataObject)
|
||||||
|
{
|
||||||
|
PropertyInfo = propertyInfo;
|
||||||
|
DataObject = dataObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StringValue
|
||||||
|
{
|
||||||
|
get => (string)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IntValue
|
||||||
|
{
|
||||||
|
get => (int)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long LongValue
|
||||||
|
{
|
||||||
|
get => (long)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool BoolValue
|
||||||
|
{
|
||||||
|
get => (bool)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime DateTimeValue
|
||||||
|
{
|
||||||
|
get => (DateTime)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Class
|
||||||
|
{
|
||||||
|
get => (T)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double DoubleValue
|
||||||
|
{
|
||||||
|
get => (double)PropertyInfo.GetValue(DataObject)!;
|
||||||
|
set => PropertyInfo.SetValue(DataObject, value);
|
||||||
|
}
|
||||||
|
}
|
64
Moonlight/App/Http/Controllers/Api/Auth/ResetController.cs
Normal file
64
Moonlight/App/Http/Controllers/Api/Auth/ResetController.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
using Moonlight.App.Models.Enums;
|
||||||
|
using Moonlight.App.Repositories;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
using Moonlight.App.Services.Utils;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Http.Controllers.Api.Auth;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/auth/reset")]
|
||||||
|
public class ResetController : Controller
|
||||||
|
{
|
||||||
|
private readonly Repository<User> UserRepository;
|
||||||
|
private readonly IdentityService IdentityService;
|
||||||
|
private readonly JwtService JwtService;
|
||||||
|
|
||||||
|
public ResetController(Repository<User> userRepository, IdentityService identityService, JwtService jwtService)
|
||||||
|
{
|
||||||
|
UserRepository = userRepository;
|
||||||
|
IdentityService = identityService;
|
||||||
|
JwtService = jwtService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult> Get([FromQuery] string token)
|
||||||
|
{
|
||||||
|
// Validate token
|
||||||
|
|
||||||
|
if (!await JwtService.Validate(token))
|
||||||
|
return Redirect("/password-reset");
|
||||||
|
|
||||||
|
var data = await JwtService.Decode(token);
|
||||||
|
|
||||||
|
if (!data.ContainsKey("accountToReset"))
|
||||||
|
return Redirect("/password-reset");
|
||||||
|
|
||||||
|
var userId = int.Parse(data["accountToReset"]);
|
||||||
|
var user = UserRepository
|
||||||
|
.Get()
|
||||||
|
.FirstOrDefault(x => x.Id == userId);
|
||||||
|
|
||||||
|
// User may have been deleted, so we check here
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
return Redirect("/password-reset");
|
||||||
|
|
||||||
|
// In order to allow the user to get access to the change password screen
|
||||||
|
// we need to authenticate him so we can read his flags.
|
||||||
|
// That's why we are creating a session here
|
||||||
|
|
||||||
|
var sessionToken = await IdentityService.GenerateToken(user);
|
||||||
|
|
||||||
|
// Authenticate the current identity service instance in order to
|
||||||
|
// get access to the flags field.
|
||||||
|
await IdentityService.Authenticate(sessionToken);
|
||||||
|
IdentityService.Flags[UserFlag.PasswordPending] = true;
|
||||||
|
await IdentityService.SaveFlags();
|
||||||
|
|
||||||
|
// Make the user login so he can reach the change password screen
|
||||||
|
Response.Cookies.Append("token", sessionToken);
|
||||||
|
return Redirect("/");
|
||||||
|
}
|
||||||
|
}
|
51
Moonlight/App/Http/Controllers/Api/Auth/VerifyController.cs
Normal file
51
Moonlight/App/Http/Controllers/Api/Auth/VerifyController.cs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Moonlight.App.Helpers;
|
||||||
|
using Moonlight.App.Models.Enums;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
using Moonlight.App.Services.Utils;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Http.Controllers.Api.Auth;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/auth/verify")]
|
||||||
|
public class VerifyController : Controller
|
||||||
|
{
|
||||||
|
private readonly IdentityService IdentityService;
|
||||||
|
private readonly JwtService JwtService;
|
||||||
|
|
||||||
|
public VerifyController(IdentityService identityService, JwtService jwtService)
|
||||||
|
{
|
||||||
|
IdentityService = identityService;
|
||||||
|
JwtService = jwtService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult> Get([FromQuery] string token)
|
||||||
|
{
|
||||||
|
await IdentityService.Authenticate(Request);
|
||||||
|
|
||||||
|
if (!IdentityService.IsSignedIn)
|
||||||
|
return Redirect("/login");
|
||||||
|
|
||||||
|
if (!await JwtService.Validate(token))
|
||||||
|
return Redirect("/login");
|
||||||
|
|
||||||
|
var data = await JwtService.Decode(token);
|
||||||
|
|
||||||
|
if (!data.ContainsKey("mailToVerify"))
|
||||||
|
return Redirect("/login");
|
||||||
|
|
||||||
|
var mailToVerify = data["mailToVerify"];
|
||||||
|
|
||||||
|
if (mailToVerify != IdentityService.CurrentUser.Email)
|
||||||
|
{
|
||||||
|
Logger.Warn($"User {IdentityService.CurrentUser.Email} tried to mail verify {mailToVerify} via verify api endpoint", "security");
|
||||||
|
return Redirect("/login");
|
||||||
|
}
|
||||||
|
|
||||||
|
IdentityService.Flags[UserFlag.MailVerified] = true;
|
||||||
|
await IdentityService.SaveFlags();
|
||||||
|
|
||||||
|
return Redirect("/");
|
||||||
|
}
|
||||||
|
}
|
37
Moonlight/App/Http/Controllers/Api/BucketController.cs
Normal file
37
Moonlight/App/Http/Controllers/Api/BucketController.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Moonlight.App.Helpers;
|
||||||
|
using Moonlight.App.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Http.Controllers.Api;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/bucket")]
|
||||||
|
public class BucketController : Controller
|
||||||
|
{
|
||||||
|
private readonly BucketService BucketService;
|
||||||
|
|
||||||
|
public BucketController(BucketService bucketService)
|
||||||
|
{
|
||||||
|
BucketService = bucketService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{bucket}/{file}")]
|
||||||
|
public async Task<ActionResult> Get([FromRoute] string bucket, [FromRoute] string file) // TODO: Implement auth
|
||||||
|
{
|
||||||
|
if (bucket.Contains("..") || file.Contains(".."))
|
||||||
|
{
|
||||||
|
Logger.Warn($"Detected path transversal attack ({Request.HttpContext.Connection.RemoteIpAddress}).", "security");
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var stream = await BucketService.Pull(bucket, file);
|
||||||
|
return File(stream, MimeTypes.GetMimeType(file));
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
Moonlight/App/Http/Controllers/Api/WebsocketController.cs
Normal file
59
Moonlight/App/Http/Controllers/Api/WebsocketController.cs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Moonlight.App.Api;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Http.Controllers.Api;
|
||||||
|
|
||||||
|
public class WebsocketController : Controller
|
||||||
|
{
|
||||||
|
private readonly ApiManagementService ApiManagementService;
|
||||||
|
|
||||||
|
public WebsocketController(ApiManagementService apiManagementService)
|
||||||
|
{
|
||||||
|
ApiManagementService = apiManagementService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("/api/ws")]
|
||||||
|
public async Task Get()
|
||||||
|
{
|
||||||
|
if (HttpContext.WebSockets.IsWebSocketRequest)
|
||||||
|
{
|
||||||
|
using (var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync())
|
||||||
|
{
|
||||||
|
await Echo(webSocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Echo(WebSocket webSocket)
|
||||||
|
{
|
||||||
|
var context = new ApiUserContext(webSocket);
|
||||||
|
ApiManagementService.Contexts.Add(context);
|
||||||
|
|
||||||
|
await webSocket.SendAsync(Encoding.UTF8.GetBytes("Hello World"), WebSocketMessageType.Text,
|
||||||
|
true, CancellationToken.None);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (webSocket.State == WebSocketState.Open)
|
||||||
|
{
|
||||||
|
var buffer = new byte[1024 * 10];
|
||||||
|
var data = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
buffer = buffer[..data.Count];
|
||||||
|
|
||||||
|
await ApiManagementService.HandleRequest(context, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiManagementService.Contexts.Remove(context);
|
||||||
|
}
|
||||||
|
}
|
50
Moonlight/App/Models/Abstractions/FlagStorage.cs
Normal file
50
Moonlight/App/Models/Abstractions/FlagStorage.cs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
using Moonlight.App.Models.Enums;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Abstractions;
|
||||||
|
|
||||||
|
public class FlagStorage
|
||||||
|
{
|
||||||
|
private readonly List<string> FlagList;
|
||||||
|
|
||||||
|
public UserFlag[] Flags => FlagList
|
||||||
|
.Select(x => Enum.Parse(typeof(UserFlag), x))
|
||||||
|
.Select(x => (UserFlag)x)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
public string[] RawFlags => FlagList.ToArray();
|
||||||
|
public string RawFlagString => string.Join(";", FlagList);
|
||||||
|
|
||||||
|
public bool this[UserFlag flag]
|
||||||
|
{
|
||||||
|
get => Flags.Contains(flag);
|
||||||
|
set => Set(flag.ToString(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool this[string flagName]
|
||||||
|
{
|
||||||
|
get => FlagList.Contains(flagName);
|
||||||
|
set => Set(flagName, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FlagStorage(string flagString)
|
||||||
|
{
|
||||||
|
FlagList = flagString
|
||||||
|
.Split(";")
|
||||||
|
.Where(x => !string.IsNullOrEmpty(x))
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(string flagName, bool shouldAdd)
|
||||||
|
{
|
||||||
|
if (shouldAdd)
|
||||||
|
{
|
||||||
|
if(!FlagList.Contains(flagName))
|
||||||
|
FlagList.Add(flagName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (FlagList.Contains(flagName))
|
||||||
|
FlagList.Remove(flagName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
Moonlight/App/Models/Abstractions/PaymentGateway.cs
Normal file
8
Moonlight/App/Models/Abstractions/PaymentGateway.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Moonlight.App.Models.Abstractions;
|
||||||
|
|
||||||
|
public abstract class PaymentGateway
|
||||||
|
{
|
||||||
|
public abstract string Name { get; }
|
||||||
|
public abstract string Icon { get; }
|
||||||
|
public abstract Task<string> Start(double price);
|
||||||
|
}
|
34
Moonlight/App/Models/Abstractions/PermissionStorage.cs
Normal file
34
Moonlight/App/Models/Abstractions/PermissionStorage.cs
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
using Moonlight.App.Models.Enums;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Abstractions;
|
||||||
|
|
||||||
|
public class PermissionStorage
|
||||||
|
{
|
||||||
|
public readonly int PermissionInteger;
|
||||||
|
|
||||||
|
public PermissionStorage(int permissionInteger)
|
||||||
|
{
|
||||||
|
PermissionInteger = permissionInteger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Permission[] Permissions => GetPermissions();
|
||||||
|
|
||||||
|
public Permission[] GetPermissions()
|
||||||
|
{
|
||||||
|
return GetAllPermissions()
|
||||||
|
.Where(x => (int)x <= PermissionInteger)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Permission[] GetAllPermissions()
|
||||||
|
{
|
||||||
|
return Enum.GetValues<Permission>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Permission GetFromInteger(int id)
|
||||||
|
{
|
||||||
|
return GetAllPermissions().First(x => (int)x == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool this[Permission permission] => Permissions.Contains(permission);
|
||||||
|
}
|
10
Moonlight/App/Models/Abstractions/ServiceActions.cs
Normal file
10
Moonlight/App/Models/Abstractions/ServiceActions.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
using Moonlight.App.Database.Entities.Store;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Abstractions;
|
||||||
|
|
||||||
|
public abstract class ServiceActions
|
||||||
|
{
|
||||||
|
public abstract Task Create(IServiceProvider provider, Service service);
|
||||||
|
public abstract Task Update(IServiceProvider provider, Service service);
|
||||||
|
public abstract Task Delete(IServiceProvider provider, Service service);
|
||||||
|
}
|
12
Moonlight/App/Models/Abstractions/Session.cs
Normal file
12
Moonlight/App/Models/Abstractions/Session.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Abstractions;
|
||||||
|
|
||||||
|
public class Session
|
||||||
|
{
|
||||||
|
public string Ip { get; set; } = "N/A";
|
||||||
|
public string Url { get; set; } = "N/A";
|
||||||
|
public User? User { get; set; }
|
||||||
|
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||||
|
public DateTime UpdatedAt { get; set; } = DateTime.UtcNow; // To remove inactive sessions
|
||||||
|
}
|
8
Moonlight/App/Models/Abstractions/Subscriber.cs
Normal file
8
Moonlight/App/Models/Abstractions/Subscriber.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Moonlight.App.Models.Abstractions;
|
||||||
|
|
||||||
|
public class Subscriber
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public object Action { get; set; }
|
||||||
|
public object Handle { get; set; }
|
||||||
|
}
|
16
Moonlight/App/Models/Enums/Permission.cs
Normal file
16
Moonlight/App/Models/Enums/Permission.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
namespace Moonlight.App.Models.Enums;
|
||||||
|
|
||||||
|
public enum Permission
|
||||||
|
{
|
||||||
|
Default = 0,
|
||||||
|
AdminMenu = 999,
|
||||||
|
AdminOverview = 1000,
|
||||||
|
AdminUsers = 1001,
|
||||||
|
AdminSessions = 1002,
|
||||||
|
AdminUsersEdit = 1003,
|
||||||
|
AdminTickets = 1004,
|
||||||
|
AdminCommunity = 1030,
|
||||||
|
AdminStore = 1900,
|
||||||
|
AdminViewExceptions = 1999,
|
||||||
|
AdminRoot = 2000
|
||||||
|
}
|
8
Moonlight/App/Models/Enums/UserFlag.cs
Normal file
8
Moonlight/App/Models/Enums/UserFlag.cs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Moonlight.App.Models.Enums;
|
||||||
|
|
||||||
|
public enum UserFlag
|
||||||
|
{
|
||||||
|
MailVerified,
|
||||||
|
PasswordPending,
|
||||||
|
TotpEnabled
|
||||||
|
}
|
12
Moonlight/App/Models/Forms/Admin/Community/AddWordFilter.cs
Normal file
12
Moonlight/App/Models/Forms/Admin/Community/AddWordFilter.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms.Admin.Community;
|
||||||
|
|
||||||
|
public class AddWordFilter
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "You need to specify a filter")]
|
||||||
|
[Description(
|
||||||
|
"This filters all posts and comments created using this regex. If any match is found it will block the action")]
|
||||||
|
public string Filter { get; set; } = "";
|
||||||
|
}
|
12
Moonlight/App/Models/Forms/Admin/Community/EditWordFilter.cs
Normal file
12
Moonlight/App/Models/Forms/Admin/Community/EditWordFilter.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms.Admin.Community;
|
||||||
|
|
||||||
|
public class EditWordFilter
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "You need to specify a filter")]
|
||||||
|
[Description(
|
||||||
|
"This filters all posts and comments created using this regex. If any match is found it will block the action")]
|
||||||
|
public string Filter { get; set; } = "";
|
||||||
|
}
|
16
Moonlight/App/Models/Forms/Admin/Store/AddCouponForm.cs
Normal file
16
Moonlight/App/Models/Forms/Admin/Store/AddCouponForm.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms.Admin.Store;
|
||||||
|
|
||||||
|
public class AddCouponForm
|
||||||
|
{
|
||||||
|
[MinLength(5, ErrorMessage = "The code needs to be longer than 4")]
|
||||||
|
[MaxLength(15, ErrorMessage = "The code should not be longer than 15 characters")]
|
||||||
|
public string Code { get; set; } = "";
|
||||||
|
|
||||||
|
[Range(1, 99, ErrorMessage = "The percent needs to be between 1 and 99")]
|
||||||
|
public int Percent { get; set; }
|
||||||
|
|
||||||
|
[Range(0, int.MaxValue, ErrorMessage = "The amount needs to be equals or greater than 0")]
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
16
Moonlight/App/Models/Forms/Admin/Store/AddGiftCodeForm.cs
Normal file
16
Moonlight/App/Models/Forms/Admin/Store/AddGiftCodeForm.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms.Admin.Store;
|
||||||
|
|
||||||
|
public class AddGiftCodeForm
|
||||||
|
{
|
||||||
|
[MinLength(5, ErrorMessage = "The code needs to be longer than 4")]
|
||||||
|
[MaxLength(15, ErrorMessage = "The code should not be longer than 15 characters")]
|
||||||
|
public string Code { get; set; } = "";
|
||||||
|
|
||||||
|
[Range(0, int.MaxValue, ErrorMessage = "The value needs to be equals or greater than 0")]
|
||||||
|
public double Value { get; set; }
|
||||||
|
|
||||||
|
[Range(0, int.MaxValue, ErrorMessage = "The amount needs to be equals or greater than 0")]
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
16
Moonlight/App/Models/Forms/Admin/Store/EditCouponForm.cs
Normal file
16
Moonlight/App/Models/Forms/Admin/Store/EditCouponForm.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms.Admin.Store;
|
||||||
|
|
||||||
|
public class EditCouponForm
|
||||||
|
{
|
||||||
|
[MinLength(5, ErrorMessage = "The code needs to be longer than 4")]
|
||||||
|
[MaxLength(15, ErrorMessage = "The code should not be longer than 15 characters")]
|
||||||
|
public string Code { get; set; } = "";
|
||||||
|
|
||||||
|
[Range(1, 99, ErrorMessage = "The percent needs to be between 1 and 99")]
|
||||||
|
public int Percent { get; set; }
|
||||||
|
|
||||||
|
[Range(0, int.MaxValue, ErrorMessage = "The amount needs to be equals or greater than 0")]
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
16
Moonlight/App/Models/Forms/Admin/Store/EditGiftCodeForm.cs
Normal file
16
Moonlight/App/Models/Forms/Admin/Store/EditGiftCodeForm.cs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms.Admin.Store;
|
||||||
|
|
||||||
|
public class EditGiftCodeForm
|
||||||
|
{
|
||||||
|
[MinLength(5, ErrorMessage = "The code needs to be longer than 4")]
|
||||||
|
[MaxLength(15, ErrorMessage = "The code should not be longer than 15 characters")]
|
||||||
|
public string Code { get; set; } = "";
|
||||||
|
|
||||||
|
[Range(0, int.MaxValue, ErrorMessage = "The value needs to be equals or greater than 0")]
|
||||||
|
public double Value { get; set; }
|
||||||
|
|
||||||
|
[Range(0, int.MaxValue, ErrorMessage = "The amount needs to be equals or greater than 0")]
|
||||||
|
public int Amount { get; set; }
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue