This commit is contained in:
maliming 2019-07-16 11:00:55 +08:00
Родитель da633563bb
Коммит e341deaaf4
215 изменённых файлов: 27657 добавлений и 0 удалений

57
GraphQLDemo/README.md Normal file
Просмотреть файл

@ -0,0 +1,57 @@
# The example is based on the following article
See: https://medium.com/volosoft/building-graphql-apis-with-asp-net-core-419b32a5305b
## Get Started
* Modify the database connection string as needed, then perform the migration.
* Launch the Hotel.Web.Host project, browse http://localhost:21021/ui/playground
* Enter the expression to execute the query.
Input:
```
query TestQuery {
reservations (roomAllowedSmoking:false, roomStatus: AVAILABLE){
id
checkinDate
checkoutDate
guest {
id
name
registerDate
}
room {
id
name
number
allowedSmoking
status
}
}
}
```
Output:
```
{
"data": {
"reservations": [
{
"id": 1,
"checkinDate": "2019-07-14",
"checkoutDate": "2019-07-19",
"guest": null,
"room": null
},
{
"id": 2,
"checkinDate": "2019-07-15",
"checkoutDate": "2019-07-20",
"guest": null,
"room": null
}
]
}
}
```
For more details, please refer to the above article and the documentation of graphql.

252
GraphQLDemo/aspnet-core/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,252 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml

Просмотреть файл

@ -0,0 +1,71 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.9
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F10AA149-2626-486E-85BB-9CD5365F3016}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotel.Core", "src\Hotel.Core\Hotel.Core.csproj", "{0FA75A5B-AB83-4FD0-B545-279774C01E87}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotel.Application", "src\Hotel.Application\Hotel.Application.csproj", "{3870C648-4AEA-4B85-BA3F-F2F63B96136A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotel.Tests", "test\Hotel.Tests\Hotel.Tests.csproj", "{0D4C5D00-C144-4213-A007-4B8944113AB1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotel.Migrator", "src\Hotel.Migrator\Hotel.Migrator.csproj", "{880B3591-E057-46FE-B525-10BD83828B93}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotel.Web.Host", "src\Hotel.Web.Host\Hotel.Web.Host.csproj", "{38E184BD-E874-4633-A947-AED4FDB73F40}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hotel.Web.Core", "src\Hotel.Web.Core\Hotel.Web.Core.csproj", "{22CFE0D2-8DCA-42D7-AD7D-784C3862493F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hotel.EntityFrameworkCore", "src\Hotel.EntityFrameworkCore\Hotel.EntityFrameworkCore.csproj", "{E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0FA75A5B-AB83-4FD0-B545-279774C01E87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0FA75A5B-AB83-4FD0-B545-279774C01E87}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0FA75A5B-AB83-4FD0-B545-279774C01E87}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0FA75A5B-AB83-4FD0-B545-279774C01E87}.Release|Any CPU.Build.0 = Release|Any CPU
{3870C648-4AEA-4B85-BA3F-F2F63B96136A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3870C648-4AEA-4B85-BA3F-F2F63B96136A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3870C648-4AEA-4B85-BA3F-F2F63B96136A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3870C648-4AEA-4B85-BA3F-F2F63B96136A}.Release|Any CPU.Build.0 = Release|Any CPU
{0D4C5D00-C144-4213-A007-4B8944113AB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D4C5D00-C144-4213-A007-4B8944113AB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D4C5D00-C144-4213-A007-4B8944113AB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D4C5D00-C144-4213-A007-4B8944113AB1}.Release|Any CPU.Build.0 = Release|Any CPU
{880B3591-E057-46FE-B525-10BD83828B93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{880B3591-E057-46FE-B525-10BD83828B93}.Debug|Any CPU.Build.0 = Debug|Any CPU
{880B3591-E057-46FE-B525-10BD83828B93}.Release|Any CPU.ActiveCfg = Release|Any CPU
{880B3591-E057-46FE-B525-10BD83828B93}.Release|Any CPU.Build.0 = Release|Any CPU
{38E184BD-E874-4633-A947-AED4FDB73F40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{38E184BD-E874-4633-A947-AED4FDB73F40}.Debug|Any CPU.Build.0 = Debug|Any CPU
{38E184BD-E874-4633-A947-AED4FDB73F40}.Release|Any CPU.ActiveCfg = Release|Any CPU
{38E184BD-E874-4633-A947-AED4FDB73F40}.Release|Any CPU.Build.0 = Release|Any CPU
{22CFE0D2-8DCA-42D7-AD7D-784C3862493F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{22CFE0D2-8DCA-42D7-AD7D-784C3862493F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22CFE0D2-8DCA-42D7-AD7D-784C3862493F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22CFE0D2-8DCA-42D7-AD7D-784C3862493F}.Release|Any CPU.Build.0 = Release|Any CPU
{E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0580562-F8F2-4EBB-B07A-ABFC6F2C314F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{0FA75A5B-AB83-4FD0-B545-279774C01E87} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}
{3870C648-4AEA-4B85-BA3F-F2F63B96136A} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}
{0D4C5D00-C144-4213-A007-4B8944113AB1} = {F10AA149-2626-486E-85BB-9CD5365F3016}
{880B3591-E057-46FE-B525-10BD83828B93} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}
{38E184BD-E874-4633-A947-AED4FDB73F40} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}
{22CFE0D2-8DCA-42D7-AD7D-784C3862493F} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}
{E0580562-F8F2-4EBB-B07A-ABFC6F2C314F} = {AFAA0841-BD93-466F-B8F4-FB4EEC86F1FC}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -0,0 +1,57 @@
# COMMON PATHS
$buildFolder = (Get-Item -Path "./" -Verbose).FullName
$slnFolder = Join-Path $buildFolder "../"
$outputFolder = Join-Path $buildFolder "outputs"
$webHostFolder = Join-Path $slnFolder "src/Hotel.Web.Host"
$ngFolder = Join-Path $buildFolder "../../angular"
## CLEAR ######################################################################
Remove-Item $outputFolder -Force -Recurse -ErrorAction Ignore
New-Item -Path $outputFolder -ItemType Directory
## RESTORE NUGET PACKAGES #####################################################
Set-Location $slnFolder
dotnet restore
## PUBLISH WEB HOST PROJECT ###################################################
Set-Location $webHostFolder
dotnet publish --output (Join-Path $outputFolder "Host")
## PUBLISH ANGULAR UI PROJECT #################################################
Set-Location $ngFolder
& yarn
& ng build -prod
Copy-Item (Join-Path $ngFolder "dist") (Join-Path $outputFolder "ng") -Recurse
Copy-Item (Join-Path $ngFolder "Dockerfile") (Join-Path $outputFolder "ng")
# Change UI configuration
$ngConfigPath = Join-Path $outputFolder "ng/assets/appconfig.json"
(Get-Content $ngConfigPath) -replace "21021", "9901" | Set-Content $ngConfigPath
(Get-Content $ngConfigPath) -replace "4200", "9902" | Set-Content $ngConfigPath
## CREATE DOCKER IMAGES #######################################################
# Host
Set-Location (Join-Path $outputFolder "Host")
docker rmi abp/host -f
docker build -t abp/host .
# Angular UI
Set-Location (Join-Path $outputFolder "ng")
docker rmi abp/ng -f
docker build -t abp/ng .
## DOCKER COMPOSE FILES #######################################################
Copy-Item (Join-Path $slnFolder "docker/ng/*.*") $outputFolder
## FINALIZE ###################################################################
Set-Location $outputFolder

Просмотреть файл

@ -0,0 +1,17 @@
version: '2'
services:
abp_host:
image: abp/host
environment:
- ASPNETCORE_ENVIRONMENT=Staging
ports:
- "9901:80"
volumes:
- "./Host-Logs:/app/App_Data/Logs"
abp_ng:
image: abp/ng
ports:
- "9902:80"

Просмотреть файл

@ -0,0 +1 @@
docker-compose down -v --rmi local

Просмотреть файл

@ -0,0 +1 @@
docker-compose up -d

Просмотреть файл

@ -0,0 +1,10 @@
namespace Hotel
{
public class AppConsts
{
/// <summary>
/// Default pass phrase for SimpleStringCipher decrypt/encrypt operations
/// </summary>
public const string DefaultPassPhrase = "gsKxGZ012HLL3MI5";
}
}

Просмотреть файл

@ -0,0 +1,64 @@
using System;
using Abp;
using Abp.Authorization;
using Abp.Dependency;
using Abp.UI;
namespace Hotel.Authorization
{
public class AbpLoginResultTypeHelper : AbpServiceBase, ITransientDependency
{
public AbpLoginResultTypeHelper()
{
LocalizationSourceName = HotelConsts.LocalizationSourceName;
}
public Exception CreateExceptionForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName)
{
switch (result)
{
case AbpLoginResultType.Success:
return new Exception("Don't call this method with a success result!");
case AbpLoginResultType.InvalidUserNameOrEmailAddress:
case AbpLoginResultType.InvalidPassword:
return new UserFriendlyException(L("LoginFailed"), L("InvalidUserNameOrPassword"));
case AbpLoginResultType.InvalidTenancyName:
return new UserFriendlyException(L("LoginFailed"), L("ThereIsNoTenantDefinedWithName{0}", tenancyName));
case AbpLoginResultType.TenantIsNotActive:
return new UserFriendlyException(L("LoginFailed"), L("TenantIsNotActive", tenancyName));
case AbpLoginResultType.UserIsNotActive:
return new UserFriendlyException(L("LoginFailed"), L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress));
case AbpLoginResultType.UserEmailIsNotConfirmed:
return new UserFriendlyException(L("LoginFailed"), L("UserEmailIsNotConfirmedAndCanNotLogin"));
case AbpLoginResultType.LockedOut:
return new UserFriendlyException(L("LoginFailed"), L("UserLockedOutMessage"));
default: // Can not fall to default actually. But other result types can be added in the future and we may forget to handle it
Logger.Warn("Unhandled login fail reason: " + result);
return new UserFriendlyException(L("LoginFailed"));
}
}
public string CreateLocalizedMessageForFailedLoginAttempt(AbpLoginResultType result, string usernameOrEmailAddress, string tenancyName)
{
switch (result)
{
case AbpLoginResultType.Success:
throw new Exception("Don't call this method with a success result!");
case AbpLoginResultType.InvalidUserNameOrEmailAddress:
case AbpLoginResultType.InvalidPassword:
return L("InvalidUserNameOrPassword");
case AbpLoginResultType.InvalidTenancyName:
return L("ThereIsNoTenantDefinedWithName{0}", tenancyName);
case AbpLoginResultType.TenantIsNotActive:
return L("TenantIsNotActive", tenancyName);
case AbpLoginResultType.UserIsNotActive:
return L("UserIsNotActiveAndCanNotLogin", usernameOrEmailAddress);
case AbpLoginResultType.UserEmailIsNotConfirmed:
return L("UserEmailIsNotConfirmedAndCanNotLogin");
default: // Can not fall to default actually. But other result types can be added in the future and we may forget to handle it
Logger.Warn("Unhandled login fail reason: " + result);
return L("LoginFailed");
}
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
using System.Threading.Tasks;
using Abp.Configuration;
using Abp.Zero.Configuration;
using Hotel.Authorization.Accounts.Dto;
using Hotel.Authorization.Users;
namespace Hotel.Authorization.Accounts
{
public class AccountAppService : HotelAppServiceBase, IAccountAppService
{
// from: http://regexlib.com/REDetails.aspx?regexp_id=1923
public const string PasswordRegex = "(?=^.{8,}$)(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\\s)[0-9a-zA-Z!@#$%^&*()]*$";
private readonly UserRegistrationManager _userRegistrationManager;
public AccountAppService(
UserRegistrationManager userRegistrationManager)
{
_userRegistrationManager = userRegistrationManager;
}
public async Task<IsTenantAvailableOutput> IsTenantAvailable(IsTenantAvailableInput input)
{
var tenant = await TenantManager.FindByTenancyNameAsync(input.TenancyName);
if (tenant == null)
{
return new IsTenantAvailableOutput(TenantAvailabilityState.NotFound);
}
if (!tenant.IsActive)
{
return new IsTenantAvailableOutput(TenantAvailabilityState.InActive);
}
return new IsTenantAvailableOutput(TenantAvailabilityState.Available, tenant.Id);
}
public async Task<RegisterOutput> Register(RegisterInput input)
{
var user = await _userRegistrationManager.RegisterAsync(
input.Name,
input.Surname,
input.EmailAddress,
input.UserName,
input.Password,
true // Assumed email address is always confirmed. Change this if you want to implement email confirmation.
);
var isEmailConfirmationRequiredForLogin = await SettingManager.GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.IsEmailConfirmationRequiredForLogin);
return new RegisterOutput
{
CanLogin = user.IsActive && (user.IsEmailConfirmed || !isEmailConfirmationRequiredForLogin)
};
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations;
using Abp.MultiTenancy;
namespace Hotel.Authorization.Accounts.Dto
{
public class IsTenantAvailableInput
{
[Required]
[StringLength(AbpTenantBase.MaxTenancyNameLength)]
public string TenancyName { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,19 @@
namespace Hotel.Authorization.Accounts.Dto
{
public class IsTenantAvailableOutput
{
public TenantAvailabilityState State { get; set; }
public int? TenantId { get; set; }
public IsTenantAvailableOutput()
{
}
public IsTenantAvailableOutput(TenantAvailabilityState state, int? tenantId = null)
{
State = state;
TenantId = tenantId;
}
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Abp.Auditing;
using Abp.Authorization.Users;
using Abp.Extensions;
using Hotel.Validation;
namespace Hotel.Authorization.Accounts.Dto
{
public class RegisterInput : IValidatableObject
{
[Required]
[StringLength(AbpUserBase.MaxNameLength)]
public string Name { get; set; }
[Required]
[StringLength(AbpUserBase.MaxSurnameLength)]
public string Surname { get; set; }
[Required]
[StringLength(AbpUserBase.MaxUserNameLength)]
public string UserName { get; set; }
[Required]
[EmailAddress]
[StringLength(AbpUserBase.MaxEmailAddressLength)]
public string EmailAddress { get; set; }
[Required]
[StringLength(AbpUserBase.MaxPlainPasswordLength)]
[DisableAuditing]
public string Password { get; set; }
[DisableAuditing]
public string CaptchaResponse { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!UserName.IsNullOrEmpty())
{
if (!UserName.Equals(EmailAddress) && ValidationHelper.IsEmail(UserName))
{
yield return new ValidationResult("Username cannot be an email address unless it's the same as your email address!");
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
namespace Hotel.Authorization.Accounts.Dto
{
public class RegisterOutput
{
public bool CanLogin { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,9 @@
namespace Hotel.Authorization.Accounts.Dto
{
public enum TenantAvailabilityState
{
Available = 1,
InActive,
NotFound
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using System.Threading.Tasks;
using Abp.Application.Services;
using Hotel.Authorization.Accounts.Dto;
namespace Hotel.Authorization.Accounts
{
public interface IAccountAppService : IApplicationService
{
Task<IsTenantAvailableOutput> IsTenantAvailable(IsTenantAvailableInput input);
Task<RegisterOutput> Register(RegisterInput input);
}
}

Просмотреть файл

@ -0,0 +1,16 @@
using System.Threading.Tasks;
using Abp.Authorization;
using Abp.Runtime.Session;
using Hotel.Configuration.Dto;
namespace Hotel.Configuration
{
[AbpAuthorize]
public class ConfigurationAppService : HotelAppServiceBase, IConfigurationAppService
{
public async Task ChangeUiTheme(ChangeUiThemeInput input)
{
await SettingManager.ChangeSettingForUserAsync(AbpSession.ToUserIdentifier(), AppSettingNames.UiTheme, input.Theme);
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
using System.ComponentModel.DataAnnotations;
namespace Hotel.Configuration.Dto
{
public class ChangeUiThemeInput
{
[Required]
[StringLength(32)]
public string Theme { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,10 @@
using System.Threading.Tasks;
using Hotel.Configuration.Dto;
namespace Hotel.Configuration
{
public interface IConfigurationAppService
{
Task ChangeUiTheme(ChangeUiThemeInput input);
}
}

Просмотреть файл

@ -0,0 +1,14 @@
namespace Hotel.Configuration.Ui
{
public class UiThemeInfo
{
public string Name { get; }
public string CssClass { get; }
public UiThemeInfo(string name, string cssClass)
{
Name = name;
CssClass = cssClass;
}
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using System.Collections.Generic;
namespace Hotel.Configuration.Ui
{
public static class UiThemes
{
public static List<UiThemeInfo> All { get; }
static UiThemes()
{
All = new List<UiThemeInfo>
{
new UiThemeInfo("Red", "red"),
new UiThemeInfo("Pink", "pink"),
new UiThemeInfo("Purple", "purple"),
new UiThemeInfo("Deep Purple", "deep-purple"),
new UiThemeInfo("Indigo", "indigo"),
new UiThemeInfo("Blue", "blue"),
new UiThemeInfo("Light Blue", "light-blue"),
new UiThemeInfo("Cyan", "cyan"),
new UiThemeInfo("Teal", "teal"),
new UiThemeInfo("Green", "green"),
new UiThemeInfo("Light Green", "light-green"),
new UiThemeInfo("Lime", "lime"),
new UiThemeInfo("Yellow", "yellow"),
new UiThemeInfo("Amber", "amber"),
new UiThemeInfo("Orange", "orange"),
new UiThemeInfo("Deep Orange", "deep-orange"),
new UiThemeInfo("Brown", "brown"),
new UiThemeInfo("Grey", "grey"),
new UiThemeInfo("Blue Grey", "blue-grey"),
new UiThemeInfo("Black", "black")
};
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<VersionPrefix>1.0.0.0</VersionPrefix>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<AssemblyName>Hotel.Application</AssemblyName>
<PackageId>Hotel.Application</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace>Hotel</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Hotel.Core\Hotel.Core.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,47 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Abp.Application.Services;
using Abp.IdentityFramework;
using Abp.Runtime.Session;
using Hotel.Authorization.Users;
using Hotel.MultiTenancy;
namespace Hotel
{
/// <summary>
/// Derive your application services from this class.
/// </summary>
public abstract class HotelAppServiceBase : ApplicationService
{
public TenantManager TenantManager { get; set; }
public UserManager UserManager { get; set; }
protected HotelAppServiceBase()
{
LocalizationSourceName = HotelConsts.LocalizationSourceName;
}
protected virtual Task<User> GetCurrentUserAsync()
{
var user = UserManager.FindByIdAsync(AbpSession.GetUserId().ToString());
if (user == null)
{
throw new Exception("There is no current user!");
}
return user;
}
protected virtual Task<Tenant> GetCurrentTenantAsync()
{
return TenantManager.GetByIdAsync(AbpSession.GetTenantId());
}
protected virtual void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
using Abp.AutoMapper;
using Abp.Modules;
using Abp.Reflection.Extensions;
using Hotel.Authorization;
namespace Hotel
{
[DependsOn(
typeof(HotelCoreModule),
typeof(AbpAutoMapperModule))]
public class HotelApplicationModule : AbpModule
{
public override void PreInitialize()
{
Configuration.Authorization.Providers.Add<HotelAuthorizationProvider>();
}
public override void Initialize()
{
var thisAssembly = typeof(HotelApplicationModule).GetAssembly();
IocManager.RegisterAssemblyByConvention(thisAssembly);
Configuration.Modules.AbpAutoMapper().Configurators.Add(
// Scan the assembly for classes which inherit from AutoMapper.Profile
cfg => cfg.AddProfiles(thisAssembly)
);
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
using System.ComponentModel.DataAnnotations;
using Abp.Authorization.Users;
using Abp.AutoMapper;
using Abp.MultiTenancy;
namespace Hotel.MultiTenancy.Dto
{
[AutoMapTo(typeof(Tenant))]
public class CreateTenantDto
{
[Required]
[StringLength(AbpTenantBase.MaxTenancyNameLength)]
[RegularExpression(AbpTenantBase.TenancyNameRegex)]
public string TenancyName { get; set; }
[Required]
[StringLength(AbpTenantBase.MaxNameLength)]
public string Name { get; set; }
[Required]
[StringLength(AbpUserBase.MaxEmailAddressLength)]
public string AdminEmailAddress { get; set; }
[StringLength(AbpTenantBase.MaxConnectionStringLength)]
public string ConnectionString { get; set; }
public bool IsActive {get; set;}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
using Abp.Application.Services.Dto;
namespace Hotel.MultiTenancy.Dto
{
public class PagedTenantResultRequestDto : PagedResultRequestDto
{
public string Keyword { get; set; }
public bool? IsActive { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.MultiTenancy;
namespace Hotel.MultiTenancy.Dto
{
[AutoMapFrom(typeof(Tenant))]
public class TenantDto : EntityDto
{
[Required]
[StringLength(AbpTenantBase.MaxTenancyNameLength)]
[RegularExpression(AbpTenantBase.TenancyNameRegex)]
public string TenancyName { get; set; }
[Required]
[StringLength(AbpTenantBase.MaxNameLength)]
public string Name { get; set; }
public bool IsActive {get; set;}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Hotel.MultiTenancy.Dto;
namespace Hotel.MultiTenancy
{
public interface ITenantAppService : IAsyncCrudAppService<TenantDto, int, PagedTenantResultRequestDto, CreateTenantDto, TenantDto>
{
}
}

Просмотреть файл

@ -0,0 +1,123 @@
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.IdentityFramework;
using Abp.Linq.Extensions;
using Abp.MultiTenancy;
using Abp.Runtime.Security;
using Hotel.Authorization;
using Hotel.Authorization.Roles;
using Hotel.Authorization.Users;
using Hotel.Editions;
using Hotel.MultiTenancy.Dto;
using Microsoft.AspNetCore.Identity;
namespace Hotel.MultiTenancy
{
[AbpAuthorize(PermissionNames.Pages_Tenants)]
public class TenantAppService : AsyncCrudAppService<Tenant, TenantDto, int, PagedTenantResultRequestDto, CreateTenantDto, TenantDto>, ITenantAppService
{
private readonly TenantManager _tenantManager;
private readonly EditionManager _editionManager;
private readonly UserManager _userManager;
private readonly RoleManager _roleManager;
private readonly IAbpZeroDbMigrator _abpZeroDbMigrator;
public TenantAppService(
IRepository<Tenant, int> repository,
TenantManager tenantManager,
EditionManager editionManager,
UserManager userManager,
RoleManager roleManager,
IAbpZeroDbMigrator abpZeroDbMigrator)
: base(repository)
{
_tenantManager = tenantManager;
_editionManager = editionManager;
_userManager = userManager;
_roleManager = roleManager;
_abpZeroDbMigrator = abpZeroDbMigrator;
}
public override async Task<TenantDto> Create(CreateTenantDto input)
{
CheckCreatePermission();
// Create tenant
var tenant = ObjectMapper.Map<Tenant>(input);
tenant.ConnectionString = input.ConnectionString.IsNullOrEmpty()
? null
: SimpleStringCipher.Instance.Encrypt(input.ConnectionString);
var defaultEdition = await _editionManager.FindByNameAsync(EditionManager.DefaultEditionName);
if (defaultEdition != null)
{
tenant.EditionId = defaultEdition.Id;
}
await _tenantManager.CreateAsync(tenant);
await CurrentUnitOfWork.SaveChangesAsync(); // To get new tenant's id.
// Create tenant database
_abpZeroDbMigrator.CreateOrMigrateForTenant(tenant);
// We are working entities of new tenant, so changing tenant filter
using (CurrentUnitOfWork.SetTenantId(tenant.Id))
{
// Create static roles for new tenant
CheckErrors(await _roleManager.CreateStaticRoles(tenant.Id));
await CurrentUnitOfWork.SaveChangesAsync(); // To get static role ids
// Grant all permissions to admin role
var adminRole = _roleManager.Roles.Single(r => r.Name == StaticRoleNames.Tenants.Admin);
await _roleManager.GrantAllPermissionsAsync(adminRole);
// Create admin user for the tenant
var adminUser = User.CreateTenantAdminUser(tenant.Id, input.AdminEmailAddress);
await _userManager.InitializeOptionsAsync(tenant.Id);
CheckErrors(await _userManager.CreateAsync(adminUser, User.DefaultPassword));
await CurrentUnitOfWork.SaveChangesAsync(); // To get admin user's id
// Assign admin user to role!
CheckErrors(await _userManager.AddToRoleAsync(adminUser, adminRole.Name));
await CurrentUnitOfWork.SaveChangesAsync();
}
return MapToEntityDto(tenant);
}
protected override IQueryable<Tenant> CreateFilteredQuery(PagedTenantResultRequestDto input)
{
return Repository.GetAll()
.WhereIf(!input.Keyword.IsNullOrWhiteSpace(), x => x.TenancyName.Contains(input.Keyword) || x.Name.Contains(input.Keyword))
.WhereIf(input.IsActive.HasValue, x => x.IsActive == input.IsActive);
}
protected override void MapToEntity(TenantDto updateInput, Tenant entity)
{
// Manually mapped since TenantDto contains non-editable properties too.
entity.Name = updateInput.Name;
entity.TenancyName = updateInput.TenancyName;
entity.IsActive = updateInput.IsActive;
}
public override async Task Delete(EntityDto<int> input)
{
CheckDeletePermission();
var tenant = await _tenantManager.GetByIdAsync(input.Id);
await _tenantManager.DeleteAsync(tenant);
}
private void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
}
}

Просмотреть файл

@ -0,0 +1,311 @@
using System;
namespace Hotel.Net.MimeTypes
{
/* Copied from:
* http://stackoverflow.com/questions/10362140/asp-mvc-are-there-any-constants-for-the-default-content-types */
/// <summary>
/// Common mime types.
/// </summary>
public static class MimeTypeNames
{
///<summary>Used to denote the encoding necessary for files containing JavaScript source code. The alternative MIME type for this file type is text/javascript.</summary>
public const string ApplicationXJavascript = "application/x-javascript";
///<summary>24bit Linear PCM audio at 8-48kHz, 1-N channels; Defined in RFC 3190</summary>
public const string AudioL24 = "audio/L24";
///<summary>Adobe Flash files for example with the extension .swf</summary>
public const string ApplicationXShockwaveFlash = "application/x-shockwave-flash";
///<summary>Arbitrary binary data.[5] Generally speaking this type identifies files that are not associated with a specific application. Contrary to past assumptions by software packages such as Apache this is not a type that should be applied to unknown files. In such a case, a server or application should not indicate a content type, as it may be incorrect, but rather, should omit the type in order to allow the recipient to guess the type.[6]</summary>
public const string ApplicationOctetStream = "application/octet-stream";
///<summary>Atom feeds</summary>
public const string ApplicationAtomXml = "application/atom+xml";
///<summary>Cascading Style Sheets; Defined in RFC 2318</summary>
public const string TextCss = "text/css";
///<summary>commands; subtype resident in Gecko browsers like Firefox 3.5</summary>
public const string TextCmd = "text/cmd";
///<summary>Comma-separated values; Defined in RFC 4180</summary>
public const string TextCsv = "text/csv";
///<summary>deb (file format), a software package format used by the Debian project</summary>
public const string ApplicationXDeb = "application/x-deb";
///<summary>Defined in RFC 1847</summary>
public const string MultipartEncrypted = "multipart/encrypted";
///<summary>Defined in RFC 1847</summary>
public const string MultipartSigned = "multipart/signed";
///<summary>Defined in RFC 2616</summary>
public const string MessageHttp = "message/http";
///<summary>Defined in RFC 4735</summary>
public const string ModelExample = "model/example";
///<summary>device-independent document in DVI format</summary>
public const string ApplicationXDvi = "application/x-dvi";
///<summary>DTD files; Defined by RFC 3023</summary>
public const string ApplicationXmlDtd = "application/xml-dtd";
///<summary>ECMAScript/JavaScript; Defined in RFC 4329 (equivalent to application/ecmascript but with looser processing rules) It is not accepted in IE 8 or earlier - text/javascript is accepted but it is defined as obsolete in RFC 4329. The "type" attribute of the <script> tag in HTML5 is optional and in practice omitting the media type of JavaScript programs is the most interoperable solution since all browsers have always assumed the correct default even before HTML5.</summary>
public const string ApplicationJavascript = "application/javascript";
///<summary>ECMAScript/JavaScript; Defined in RFC 4329 (equivalent to application/javascript but with stricter processing rules)</summary>
public const string ApplicationEcmascript = "application/ecmascript";
///<summary>EDI EDIFACT data; Defined in RFC 1767</summary>
public const string ApplicationEdifact = "application/EDIFACT";
///<summary>EDI X12 data; Defined in RFC 1767</summary>
public const string ApplicationEdiX12 = "application/EDI-X12";
///<summary>Email; Defined in RFC 2045 and RFC 2046</summary>
public const string MessagePartial = "message/partial";
///<summary>Email; EML files, MIME files, MHT files, MHTML files; Defined in RFC 2045 and RFC 2046</summary>
public const string MessageRfc822 = "message/rfc822";
///<summary>Extensible Markup Language; Defined in RFC 3023</summary>
public const string TextXml = "text/xml";
///<summary>Flash video (FLV files)</summary>
public const string VideoXFlv = "video/x-flv";
///<summary>GIF image; Defined in RFC 2045 and RFC 2046</summary>
public const string ImageGif = "image/gif";
///<summary>GoogleWebToolkit data</summary>
public const string TextXGwtRpc = "text/x-gwt-rpc";
///<summary>Gzip</summary>
public const string ApplicationXGzip = "application/x-gzip";
///<summary>HTML; Defined in RFC 2854</summary>
public const string TextHtml = "text/html";
///<summary>ICO image; Registered[9]</summary>
public const string ImageVndMicrosoftIcon = "image/vnd.microsoft.icon";
///<summary>IGS files, IGES files; Defined in RFC 2077</summary>
public const string ModelIges = "model/iges";
///<summary>IMDN Instant Message Disposition Notification; Defined in RFC 5438</summary>
public const string MessageImdnXml = "message/imdn+xml";
///<summary>JavaScript Object Notation JSON; Defined in RFC 4627</summary>
public const string ApplicationJson = "application/json";
///<summary>JavaScript Object Notation (JSON) Patch; Defined in RFC 6902</summary>
public const string ApplicationJsonPatch = "application/json-patch+json";
///<summary>JavaScript - Defined in and obsoleted by RFC 4329 in order to discourage its usage in favor of application/javascript. However,text/javascript is allowed in HTML 4 and 5 and, unlike application/javascript, has cross-browser support. The "type" attribute of the <script> tag in HTML5 is optional and there is no need to use it at all since all browsers have always assumed the correct default (even in HTML 4 where it was required by the specification).</summary>
[Obsolete]
public const string TextJavascript = "text/javascript";
///<summary>JPEG JFIF image; Associated with Internet Explorer; Listed in ms775147(v=vs.85) - Progressive JPEG, initiated before global browser support for progressive JPEGs (Microsoft and Firefox).</summary>
public const string ImagePjpeg = "image/pjpeg";
///<summary>JPEG JFIF image; Defined in RFC 2045 and RFC 2046</summary>
public const string ImageJpeg = "image/jpeg";
///<summary>jQuery template data</summary>
public const string TextXJqueryTmpl = "text/x-jquery-tmpl";
///<summary>KML files (e.g. for Google Earth)</summary>
public const string ApplicationVndGoogleEarthKmlXml = "application/vnd.google-earth.kml+xml";
///<summary>LaTeX files</summary>
public const string ApplicationXLatex = "application/x-latex";
///<summary>Matroska open media format</summary>
public const string VideoXMatroska = "video/x-matroska";
///<summary>Microsoft Excel 2007 files</summary>
public const string ApplicationVndOpenxmlformatsOfficedocumentSpreadsheetmlSheet = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
///<summary>Microsoft Excel files</summary>
public const string ApplicationVndMsExcel = "application/vnd.ms-excel";
///<summary>Microsoft Powerpoint 2007 files</summary>
public const string ApplicationVndOpenxmlformatsOfficedocumentPresentationmlPresentation = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
///<summary>Microsoft Powerpoint files</summary>
public const string ApplicationVndMsPowerpoint = "application/vnd.ms-powerpoint";
///<summary>Microsoft Word 2007 files</summary>
public const string ApplicationVndOpenxmlformatsOfficedocumentWordprocessingmlDocument = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
///<summary>Microsoft Word files[15]</summary>
public const string ApplicationMsword = "application/msword";
///<summary>MIME Email; Defined in RFC 2045 and RFC 2046</summary>
public const string MultipartAlternative = "multipart/alternative";
///<summary>MIME Email; Defined in RFC 2045 and RFC 2046</summary>
public const string MultipartMixed = "multipart/mixed";
///<summary>MIME Email; Defined in RFC 2387 and used by MHTML (HTML mail)</summary>
public const string MultipartRelated = "multipart/related";
///<summary>MIME Webform; Defined in RFC 2388</summary>
public const string MultipartFormData = "multipart/form-data";
///<summary>Mozilla XUL files</summary>
public const string ApplicationVndMozillaXulXml = "application/vnd.mozilla.xul+xml";
///<summary>MP3 or other MPEG audio; Defined in RFC 3003</summary>
public const string AudioMpeg = "audio/mpeg";
///<summary>MP4 audio</summary>
public const string AudioMp4 = "audio/mp4";
///<summary>MP4 video; Defined in RFC 4337</summary>
public const string VideoMp4 = "video/mp4";
///<summary>MPEG-1 video with multiplexed audio; Defined in RFC 2045 and RFC 2046</summary>
public const string VideoMpeg = "video/mpeg";
///<summary>MSH files, MESH files; Defined in RFC 2077, SILO files</summary>
public const string ModelMesh = "model/mesh";
///<summary>mulaw audio at 8 kHz, 1 channel; Defined in RFC 2046</summary>
public const string AudioBasic = "audio/basic";
///<summary>Ogg Theora or other video (with audio); Defined in RFC 5334</summary>
public const string VideoOgg = "video/ogg";
///<summary>Ogg Vorbis, Speex, Flac and other audio; Defined in RFC 5334</summary>
public const string AudioOgg = "audio/ogg";
///<summary>Ogg, a multimedia bitstream container format; Defined in RFC 5334</summary>
public const string ApplicationOgg = "application/ogg";
///<summary>OP</summary>
public const string ApplicationXopXml = "application/xop+xml";
///<summary>OpenDocument Graphics; Registered[14]</summary>
public const string ApplicationVndOasisOpendocumentGraphics = "application/vnd.oasis.opendocument.graphics";
///<summary>OpenDocument Presentation; Registered[13]</summary>
public const string ApplicationVndOasisOpendocumentPresentation = "application/vnd.oasis.opendocument.presentation";
///<summary>OpenDocument Spreadsheet; Registered[12]</summary>
public const string ApplicationVndOasisOpendocumentSpreadsheet = "application/vnd.oasis.opendocument.spreadsheet";
///<summary>OpenDocument Text; Registered[11]</summary>
public const string ApplicationVndOasisOpendocumentText = "application/vnd.oasis.opendocument.text";
///<summary>p12 files</summary>
public const string ApplicationXPkcs12 = "application/x-pkcs12";
///<summary>p7b and spc files</summary>
public const string ApplicationXPkcs7Certificates = "application/x-pkcs7-certificates";
///<summary>p7c files</summary>
public const string ApplicationXPkcs7Mime = "application/x-pkcs7-mime";
///<summary>p7r files</summary>
public const string ApplicationXPkcs7Certreqresp = "application/x-pkcs7-certreqresp";
///<summary>p7s files</summary>
public const string ApplicationXPkcs7Signature = "application/x-pkcs7-signature";
///<summary>Portable Document Format, PDF has been in use for document exchange on the Internet since 1993; Defined in RFC 3778</summary>
public const string ApplicationPdf = "application/pdf";
///<summary>Portable Network Graphics; Registered,[8] Defined in RFC 2083</summary>
public const string ImagePng = "image/png";
///<summary>PostScript; Defined in RFC 2046</summary>
public const string ApplicationPostscript = "application/postscript";
///<summary>QuickTime video; Registered[10]</summary>
public const string VideoQuicktime = "video/quicktime";
///<summary>RAR archive files</summary>
public const string ApplicationXRarCompressed = "application/x-rar-compressed";
///<summary>RealAudio; Documented in RealPlayer Customer Support Answer 2559</summary>
public const string AudioVndRnRealaudio = "audio/vnd.rn-realaudio";
///<summary>Resource Description Framework; Defined by RFC 3870</summary>
public const string ApplicationRdfXml = "application/rdf+xml";
///<summary>RSS feeds</summary>
public const string ApplicationRssXml = "application/rss+xml";
///<summary>SOAP; Defined by RFC 3902</summary>
public const string ApplicationSoapXml = "application/soap+xml";
///<summary>StuffIt archive files</summary>
public const string ApplicationXStuffit = "application/x-stuffit";
///<summary>SVG vector image; Defined in SVG Tiny 1.2 Specification Appendix M</summary>
public const string ImageSvgXml = "image/svg+xml";
///<summary>Tag Image File Format (only for Baseline TIFF); Defined in RFC 3302</summary>
public const string ImageTiff = "image/tiff";
///<summary>Tarball files</summary>
public const string ApplicationXTar = "application/x-tar";
///<summary>Textual data; Defined in RFC 2046 and RFC 3676</summary>
public const string TextPlain = "text/plain";
///<summary>TrueType Font No registered MIME type, but this is the most commonly used</summary>
public const string ApplicationXFontTtf = "application/x-font-ttf";
///<summary>vCard (contact information); Defined in RFC 6350</summary>
public const string TextVcard = "text/vcard";
///<summary>Vorbis encoded audio; Defined in RFC 5215</summary>
public const string AudioVorbis = "audio/vorbis";
///<summary>WAV audio; Defined in RFC 2361</summary>
public const string AudioVndWave = "audio/vnd.wave";
///<summary>Web Open Font Format; (candidate recommendation; use application/x-font-woff until standard is official)</summary>
public const string ApplicationFontWoff = "application/font-woff";
///<summary>WebM Matroska-based open media format</summary>
public const string VideoWebm = "video/webm";
///<summary>WebM open media format</summary>
public const string AudioWebm = "audio/webm";
///<summary>Windows Media Audio Redirector; Documented in Microsoft help page</summary>
public const string AudioXMsWax = "audio/x-ms-wax";
///<summary>Windows Media Audio; Documented in Microsoft KB 288102</summary>
public const string AudioXMsWma = "audio/x-ms-wma";
///<summary>Windows Media Video; Documented in Microsoft KB 288102</summary>
public const string VideoXMsWmv = "video/x-ms-wmv";
///<summary>WRL files, VRML files; Defined in RFC 2077</summary>
public const string ModelVrml = "model/vrml";
///<summary>X3D ISO standard for representing 3D computer graphics, X3D XML files</summary>
public const string ModelX3DXml = "model/x3d+xml";
///<summary>X3D ISO standard for representing 3D computer graphics, X3DB binary files</summary>
public const string ModelX3DBinary = "model/x3d+binary";
///<summary>X3D ISO standard for representing 3D computer graphics, X3DV VRML files</summary>
public const string ModelX3DVrml = "model/x3d+vrml";
///<summary>XHTML; Defined by RFC 3236</summary>
public const string ApplicationXhtmlXml = "application/xhtml+xml";
///<summary>ZIP archive files; Registered[7]</summary>
public const string ApplicationZip = "application/zip";
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Hotel.Application")]
[assembly: AssemblyTrademark("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("3870c648-4aea-4b85-ba3f-f2f63b96136a")]

Просмотреть файл

@ -0,0 +1,27 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Abp.Authorization.Roles;
using Abp.AutoMapper;
using Hotel.Authorization.Roles;
namespace Hotel.Roles.Dto
{
[AutoMapTo(typeof(Role))]
public class CreateRoleDto
{
[Required]
[StringLength(AbpRoleBase.MaxNameLength)]
public string Name { get; set; }
[Required]
[StringLength(AbpRoleBase.MaxDisplayNameLength)]
public string DisplayName { get; set; }
public string NormalizedName { get; set; }
[StringLength(Role.MaxDescriptionLength)]
public string Description { get; set; }
public List<string> Permissions { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,11 @@
namespace Hotel.Roles.Dto
{
public class FlatPermissionDto
{
public string Name { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace Hotel.Roles.Dto
{
public class GetRoleForEditOutput
{
public RoleEditDto Role { get; set; }
public List<FlatPermissionDto> Permissions { get; set; }
public List<string> GrantedPermissionNames { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,7 @@
namespace Hotel.Roles.Dto
{
public class GetRolesInput
{
public string Permission { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,10 @@
using Abp.Application.Services.Dto;
namespace Hotel.Roles.Dto
{
public class PagedRoleResultRequestDto : PagedResultRequestDto
{
public string Keyword { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,16 @@
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.Authorization;
namespace Hotel.Roles.Dto
{
[AutoMapFrom(typeof(Permission))]
public class PermissionDto : EntityDto<long>
{
public string Name { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Abp.Application.Services.Dto;
using Abp.Authorization.Roles;
using Abp.AutoMapper;
using Hotel.Authorization.Roles;
namespace Hotel.Roles.Dto
{
[AutoMap(typeof(Role))]
public class RoleDto : EntityDto<int>
{
[Required]
[StringLength(AbpRoleBase.MaxNameLength)]
public string Name { get; set; }
[Required]
[StringLength(AbpRoleBase.MaxDisplayNameLength)]
public string DisplayName { get; set; }
public string NormalizedName { get; set; }
[StringLength(Role.MaxDescriptionLength)]
public string Description { get; set; }
public List<string> Permissions { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,23 @@
using System.ComponentModel.DataAnnotations;
using Abp.Application.Services.Dto;
using Abp.Authorization.Roles;
using Hotel.Authorization.Roles;
namespace Hotel.Roles.Dto
{
public class RoleEditDto: EntityDto<int>
{
[Required]
[StringLength(AbpRoleBase.MaxNameLength)]
public string Name { get; set; }
[Required]
[StringLength(AbpRoleBase.MaxDisplayNameLength)]
public string DisplayName { get; set; }
[StringLength(Role.MaxDescriptionLength)]
public string Description { get; set; }
public bool IsStatic { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,19 @@
using System;
using Abp.Application.Services.Dto;
using Abp.Domain.Entities.Auditing;
namespace Hotel.Roles.Dto
{
public class RoleListDto : EntityDto, IHasCreationTime
{
public string Name { get; set; }
public string DisplayName { get; set; }
public bool IsStatic { get; set; }
public bool IsDefault { get; set; }
public DateTime CreationTime { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,20 @@
using AutoMapper;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Hotel.Authorization.Roles;
namespace Hotel.Roles.Dto
{
public class RoleMapProfile : Profile
{
public RoleMapProfile()
{
// Role and permission
CreateMap<Permission, string>().ConvertUsing(r => r.Name);
CreateMap<RolePermissionSetting, string>().ConvertUsing(r => r.Name);
CreateMap<CreateRoleDto, Role>().ForMember(x => x.Permissions, opt => opt.Ignore());
CreateMap<RoleDto, Role>().ForMember(x => x.Permissions, opt => opt.Ignore());
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Hotel.Roles.Dto;
namespace Hotel.Roles
{
public interface IRoleAppService : IAsyncCrudAppService<RoleDto, int, PagedRoleResultRequestDto, CreateRoleDto, RoleDto>
{
Task<ListResultDto<PermissionDto>> GetAllPermissions();
Task<GetRoleForEditOutput> GetRoleForEdit(EntityDto input);
Task<ListResultDto<RoleListDto>> GetRolesAsync(GetRolesInput input);
}
}

Просмотреть файл

@ -0,0 +1,148 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.IdentityFramework;
using Abp.Linq.Extensions;
using Hotel.Authorization;
using Hotel.Authorization.Roles;
using Hotel.Authorization.Users;
using Hotel.Roles.Dto;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace Hotel.Roles
{
[AbpAuthorize(PermissionNames.Pages_Roles)]
public class RoleAppService : AsyncCrudAppService<Role, RoleDto, int, PagedRoleResultRequestDto, CreateRoleDto, RoleDto>, IRoleAppService
{
private readonly RoleManager _roleManager;
private readonly UserManager _userManager;
public RoleAppService(IRepository<Role> repository, RoleManager roleManager, UserManager userManager)
: base(repository)
{
_roleManager = roleManager;
_userManager = userManager;
}
public override async Task<RoleDto> Create(CreateRoleDto input)
{
CheckCreatePermission();
var role = ObjectMapper.Map<Role>(input);
role.SetNormalizedName();
CheckErrors(await _roleManager.CreateAsync(role));
var grantedPermissions = PermissionManager
.GetAllPermissions()
.Where(p => input.Permissions.Contains(p.Name))
.ToList();
await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);
return MapToEntityDto(role);
}
public async Task<ListResultDto<RoleListDto>> GetRolesAsync(GetRolesInput input)
{
var roles = await _roleManager
.Roles
.WhereIf(
!input.Permission.IsNullOrWhiteSpace(),
r => r.Permissions.Any(rp => rp.Name == input.Permission && rp.IsGranted)
)
.ToListAsync();
return new ListResultDto<RoleListDto>(ObjectMapper.Map<List<RoleListDto>>(roles));
}
public override async Task<RoleDto> Update(RoleDto input)
{
CheckUpdatePermission();
var role = await _roleManager.GetRoleByIdAsync(input.Id);
ObjectMapper.Map(input, role);
CheckErrors(await _roleManager.UpdateAsync(role));
var grantedPermissions = PermissionManager
.GetAllPermissions()
.Where(p => input.Permissions.Contains(p.Name))
.ToList();
await _roleManager.SetGrantedPermissionsAsync(role, grantedPermissions);
return MapToEntityDto(role);
}
public override async Task Delete(EntityDto<int> input)
{
CheckDeletePermission();
var role = await _roleManager.FindByIdAsync(input.Id.ToString());
var users = await _userManager.GetUsersInRoleAsync(role.NormalizedName);
foreach (var user in users)
{
CheckErrors(await _userManager.RemoveFromRoleAsync(user, role.NormalizedName));
}
CheckErrors(await _roleManager.DeleteAsync(role));
}
public Task<ListResultDto<PermissionDto>> GetAllPermissions()
{
var permissions = PermissionManager.GetAllPermissions();
return Task.FromResult(new ListResultDto<PermissionDto>(
ObjectMapper.Map<List<PermissionDto>>(permissions)
));
}
protected override IQueryable<Role> CreateFilteredQuery(PagedRoleResultRequestDto input)
{
return Repository.GetAllIncluding(x => x.Permissions)
.WhereIf(!input.Keyword.IsNullOrWhiteSpace(), x => x.Name.Contains(input.Keyword)
|| x.DisplayName.Contains(input.Keyword)
|| x.Description.Contains(input.Keyword));
}
protected override async Task<Role> GetEntityByIdAsync(int id)
{
return await Repository.GetAllIncluding(x => x.Permissions).FirstOrDefaultAsync(x => x.Id == id);
}
protected override IQueryable<Role> ApplySorting(IQueryable<Role> query, PagedRoleResultRequestDto input)
{
return query.OrderBy(r => r.DisplayName);
}
protected virtual void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
public async Task<GetRoleForEditOutput> GetRoleForEdit(EntityDto input)
{
var permissions = PermissionManager.GetAllPermissions();
var role = await _roleManager.GetRoleByIdAsync(input.Id);
var grantedPermissions = (await _roleManager.GetGrantedPermissionsAsync(role)).ToArray();
var roleEditDto = ObjectMapper.Map<RoleEditDto>(role);
return new GetRoleForEditOutput
{
Role = roleEditDto,
Permissions = ObjectMapper.Map<List<FlatPermissionDto>>(permissions).OrderBy(p => p.DisplayName).ToList(),
GrantedPermissionNames = grantedPermissions.Select(p => p.Name).ToList()
};
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
namespace Hotel.Sessions.Dto
{
public class ApplicationInfoDto
{
public string Version { get; set; }
public DateTime ReleaseDate { get; set; }
public Dictionary<string, bool> Features { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,11 @@
namespace Hotel.Sessions.Dto
{
public class GetCurrentLoginInformationsOutput
{
public ApplicationInfoDto Application { get; set; }
public UserLoginInfoDto User { get; set; }
public TenantLoginInfoDto Tenant { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,14 @@
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Hotel.MultiTenancy;
namespace Hotel.Sessions.Dto
{
[AutoMapFrom(typeof(Tenant))]
public class TenantLoginInfoDto : EntityDto
{
public string TenancyName { get; set; }
public string Name { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Hotel.Authorization.Users;
namespace Hotel.Sessions.Dto
{
[AutoMapFrom(typeof(User))]
public class UserLoginInfoDto : EntityDto<long>
{
public string Name { get; set; }
public string Surname { get; set; }
public string UserName { get; set; }
public string EmailAddress { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Abp.Application.Services;
using Hotel.Sessions.Dto;
namespace Hotel.Sessions
{
public interface ISessionAppService : IApplicationService
{
Task<GetCurrentLoginInformationsOutput> GetCurrentLoginInformations();
}
}

Просмотреть файл

@ -0,0 +1,36 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Abp.Auditing;
using Hotel.Sessions.Dto;
namespace Hotel.Sessions
{
public class SessionAppService : HotelAppServiceBase, ISessionAppService
{
[DisableAuditing]
public async Task<GetCurrentLoginInformationsOutput> GetCurrentLoginInformations()
{
var output = new GetCurrentLoginInformationsOutput
{
Application = new ApplicationInfoDto
{
Version = AppVersionHelper.Version,
ReleaseDate = AppVersionHelper.ReleaseDate,
Features = new Dictionary<string, bool>()
}
};
if (AbpSession.TenantId.HasValue)
{
output.Tenant = ObjectMapper.Map<TenantLoginInfoDto>(await GetCurrentTenantAsync());
}
if (AbpSession.UserId.HasValue)
{
output.User = ObjectMapper.Map<UserLoginInfoDto>(await GetCurrentUserAsync());
}
return output;
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using System.ComponentModel.DataAnnotations;
namespace Hotel.Users.Dto
{
public class ChangePasswordDto
{
[Required]
public string CurrentPassword { get; set; }
[Required]
public string NewPassword { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,10 @@
using System.ComponentModel.DataAnnotations;
namespace Hotel.Users.Dto
{
public class ChangeUserLanguageDto
{
[Required]
public string LanguageName { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,47 @@
using System.ComponentModel.DataAnnotations;
using Abp.Auditing;
using Abp.Authorization.Users;
using Abp.AutoMapper;
using Abp.Runtime.Validation;
using Hotel.Authorization.Users;
namespace Hotel.Users.Dto
{
[AutoMapTo(typeof(User))]
public class CreateUserDto : IShouldNormalize
{
[Required]
[StringLength(AbpUserBase.MaxUserNameLength)]
public string UserName { get; set; }
[Required]
[StringLength(AbpUserBase.MaxNameLength)]
public string Name { get; set; }
[Required]
[StringLength(AbpUserBase.MaxSurnameLength)]
public string Surname { get; set; }
[Required]
[EmailAddress]
[StringLength(AbpUserBase.MaxEmailAddressLength)]
public string EmailAddress { get; set; }
public bool IsActive { get; set; }
public string[] RoleNames { get; set; }
[Required]
[StringLength(AbpUserBase.MaxPlainPasswordLength)]
[DisableAuditing]
public string Password { get; set; }
public void Normalize()
{
if (RoleNames == null)
{
RoleNames = new string[0];
}
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
using Abp.Application.Services.Dto;
using System;
namespace Hotel.Users.Dto
{
//custom PagedResultRequestDto
public class PagedUserResultRequestDto : PagedResultRequestDto
{
public string Keyword { get; set; }
public bool? IsActive { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,16 @@
using System.ComponentModel.DataAnnotations;
namespace Hotel.Users.Dto
{
public class ResetPasswordDto
{
[Required]
public string AdminPassword { get; set; }
[Required]
public long UserId { get; set; }
[Required]
public string NewPassword { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,40 @@
using System;
using System.ComponentModel.DataAnnotations;
using Abp.Application.Services.Dto;
using Abp.Authorization.Users;
using Abp.AutoMapper;
using Hotel.Authorization.Users;
namespace Hotel.Users.Dto
{
[AutoMapFrom(typeof(User))]
public class UserDto : EntityDto<long>
{
[Required]
[StringLength(AbpUserBase.MaxUserNameLength)]
public string UserName { get; set; }
[Required]
[StringLength(AbpUserBase.MaxNameLength)]
public string Name { get; set; }
[Required]
[StringLength(AbpUserBase.MaxSurnameLength)]
public string Surname { get; set; }
[Required]
[EmailAddress]
[StringLength(AbpUserBase.MaxEmailAddressLength)]
public string EmailAddress { get; set; }
public bool IsActive { get; set; }
public string FullName { get; set; }
public DateTime? LastLoginTime { get; set; }
public DateTime CreationTime { get; set; }
public string[] RoleNames { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,19 @@
using AutoMapper;
using Hotel.Authorization.Users;
namespace Hotel.Users.Dto
{
public class UserMapProfile : Profile
{
public UserMapProfile()
{
CreateMap<UserDto, User>();
CreateMap<UserDto, User>()
.ForMember(x => x.Roles, opt => opt.Ignore())
.ForMember(x => x.CreationTime, opt => opt.Ignore());
CreateMap<CreateUserDto, User>();
CreateMap<CreateUserDto, User>().ForMember(x => x.Roles, opt => opt.Ignore());
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Hotel.Roles.Dto;
using Hotel.Users.Dto;
namespace Hotel.Users
{
public interface IUserAppService : IAsyncCrudAppService<UserDto, long, PagedUserResultRequestDto, CreateUserDto, UserDto>
{
Task<ListResultDto<RoleDto>> GetRoles();
Task ChangeLanguage(ChangeUserLanguageDto input);
}
}

Просмотреть файл

@ -0,0 +1,224 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.IdentityFramework;
using Abp.Linq.Extensions;
using Abp.Localization;
using Abp.Runtime.Session;
using Abp.UI;
using Hotel.Authorization;
using Hotel.Authorization.Accounts;
using Hotel.Authorization.Roles;
using Hotel.Authorization.Users;
using Hotel.Roles.Dto;
using Hotel.Users.Dto;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace Hotel.Users
{
[AbpAuthorize(PermissionNames.Pages_Users)]
public class UserAppService : AsyncCrudAppService<User, UserDto, long, PagedUserResultRequestDto, CreateUserDto, UserDto>, IUserAppService
{
private readonly UserManager _userManager;
private readonly RoleManager _roleManager;
private readonly IRepository<Role> _roleRepository;
private readonly IPasswordHasher<User> _passwordHasher;
private readonly IAbpSession _abpSession;
private readonly LogInManager _logInManager;
public UserAppService(
IRepository<User, long> repository,
UserManager userManager,
RoleManager roleManager,
IRepository<Role> roleRepository,
IPasswordHasher<User> passwordHasher,
IAbpSession abpSession,
LogInManager logInManager)
: base(repository)
{
_userManager = userManager;
_roleManager = roleManager;
_roleRepository = roleRepository;
_passwordHasher = passwordHasher;
_abpSession = abpSession;
_logInManager = logInManager;
}
public override async Task<UserDto> Create(CreateUserDto input)
{
CheckCreatePermission();
var user = ObjectMapper.Map<User>(input);
user.TenantId = AbpSession.TenantId;
user.IsEmailConfirmed = true;
await _userManager.InitializeOptionsAsync(AbpSession.TenantId);
CheckErrors(await _userManager.CreateAsync(user, input.Password));
if (input.RoleNames != null)
{
CheckErrors(await _userManager.SetRoles(user, input.RoleNames));
}
CurrentUnitOfWork.SaveChanges();
return MapToEntityDto(user);
}
public override async Task<UserDto> Update(UserDto input)
{
CheckUpdatePermission();
var user = await _userManager.GetUserByIdAsync(input.Id);
MapToEntity(input, user);
CheckErrors(await _userManager.UpdateAsync(user));
if (input.RoleNames != null)
{
CheckErrors(await _userManager.SetRoles(user, input.RoleNames));
}
return await Get(input);
}
public override async Task Delete(EntityDto<long> input)
{
var user = await _userManager.GetUserByIdAsync(input.Id);
await _userManager.DeleteAsync(user);
}
public async Task<ListResultDto<RoleDto>> GetRoles()
{
var roles = await _roleRepository.GetAllListAsync();
return new ListResultDto<RoleDto>(ObjectMapper.Map<List<RoleDto>>(roles));
}
public async Task ChangeLanguage(ChangeUserLanguageDto input)
{
await SettingManager.ChangeSettingForUserAsync(
AbpSession.ToUserIdentifier(),
LocalizationSettingNames.DefaultLanguage,
input.LanguageName
);
}
protected override User MapToEntity(CreateUserDto createInput)
{
var user = ObjectMapper.Map<User>(createInput);
user.SetNormalizedNames();
return user;
}
protected override void MapToEntity(UserDto input, User user)
{
ObjectMapper.Map(input, user);
user.SetNormalizedNames();
}
protected override UserDto MapToEntityDto(User user)
{
var roles = _roleManager.Roles.Where(r => user.Roles.Any(ur => ur.RoleId == r.Id)).Select(r => r.NormalizedName);
var userDto = base.MapToEntityDto(user);
userDto.RoleNames = roles.ToArray();
return userDto;
}
protected override IQueryable<User> CreateFilteredQuery(PagedUserResultRequestDto input)
{
return Repository.GetAllIncluding(x => x.Roles)
.WhereIf(!input.Keyword.IsNullOrWhiteSpace(), x => x.UserName.Contains(input.Keyword) || x.Name.Contains(input.Keyword) || x.EmailAddress.Contains(input.Keyword))
.WhereIf(input.IsActive.HasValue, x => x.IsActive == input.IsActive);
}
protected override async Task<User> GetEntityByIdAsync(long id)
{
var user = await Repository.GetAllIncluding(x => x.Roles).FirstOrDefaultAsync(x => x.Id == id);
if (user == null)
{
throw new EntityNotFoundException(typeof(User), id);
}
return user;
}
protected override IQueryable<User> ApplySorting(IQueryable<User> query, PagedUserResultRequestDto input)
{
return query.OrderBy(r => r.UserName);
}
protected virtual void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
public async Task<bool> ChangePassword(ChangePasswordDto input)
{
if (_abpSession.UserId == null)
{
throw new UserFriendlyException("Please log in before attemping to change password.");
}
long userId = _abpSession.UserId.Value;
var user = await _userManager.GetUserByIdAsync(userId);
var loginAsync = await _logInManager.LoginAsync(user.UserName, input.CurrentPassword, shouldLockout: false);
if (loginAsync.Result != AbpLoginResultType.Success)
{
throw new UserFriendlyException("Your 'Existing Password' did not match the one on record. Please try again or contact an administrator for assistance in resetting your password.");
}
if (!new Regex(AccountAppService.PasswordRegex).IsMatch(input.NewPassword))
{
throw new UserFriendlyException("Passwords must be at least 8 characters, contain a lowercase, uppercase, and number.");
}
user.Password = _passwordHasher.HashPassword(user, input.NewPassword);
CurrentUnitOfWork.SaveChanges();
return true;
}
public async Task<bool> ResetPassword(ResetPasswordDto input)
{
if (_abpSession.UserId == null)
{
throw new UserFriendlyException("Please log in before attemping to reset password.");
}
long currentUserId = _abpSession.UserId.Value;
var currentUser = await _userManager.GetUserByIdAsync(currentUserId);
var loginAsync = await _logInManager.LoginAsync(currentUser.UserName, input.AdminPassword, shouldLockout: false);
if (loginAsync.Result != AbpLoginResultType.Success)
{
throw new UserFriendlyException("Your 'Admin Password' did not match the one on record. Please try again.");
}
if (currentUser.IsDeleted || !currentUser.IsActive)
{
return false;
}
var roles = await _userManager.GetRolesAsync(currentUser);
if (!roles.Contains(StaticRoleNames.Tenants.Admin))
{
throw new UserFriendlyException("Only administrators may reset passwords.");
}
var user = await _userManager.GetUserByIdAsync(input.UserId);
if (user != null)
{
user.Password = _passwordHasher.HashPassword(user, input.NewPassword);
CurrentUnitOfWork.SaveChanges();
}
return true;
}
}
}

Просмотреть файл

@ -0,0 +1,27 @@
using System;
using System.IO;
using Abp.Reflection.Extensions;
namespace Hotel
{
/// <summary>
/// Central point for application version.
/// </summary>
public class AppVersionHelper
{
/// <summary>
/// Gets current version of the application.
/// It's also shown in the web page.
/// </summary>
public const string Version = "4.3.0.0";
/// <summary>
/// Gets release (last build) date of the application.
/// It's shown in the web page.
/// </summary>
public static DateTime ReleaseDate
{
get { return new FileInfo(typeof(AppVersionHelper).GetAssembly().Location).LastWriteTime; }
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
using Abp.Authorization;
using Abp.Localization;
using Abp.MultiTenancy;
namespace Hotel.Authorization
{
public class HotelAuthorizationProvider : AuthorizationProvider
{
public override void SetPermissions(IPermissionDefinitionContext context)
{
context.CreatePermission(PermissionNames.Pages_Users, L("Users"));
context.CreatePermission(PermissionNames.Pages_Roles, L("Roles"));
context.CreatePermission(PermissionNames.Pages_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host);
}
private static ILocalizableString L(string name)
{
return new LocalizableString(name, HotelConsts.LocalizationSourceName);
}
}
}

Просмотреть файл

@ -0,0 +1,45 @@
using Microsoft.AspNetCore.Identity;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Configuration.Startup;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Zero.Configuration;
using Hotel.Authorization.Roles;
using Hotel.Authorization.Users;
using Hotel.MultiTenancy;
namespace Hotel.Authorization
{
public class LogInManager : AbpLogInManager<Tenant, Role, User>
{
public LogInManager(
UserManager userManager,
IMultiTenancyConfig multiTenancyConfig,
IRepository<Tenant> tenantRepository,
IUnitOfWorkManager unitOfWorkManager,
ISettingManager settingManager,
IRepository<UserLoginAttempt, long> userLoginAttemptRepository,
IUserManagementConfig userManagementConfig,
IIocResolver iocResolver,
IPasswordHasher<User> passwordHasher,
RoleManager roleManager,
UserClaimsPrincipalFactory claimsPrincipalFactory)
: base(
userManager,
multiTenancyConfig,
tenantRepository,
unitOfWorkManager,
settingManager,
userLoginAttemptRepository,
userManagementConfig,
iocResolver,
passwordHasher,
roleManager,
claimsPrincipalFactory)
{
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
using Abp.Authorization;
using Hotel.Authorization.Roles;
using Hotel.Authorization.Users;
namespace Hotel.Authorization
{
public class PermissionChecker : PermissionChecker<Role, User>
{
public PermissionChecker(UserManager userManager)
: base(userManager)
{
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
namespace Hotel.Authorization
{
public static class PermissionNames
{
public const string Pages_Tenants = "Pages.Tenants";
public const string Pages_Users = "Pages.Users";
public const string Pages_Roles = "Pages.Roles";
}
}

Просмотреть файл

@ -0,0 +1,29 @@
using Abp.MultiTenancy;
using Abp.Zero.Configuration;
namespace Hotel.Authorization.Roles
{
public static class AppRoleConfig
{
public static void Configure(IRoleManagementConfig roleManagementConfig)
{
// Static host roles
roleManagementConfig.StaticRoles.Add(
new StaticRoleDefinition(
StaticRoleNames.Host.Admin,
MultiTenancySides.Host
)
);
// Static tenant roles
roleManagementConfig.StaticRoles.Add(
new StaticRoleDefinition(
StaticRoleNames.Tenants.Admin,
MultiTenancySides.Tenant
)
);
}
}
}

Просмотреть файл

@ -0,0 +1,28 @@
using System.ComponentModel.DataAnnotations;
using Abp.Authorization.Roles;
using Hotel.Authorization.Users;
namespace Hotel.Authorization.Roles
{
public class Role : AbpRole<User>
{
public const int MaxDescriptionLength = 5000;
public Role()
{
}
public Role(int? tenantId, string displayName)
: base(tenantId, displayName)
{
}
public Role(int? tenantId, string name, string displayName)
: base(tenantId, name, displayName)
{
}
[StringLength(MaxDescriptionLength)]
public string Description {get; set;}
}
}

Просмотреть файл

@ -0,0 +1,37 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Abp.Authorization;
using Abp.Authorization.Roles;
using Abp.Domain.Uow;
using Abp.Runtime.Caching;
using Abp.Zero.Configuration;
using Hotel.Authorization.Users;
namespace Hotel.Authorization.Roles
{
public class RoleManager : AbpRoleManager<Role, User>
{
public RoleManager(
RoleStore store,
IEnumerable<IRoleValidator<Role>> roleValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
ILogger<AbpRoleManager<Role, User>> logger,
IPermissionManager permissionManager,
ICacheManager cacheManager,
IUnitOfWorkManager unitOfWorkManager,
IRoleManagementConfig roleManagementConfig)
: base(
store,
roleValidators,
keyNormalizer,
errors, logger,
permissionManager,
cacheManager,
unitOfWorkManager,
roleManagementConfig)
{
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
using Abp.Authorization.Roles;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Hotel.Authorization.Users;
namespace Hotel.Authorization.Roles
{
public class RoleStore : AbpRoleStore<Role, User>
{
public RoleStore(
IUnitOfWorkManager unitOfWorkManager,
IRepository<Role> roleRepository,
IRepository<RolePermissionSetting, long> rolePermissionSettingRepository)
: base(
unitOfWorkManager,
roleRepository,
rolePermissionSettingRepository)
{
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
namespace Hotel.Authorization.Roles
{
public static class StaticRoleNames
{
public static class Host
{
public const string Admin = "Admin";
}
public static class Tenants
{
public const string Admin = "Admin";
}
}
}

Просмотреть файл

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using Abp.Authorization.Users;
using Abp.Extensions;
namespace Hotel.Authorization.Users
{
public class User : AbpUser<User>
{
public const string DefaultPassword = "123qwe";
public static string CreateRandomPassword()
{
return Guid.NewGuid().ToString("N").Truncate(16);
}
public static User CreateTenantAdminUser(int tenantId, string emailAddress)
{
var user = new User
{
TenantId = tenantId,
UserName = AdminUserName,
Name = AdminUserName,
Surname = AdminUserName,
EmailAddress = emailAddress,
Roles = new List<UserRole>()
};
user.SetNormalizedNames();
return user;
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Abp.Authorization;
using Hotel.Authorization.Roles;
namespace Hotel.Authorization.Users
{
public class UserClaimsPrincipalFactory : AbpUserClaimsPrincipalFactory<User, Role>
{
public UserClaimsPrincipalFactory(
UserManager userManager,
RoleManager roleManager,
IOptions<IdentityOptions> optionsAccessor)
: base(
userManager,
roleManager,
optionsAccessor)
{
}
}
}

Просмотреть файл

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Organizations;
using Abp.Runtime.Caching;
using Hotel.Authorization.Roles;
namespace Hotel.Authorization.Users
{
public class UserManager : AbpUserManager<Role, User>
{
public UserManager(
RoleManager roleManager,
UserStore store,
IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<User> passwordHasher,
IEnumerable<IUserValidator<User>> userValidators,
IEnumerable<IPasswordValidator<User>> passwordValidators,
ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors,
IServiceProvider services,
ILogger<UserManager<User>> logger,
IPermissionManager permissionManager,
IUnitOfWorkManager unitOfWorkManager,
ICacheManager cacheManager,
IRepository<OrganizationUnit, long> organizationUnitRepository,
IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
IOrganizationUnitSettings organizationUnitSettings,
ISettingManager settingManager)
: base(
roleManager,
store,
optionsAccessor,
passwordHasher,
userValidators,
passwordValidators,
keyNormalizer,
errors,
services,
logger,
permissionManager,
unitOfWorkManager,
cacheManager,
organizationUnitRepository,
userOrganizationUnitRepository,
organizationUnitSettings,
settingManager)
{
}
}
}

Просмотреть файл

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Abp.Authorization.Users;
using Abp.Domain.Services;
using Abp.IdentityFramework;
using Abp.Runtime.Session;
using Abp.UI;
using Hotel.Authorization.Roles;
using Hotel.MultiTenancy;
namespace Hotel.Authorization.Users
{
public class UserRegistrationManager : DomainService
{
public IAbpSession AbpSession { get; set; }
private readonly TenantManager _tenantManager;
private readonly UserManager _userManager;
private readonly RoleManager _roleManager;
private readonly IPasswordHasher<User> _passwordHasher;
public UserRegistrationManager(
TenantManager tenantManager,
UserManager userManager,
RoleManager roleManager,
IPasswordHasher<User> passwordHasher)
{
_tenantManager = tenantManager;
_userManager = userManager;
_roleManager = roleManager;
_passwordHasher = passwordHasher;
AbpSession = NullAbpSession.Instance;
}
public async Task<User> RegisterAsync(string name, string surname, string emailAddress, string userName, string plainPassword, bool isEmailConfirmed)
{
CheckForTenant();
var tenant = await GetActiveTenantAsync();
var user = new User
{
TenantId = tenant.Id,
Name = name,
Surname = surname,
EmailAddress = emailAddress,
IsActive = true,
UserName = userName,
IsEmailConfirmed = isEmailConfirmed,
Roles = new List<UserRole>()
};
user.SetNormalizedNames();
foreach (var defaultRole in await _roleManager.Roles.Where(r => r.IsDefault).ToListAsync())
{
user.Roles.Add(new UserRole(tenant.Id, user.Id, defaultRole.Id));
}
await _userManager.InitializeOptionsAsync(tenant.Id);
CheckErrors(await _userManager.CreateAsync(user, plainPassword));
await CurrentUnitOfWork.SaveChangesAsync();
return user;
}
private void CheckForTenant()
{
if (!AbpSession.TenantId.HasValue)
{
throw new InvalidOperationException("Can not register host users!");
}
}
private async Task<Tenant> GetActiveTenantAsync()
{
if (!AbpSession.TenantId.HasValue)
{
return null;
}
return await GetActiveTenantAsync(AbpSession.TenantId.Value);
}
private async Task<Tenant> GetActiveTenantAsync(int tenantId)
{
var tenant = await _tenantManager.FindByIdAsync(tenantId);
if (tenant == null)
{
throw new UserFriendlyException(L("UnknownTenantId{0}", tenantId));
}
if (!tenant.IsActive)
{
throw new UserFriendlyException(L("TenantIdIsNotActive{0}", tenantId));
}
return tenant;
}
protected virtual void CheckErrors(IdentityResult identityResult)
{
identityResult.CheckErrors(LocalizationManager);
}
}
}

Просмотреть файл

@ -0,0 +1,37 @@
using Abp.Authorization.Users;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Linq;
using Abp.Organizations;
using Hotel.Authorization.Roles;
namespace Hotel.Authorization.Users
{
public class UserStore : AbpUserStore<Role, User>
{
public UserStore(
IUnitOfWorkManager unitOfWorkManager,
IRepository<User, long> userRepository,
IRepository<Role> roleRepository,
IAsyncQueryableExecuter asyncQueryableExecuter,
IRepository<UserRole, long> userRoleRepository,
IRepository<UserLogin, long> userLoginRepository,
IRepository<UserClaim, long> userClaimRepository,
IRepository<UserPermissionSetting, long> userPermissionSettingRepository,
IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository,
IRepository<OrganizationUnitRole, long> organizationUnitRoleRepository)
: base(
unitOfWorkManager,
userRepository,
roleRepository,
asyncQueryableExecuter,
userRoleRepository,
userLoginRepository,
userClaimRepository,
userPermissionSettingRepository,
userOrganizationUnitRepository,
organizationUnitRoleRepository)
{
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
using System.Collections.Concurrent;
using Microsoft.Extensions.Configuration;
using Abp.Extensions;
using Abp.Reflection.Extensions;
namespace Hotel.Configuration
{
public static class AppConfigurations
{
private static readonly ConcurrentDictionary<string, IConfigurationRoot> _configurationCache;
static AppConfigurations()
{
_configurationCache = new ConcurrentDictionary<string, IConfigurationRoot>();
}
public static IConfigurationRoot Get(string path, string environmentName = null, bool addUserSecrets = false)
{
var cacheKey = path + "#" + environmentName + "#" + addUserSecrets;
return _configurationCache.GetOrAdd(
cacheKey,
_ => BuildConfiguration(path, environmentName, addUserSecrets)
);
}
private static IConfigurationRoot BuildConfiguration(string path, string environmentName = null, bool addUserSecrets = false)
{
var builder = new ConfigurationBuilder()
.SetBasePath(path)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
if (!environmentName.IsNullOrWhiteSpace())
{
builder = builder.AddJsonFile($"appsettings.{environmentName}.json", optional: true);
}
builder = builder.AddEnvironmentVariables();
if (addUserSecrets)
{
builder.AddUserSecrets(typeof(AppConfigurations).GetAssembly());
}
return builder.Build();
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
namespace Hotel.Configuration
{
public static class AppSettingNames
{
public const string UiTheme = "App.UiTheme";
}
}

Просмотреть файл

@ -0,0 +1,16 @@
using System.Collections.Generic;
using Abp.Configuration;
namespace Hotel.Configuration
{
public class AppSettingProvider : SettingProvider
{
public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context)
{
return new[]
{
new SettingDefinition(AppSettingNames.UiTheme, "red", scopes: SettingScopes.Application | SettingScopes.Tenant | SettingScopes.User, isVisibleToClients: true)
};
}
}
}

Просмотреть файл

@ -0,0 +1,20 @@
using Abp.Application.Editions;
using Abp.Application.Features;
using Abp.Domain.Repositories;
namespace Hotel.Editions
{
public class EditionManager : AbpEditionManager
{
public const string DefaultEditionName = "Standard";
public EditionManager(
IRepository<Edition> editionRepository,
IAbpZeroFeatureValueStore featureValueStore)
: base(
editionRepository,
featureValueStore)
{
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
using Abp.Application.Features;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.MultiTenancy;
using Abp.Runtime.Caching;
using Hotel.Authorization.Users;
using Hotel.MultiTenancy;
namespace Hotel.Features
{
public class FeatureValueStore : AbpFeatureValueStore<Tenant, User>
{
public FeatureValueStore(
ICacheManager cacheManager,
IRepository<TenantFeatureSetting, long> tenantFeatureRepository,
IRepository<Tenant> tenantRepository,
IRepository<EditionFeatureSetting, long> editionFeatureRepository,
IFeatureManager featureManager,
IUnitOfWorkManager unitOfWorkManager)
: base(
cacheManager,
tenantFeatureRepository,
tenantRepository,
editionFeatureRepository,
featureManager,
unitOfWorkManager)
{
}
}
}

Просмотреть файл

@ -0,0 +1,26 @@
using System;
using System.ComponentModel.DataAnnotations;
using Abp.Domain.Entities;
namespace Hotel.Guests
{
public class Guest : Entity
{
[Required]
[StringLength(300)]
public string Name { get; set; }
public DateTime RegisterDate { get; set; }
public Guest()
{
}
public Guest(string name, DateTime registerDate)
{
Name = name;
RegisterDate = registerDate;
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<VersionPrefix>1.0.0.0</VersionPrefix>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback>
<AssemblyName>Hotel.Core</AssemblyName>
<PackageId>Hotel.Core</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<UserSecretsId>AbpCompanyName-Hotel-56C2EF2F-ABD6-4EFC-AAF2-2E81C34E8FB1</UserSecretsId>
<RootNamespace>Hotel</RootNamespace>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Localization\SourceFiles\*.xml" Exclude="bin\**;obj\**;**\*.xproj;packages\**;@(EmbeddedResource)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Abp.AutoMapper" Version="4.3.0" />
<PackageReference Include="Abp.ZeroCore.EntityFrameworkCore" Version="4.3.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="2.2.0" />
<PackageReference Include="Castle.Windsor.MsDependencyInjection" Version="3.3.1" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,11 @@
namespace Hotel
{
public class HotelConsts
{
public const string LocalizationSourceName = "Hotel";
public const string ConnectionStringName = "Default";
public const bool MultiTenancyEnabled = true;
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using Abp.Modules;
using Abp.Reflection.Extensions;
using Abp.Timing;
using Abp.Zero;
using Abp.Zero.Configuration;
using Hotel.Authorization.Roles;
using Hotel.Authorization.Users;
using Hotel.Configuration;
using Hotel.Localization;
using Hotel.MultiTenancy;
using Hotel.Timing;
namespace Hotel
{
[DependsOn(typeof(AbpZeroCoreModule))]
public class HotelCoreModule : AbpModule
{
public override void PreInitialize()
{
Configuration.Auditing.IsEnabledForAnonymousUsers = true;
// Declare entity types
Configuration.Modules.Zero().EntityTypes.Tenant = typeof(Tenant);
Configuration.Modules.Zero().EntityTypes.Role = typeof(Role);
Configuration.Modules.Zero().EntityTypes.User = typeof(User);
HotelLocalizationConfigurer.Configure(Configuration.Localization);
// Enable this line to create a multi-tenant application.
Configuration.MultiTenancy.IsEnabled = HotelConsts.MultiTenancyEnabled;
// Configure roles
AppRoleConfig.Configure(Configuration.Modules.Zero().RoleManagement);
Configuration.Settings.Providers.Add<AppSettingProvider>();
}
public override void Initialize()
{
IocManager.RegisterAssemblyByConvention(typeof(HotelCoreModule).GetAssembly());
}
public override void PostInitialize()
{
IocManager.Resolve<AppTimes>().StartupTime = Clock.Now;
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Hotel.Authorization;
using Hotel.Authorization.Roles;
using Hotel.Authorization.Users;
using Hotel.Editions;
using Hotel.MultiTenancy;
namespace Hotel.Identity
{
public static class IdentityRegistrar
{
public static IdentityBuilder Register(IServiceCollection services)
{
services.AddLogging();
return services.AddAbpIdentity<Tenant, User, Role>()
.AddAbpTenantManager<TenantManager>()
.AddAbpUserManager<UserManager>()
.AddAbpRoleManager<RoleManager>()
.AddAbpEditionManager<EditionManager>()
.AddAbpUserStore<UserStore>()
.AddAbpRoleStore<RoleStore>()
.AddAbpLogInManager<LogInManager>()
.AddAbpSignInManager<SignInManager>()
.AddAbpSecurityStampValidator<SecurityStampValidator>()
.AddAbpUserClaimsPrincipalFactory<UserClaimsPrincipalFactory>()
.AddPermissionChecker<PermissionChecker>()
.AddDefaultTokenProviders();
}
}
}

Просмотреть файл

@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Abp.Authorization;
using Hotel.Authorization.Roles;
using Hotel.Authorization.Users;
using Hotel.MultiTenancy;
namespace Hotel.Identity
{
public class SecurityStampValidator : AbpSecurityStampValidator<Tenant, Role, User>
{
public SecurityStampValidator(
IOptions<SecurityStampValidatorOptions> options,
SignInManager signInManager,
ISystemClock systemClock)
: base(
options,
signInManager,
systemClock)
{
}
}
}

Просмотреть файл

@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Abp.Authorization;
using Abp.Configuration;
using Abp.Domain.Uow;
using Hotel.Authorization.Roles;
using Hotel.Authorization.Users;
using Hotel.MultiTenancy;
namespace Hotel.Identity
{
public class SignInManager : AbpSignInManager<Tenant, Role, User>
{
public SignInManager(
UserManager userManager,
IHttpContextAccessor contextAccessor,
UserClaimsPrincipalFactory claimsFactory,
IOptions<IdentityOptions> optionsAccessor,
ILogger<SignInManager<User>> logger,
IUnitOfWorkManager unitOfWorkManager,
ISettingManager settingManager,
IAuthenticationSchemeProvider schemes)
: base(
userManager,
contextAccessor,
claimsFactory,
optionsAccessor,
logger,
unitOfWorkManager,
settingManager,
schemes)
{
}
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using Abp.Configuration.Startup;
using Abp.Localization.Dictionaries;
using Abp.Localization.Dictionaries.Xml;
using Abp.Reflection.Extensions;
namespace Hotel.Localization
{
public static class HotelLocalizationConfigurer
{
public static void Configure(ILocalizationConfiguration localizationConfiguration)
{
localizationConfiguration.Sources.Add(
new DictionaryBasedLocalizationSource(HotelConsts.LocalizationSourceName,
new XmlEmbeddedFileLocalizationDictionaryProvider(
typeof(HotelLocalizationConfigurer).GetAssembly(),
"Hotel.Localization.SourceFiles"
)
)
);
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="es">
<texts>
<text name="HomePage" value="Página de inicio" />
<text name="About" value="Acerca de" />
<text name="WelcomeMessage" value="Bienvenido a WMS!" />
<text name="FormIsNotValidMessage" value="Formulario no es válido. Por favor, compruebe y corrija los errores." />
<text name="TenantNameCanNotBeEmpty" value="Nombre de la empresa no puede estar vacío" />
<text name="InvalidUserNameOrPassword" value="Usuario o contraseña invalido" />
<text name="ThereIsNoTenantDefinedWithName{0}" value="No hay empresa definida con el nombre {0}" />
<text name="TenantIsNotActive" value="La empresa {0} no está activa." />
<text name="UserIsNotActiveAndCanNotLogin" value="El usuario {0} no está activo y no puede conectarse." />
<text name="PleaseEnterLoginInformation" value="Por favor, introduzca la información de inicio de sesión" />
<text name="TenancyName" value="Nombre de la empresa" />
<text name="UserNameOrEmail" value="Nombre de usuario o correo electrónico" />
<text name="Password" value="Contraseña" />
<text name="RememberMe" value="Recuérdame" />
<text name="LogIn" value="Iniciar sesión" />
<text name="LoginFailed" value="¡Error de inicio de sesion!" />
<text name="NameSurname" value="Nombre Apellido" />
<text name="UserName" value="Nombre de usuario" />
<text name="Name" value="Nombre" />
<text name="Surname" value="Apellido" />
<text name="EmailAddress" value="Dirección de correo electrónico" />
<text name="Tenants" value="Empresas" />
<text name="SavedSuccessfully" value="Guardado correctamente" />
<text name="CreateNewTenant" value="Crear nueva empresa" />
<text name="AdminEmailAddress" value="Dirección de correo electrónico del administrador" />
<text name="Save" value="Guardar" />
<text name="Cancel" value="Cancelar" />
<text name="TenantName_Regex_Description" value="El nombre de la empresa debe ser de al menos 2 caracteres, empieza con una letra y continua con una letra, número, guión o un guión bajo." />
<text name="DefaultPasswordIs" value="La contraseña por defecto es {0}" />
<text name="CanBeEmptyToLoginAsHost" value="Puede estar vacía para iniciar la sesión como anfitrión." />
<text name="Register" value="Registro" />
<text name="OrLoginWith" value="o iniciar sesión con" />
<text name="WaitingForActivationMessage" value="Su cuenta está en espera de ser activada por el administrador del sistema." />
<text name="TenantSelection" value="Selección de Empresa" />
<text name="TenantSelection_Detail" value="Por favor seleccione una de las siguientes empresas." />
<text name="Logout" value="Cerrar sesión" />
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="fr">
<texts>
<text name="HomePage" value="Accueil" />
<text name="About" value="A propos" />
<text name="WelcomeMessage" value="Bienvenue sur Hotel !" />
<text name="FormIsNotValidMessage" value="Le formulaire n'est pas valide. Veuillez le corriger." />
<text name="TenantNameCanNotBeEmpty" value="Le nom de client (tenant) doit être renseigné." />
<text name="InvalidUserNameOrPassword" value="Nom d'utilisateur ou mot de passe non valide." />
<text name="ThereIsNoTenantDefinedWithName{0}" value="Il n'y a aucun nom de client (tenant) correspondant à {0}" />
<text name="TenantIsNotActive" value="Le client (tenant) {0} n'est pas actif." />
<text name="UserIsNotActiveAndCanNotLogin" value="L'utilisateur {0} n'est pas actif ou ne peut pas s'authentifier." />
<text name="PleaseEnterLoginInformation" value="Veuillez entrer vos informations d'authentification" />
<text name="TenancyName" value="Nom du client (tenant)" />
<text name="UserNameOrEmail" value="Nom d'utilisateur ou email" />
<text name="Password" value="Mot de passe" />
<text name="RememberMe" value="Se rappeler de moi" />
<text name="LogIn" value="Se connecter" />
<text name="LoginFailed" value="Echec d'authentification !" />
<text name="NameSurname" value="Nom de famille" />
<text name="UserName" value="Nom d'utilisateur" />
<text name="Name" value="Prénom" />
<text name="Surname" value="Nom de famille" />
<text name="EmailAddress" value="Adresse email" />
<text name="Tenants" value="Clients (tenants)" />
<text name="SavedSuccessfully" value="Enregistrement réussi" />
<text name="CreateNewTenant" value="Créer un nouveau client (tenant)" />
<text name="AdminEmailAddress" value="Adresse email de l'administrateur" />
<text name="Save" value="Valider" />
<text name="Cancel" value="Annuler" />
<text name="TenantName_Regex_Description" value="Le nom de client (tenant) doit comporter au moins 2 caractères et commencer par une lettre suivie d'autres lettres, chiffres ou tirets." />
<text name="DefaultPasswordIs" value="Le mot de passe par défaut est {0}" />
<text name="CanBeEmptyToLoginAsHost" value="Peut être laissé vide pour s'authentifier en tant qu'hébergeur (host)." />
<text name="Register" value="S'enregistrer" />
<text name="OrLoginWith" value="Ou s'authentifier avec" />
<text name="WaitingForActivationMessage" value="Votre compte est en attente d'activation par l'administrateur du système." />
<text name="TenantSelection" value="Sélection du client (tenant)" />
<text name="TenantSelection_Detail" value="Veuillez choisir l'un de ces clients (tenants) suivants." />
<text name="Logout" value="Déconnexion" />
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="it">
<texts>
<text name="HomePage" value="Home page" />
<text name="About" value="Chi siamo" />
<text name="WelcomeMessage" value="Benvenuti su My New House!" />
<text name="FormIsNotValidMessage" value="I dati non sono corretti. Verifica gli errori." />
<text name="TenantNameCanNotBeEmpty" value="Il Dominio non può essere vuoto" />
<text name="InvalidUserNameOrPassword" value="Username o password errati" />
<text name="ThereIsNoTenantDefinedWithName{0}" value="Il dominio {0} non esiste" />
<text name="TenantIsNotActive" value="Il dominio {0} non è attivo." />
<text name="UserIsNotActiveAndCanNotLogin" value="L'utente {0} non è attivo e non può fare login." />
<text name="UserEmailIsNotConfirmedAndCanNotLogin">Indirizzo email non registrato. Login non ammesso.</text>
<text name="UserLockedOutMessage">L'account è momentaneamente bloccato. Riprovare più tardi.</text>
<text name="PleaseEnterLoginInformation" value="Inserisci le informazioni di login" />
<text name="TenancyName" value="Dominio" />
<text name="UserNameOrEmail" value="Use name o email" />
<text name="Password" value="Password" />
<text name="RememberMe" value="Ricordati di me" />
<text name="LogIn" value="Log in" />
<text name="LoginFailed" value="Login errato!" />
<text name="NameSurname" value="Nome e Cognome" />
<text name="UserName" value="Username" />
<text name="Name" value="Nome" />
<text name="Surname" value="Cognome" />
<text name="EmailAddress" value="Email" />
<text name="Tenants" value="Dominio" />
<text name="SavedSuccessfully" value="Salvato" />
<text name="CreateNewTenant" value="Crea un nuovo dominio" />
<text name="AdminEmailAddress" value="Indirizzo email Amministratore" />
<text name="Save" value="Salva" />
<text name="Cancel" value="Annulla" />
<text name="TenantName_Regex_Description" value="Il dominio deve essere di almeno 2 caratteri, iniziare con una lettera e continuare con lettere, numeri o trattini." />
<text name="DefaultPasswordIs" value="La password di default è {0}" />
<text name="CanBeEmptyToLoginAsHost" value="Può essere vuoto per entrare come ospite." />
<text name="Register" value="Registrati" />
<text name="OrLoginWith" value="O entra con" />
<text name="WaitingForActivationMessage" value="Il tuo account è in attesa di approvazione." />
<text name="TenantSelection" value="Selezione dominio" />
<text name="TenantSelection_Detail" value="Seleziona uno dei seguenti domini." />
<text name="Logout" value="Logout" />
<text name="DatabaseConnectionString" value="String connession Database" />
<text name="Users" value="Utenti" />
<text name="IsActive" value="Attivo" />
<text name="FullName" value="Nome completo" />
<text name="CreateNewUser" value="Nuovo utente" />
<text name="Yes" value="Sì" />
<text name="No" value="No" />
<text name="Optional" value="Opzionale" />
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="ja">
<texts>
<text name="HomePage" value="ホームページ" />
<text name="About" value="我々について" />
<text name="WelcomeMessage" value="ようこそ Hotel へ!" />
<text name="FormIsNotValidMessage" value="フォームは無効です。エラーを修正してください。" />
<text name="TenantNameCanNotBeEmpty" value="テナント名を空にすることはできません" />
<text name="InvalidUserNameOrPassword" value="無効なユーザー名またはパスワードです" />
<text name="ThereIsNoTenantDefinedWithName{0}" value="テナント名前 {0} の定義がありません。" />
<text name="TenantIsNotActive" value="テナント {0} はアクティブではありません。 " />
<text name="UserIsNotActiveAndCanNotLogin" value="ユーザー {0} がアクティブでなくログインできません。" />
<text name="PleaseEnterLoginInformation" value="ログイン情報を入力してください" />
<text name="TenancyName" value="テナント名" />
<text name="UserNameOrEmail" value="ユーザ名 または E-mail" />
<text name="Password" value="パスワード" />
<text name="RememberMe" value="ログイン情報を記憶する" />
<text name="LogIn" value="ログイン" />
<text name="LoginFailed" value="ログイン失敗!" />
<text name="NameSurname" value="名 姓" />
<text name="UserName" value="ユーザ名" />
<text name="Name" value="名前" />
<text name="Surname" value="姓" />
<text name="EmailAddress" value="E-mailアドレス" />
<text name="Tenants" value="テナント" />
<text name="SavedSuccessfully" value="保存成功" />
<text name="CreateNewTenant" value="新規テナント作成" />
<text name="AdminEmailAddress" value="管理者 E-mailアドレス" />
<text name="Save" value="保存" />
<text name="Cancel" value="キャンセル" />
<text name="TenantName_Regex_Description" value="テナント名は少なくとも 2 文字、英字で始まり、文字、数字、ダッシュまたはアンダー スコアである必要があります。" />
<text name="DefaultPasswordIs" value="デフォルトパスワードは {0} です" />
<text name="CanBeEmptyToLoginAsHost" value="ホストでのログインは空とすることができます。" />
<text name="Register" value="登録" />
<text name="OrLoginWith" value="または次でログイン" />
<text name="WaitingForActivationMessage" value="あなたのアカウントがシステム管理者によってアクティブにされるまで待機しています。" />
<text name="TenantSelection" value="テナント選択" />
<text name="TenantSelection_Detail" value="次のテナントの 1 つを選択してください。" />
<text name="Logout" value="ログアウト" />
<text name="RegisterFormUserNameInvalidMessage">ユーザのメールアドレスを入力しないでください。</text>
<text name="DatabaseConnectionString" value="データベース接続文字列" />
<text name="Users" value="ユーザ" />
<text name="IsActive" value="アクティブ" />
<text name="FullName" value="フルネーム" />
<text name="CreateNewUser" value="新規ユーザ作成" />
<text name="Yes" value="はい" />
<text name="No" value="いいえ" />
<text name="Optional" value="オプション" />
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="lt">
<texts>
<text name="HomePage" value="Pagrindinis" />
<text name="About" value="Apie" />
<text name="WelcomeMessage" value="Sveiki atvykė į Hotel!" />
<text name="FormIsNotValidMessage" value="Forma blogai užpildyta. Peržiūrėkite ir pataisykite klaidas." />
<text name="TenantNameCanNotBeEmpty" value="Savininko pavadinimas negali būti tuščias" />
<text name="InvalidUserNameOrPassword" value="Blogas vartotojo vardas ar slaptažodis" />
<text name="ThereIsNoTenantDefinedWithName{0}" value="Nėra tokio savininko su pavadinimu {0}" />
<text name="TenantIsNotActive" value="Savininkas {0} nėra aktyvus." />
<text name="UserIsNotActiveAndCanNotLogin" value="Vartotojas {0} nėra aktyvus ir todėl negali prisijungti." />
<text name="UserEmailIsNotConfirmedAndCanNotLogin">Jūsų el. pašto adresas nepatvirtintas. Jūs negalite prisijungti.</text>
<text name="UserLockedOutMessage">Vartotojo paskyra buvo užblokuota. Pabandykite dar kartą vėliau.</text>
<text name="PleaseEnterLoginInformation" value="Įveskite prisijungimo informaciją" />
<text name="TenancyName" value="Savininko pavadinimas" />
<text name="UserNameOrEmail" value="Vartotojo vardas ar slaptažodis" />
<text name="Password" value="Slaptažodis" />
<text name="RememberMe" value="Prisiminti mane" />
<text name="LogIn" value="Prisijungti" />
<text name="LoginFailed" value="Prisijungimas nepavyko!" />
<text name="NameSurname" value="Vardas pavardė" />
<text name="UserName" value="Vartotojo vardas" />
<text name="Name" value="Vardas" />
<text name="Surname" value="Pavardė" />
<text name="EmailAddress" value="El. pašto adresas" />
<text name="Tenants" value="Savininkai" />
<text name="SavedSuccessfully" value="Išsaugota sėkmingai" />
<text name="CreateNewTenant" value="Sukurti naują savininką" />
<text name="AdminEmailAddress" value="Administratoriaus el. pašto adresas" />
<text name="Save" value="Išsaugoti" />
<text name="Cancel" value="Atšaukti" />
<text name="TenantName_Regex_Description" value="Savininko pavadinimas privalo būti bent 2 simboliai, prasidėti su raide, skaičiumi, brūkšneliu ar pabraukimu." />
<text name="DefaultPasswordIs" value="Slaptažodis pagal nutylėjimą yra {0}" />
<text name="CanBeEmptyToLoginAsHost" value="Gali būti tuščia prisijungimui šeimininku." />
<text name="Register" value="Registruotis" />
<text name="OrLoginWith" value="Arba prisijungti su" />
<text name="WaitingForActivationMessage" value="Jūsų paskyra laukia, kol bus aktyvuota sistemos administratoriaus." />
<text name="TenantSelection" value="Savininko Pasirinkimas" />
<text name="TenantSelection_Detail" value="Pasirinkite vieną iš šių savininkų." />
<text name="Logout" value="Atsijungti" />
<text name="RegisterFormUserNameInvalidMessage">Neveskite el. pašto adreso kaip vartotojo vardo.</text>
<text name="DatabaseConnectionString" value="Duomenų bazės prisijungimo eilutė" />
<text name="Users" value="Vartotojai" />
<text name="IsActive" value="Aktyvus" />
<text name="FullName" value="Vardas pavardė" />
<text name="CreateNewUser" value="Sukurti naują vartotoją" />
<text name="Yes" value="Taip" />
<text name="No" value="Ne" />
<text name="Optional" value="Neprivaloma" />
<text name="LeaveEmptyToSwitchToHost">Palikite tuščią, kad perjungtumėte į priimantįjį</text>
<text name="CurrentTenant">Dabartinis savininkas</text>
<text name="NotSelected">Nepasirinkta</text>
<text name="Change">Keisti</text>
<text name="ChangeTenant">Keisti savininką</text>
<text name="MultiLevelMenu">Multi Level Menu</text>
<text name="Back">Atgal</text>
<text name="SuccessfullyRegistered">Sėkmingai užregistruota</text>
<text name="WaitingForEmailActivation">Jūsų el. pašto adresas turi būti aktyvuotas.</text>
<text name="Roles">Rolės</text>
<text name="DisplayName">Rodomas vardas</text>
<text name="Edit">Keisti</text>
<text name="Delete">Trinti</text>
<text name="CreateNewRole">Kurti naują rolę</text>
<text name="RoleName">Rolės pavadinimas</text>
<text name="Actions">Veiksmai</text>
<text name="CouldNotCompleteLoginOperation">Prisijungimo veiksmas nepavyko. Pabandykite vėliau.</text>
<text name="CouldNotValidateExternalUser">Nepavyko patikrinti išorinio vartotojo</text>
<text name="EditRole">Keisti rolę</text>
<text name="EditTenant">Keisti savininką</text>
<text name="EditUser">Keisti vartotoją</text>
<text name="TenantIdIsNotActive{0}">Savininkas su Id {0} yra neaktyvus</text>
<text name="UnknownTenantId{0}">Nežinomas savininko Id {0}</text>
<text name="ThisFieldIsRequired">Šis laukas yra privalomas</text>
<text name="PleaseWait">Prašome palaukti...</text>
<text name="Administration">Administration</text>
<text name="ClearAll">Išvalyti visus</text>
<text name="ClearOthers">Išvalyti kitus</text>
<text name="LabelOptions">Etiketės nustatymai</text>
<text name="Permissions">Leidimai</text>
<text name="RoleDescription">Rolės aprašymas</text>
<text name="Refresh">Atnaujinti</text>
<text name="Create">Sukurti</text>
<text name="UserDetails">Vartotojo detalės</text>
<text name="UserRoles">Vartotojo rolės</text>
<text name="ConfirmPassword">Patvirtinti slaptažodį</text>
<text name="Version">Versija</text>
<text name="On">Įjungta</text>
<text name="Off">Išjungta</text>
<text name="AreYouSureWantToDelete">Ar tikrai norite pašalinti {0}?</text>
<text name="StartTyping">Pradėkite rašyti</text>
<text name="Skins">Apvalkalai</text>
<text name="Settings">Nustatymai</text>
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="nl">
<texts>
<text name="HomePage" value="Startpagina" />
<text name="About" value="Over" />
<text name="WelcomeMessage" value="Welkom bij Hotel!" />
<text name="FormIsNotValidMessage" value="Formulier is onjuist ingevuld. Controleer en herstel de fouten." />
<text name="TenantNameCanNotBeEmpty" value="Naam van de huurder mag niet leeg zijn" />
<text name="InvalidUserNameOrPassword" value="Onjuiste gebruikersnaam en/of wachtwoord" />
<text name="ThereIsNoTenantDefinedWithName{0}" value="Er is geen huurder met de naam {0}" />
<text name="TenantIsNotActive" value="Huurder {0} is niet actief." />
<text name="UserIsNotActiveAndCanNotLogin" value="Gebruiker {0} is niet actief en kan niet inloggen." />
<text name="UserEmailIsNotConfirmedAndCanNotLogin">Uw email adres is nog niet bevestigd. U kan niet inloggen.</text>
<text name="UserLockedOutMessage">De gebruikersaccount is geblokkeerd. Gelieve later opnieuw te proberen.</text>
<text name="PleaseEnterLoginInformation" value="Vul gebruikersnaam en wachtwoord in" />
<text name="TenancyName" value="Naam huurder" />
<text name="UserNameOrEmail" value="Gebruikersnaam of e-mail" />
<text name="Password" value="Wachtwoord" />
<text name="RememberMe" value="Onthoud mij" />
<text name="LogIn" value="Log in" />
<text name="LoginFailed" value="Inloggen mislukt!" />
<text name="NameSurname" value="Naam achternaam" />
<text name="UserName" value="Gebruikersnaam" />
<text name="Name" value="Naam" />
<text name="Surname" value="Achternaam" />
<text name="EmailAddress" value="E-mailadres" />
<text name="Tenants" value="Huurders" />
<text name="SavedSuccessfully" value="Correct opgeslagen" />
<text name="CreateNewTenant" value="Huurder aanmaken" />
<text name="AdminEmailAddress" value="E-mailadres beheerder" />
<text name="Save" value="Opslaan" />
<text name="Cancel" value="Annuleer" />
<text name="TenantName_Regex_Description" value="De naam van de huurder dient minimaal 2 tekens te hebben en moet beginnen met een letter en kan daarnaast nog letters, nummers en een (liggend) streepje bevatten." />
<text name="DefaultPasswordIs" value="Standaard wachtwoord is {0}" />
<text name="CanBeEmptyToLoginAsHost" value="Kan leeggelaten worden indien je als host in wilt loggen." />
<text name="Register" value="Registreer" />
<text name="OrLoginWith" value="Of log in met" />
<text name="WaitingForActivationMessage" value="Je account dient nog te worden geactiveerd door de beheerder." />
<text name="TenantSelection" value="Huurder selectie" />
<text name="TenantSelection_Detail" value="Selecteer één van onderstaande huurders." />
<text name="Logout" value="Uitloggen" />
<text name="RegisterFormUserNameInvalidMessage">Voer a.u.b. geen e-mailadres in als gebruikersnaam.</text>
<text name="DatabaseConnectionString" value="Database connectie string" />
<text name="Users" value="Gebruikers" />
<text name="IsActive" value="Is actief" />
<text name="FullName" value="Volledige naam" />
<text name="CreateNewUser" value="Gebruiker aanmaken" />
<text name="Yes" value="Ja" />
<text name="No" value="Nee" />
<text name="Optional" value="Optioneel" />
<text name="LeaveEmptyToSwitchToHost">Laat leeg om naar de host te gaan</text>
<text name="CurrentTenant">Huidige huurder</text>
<text name="NotSelected">Niet geselecteerd</text>
<text name="Change">Wijzig</text>
<text name="ChangeTenant">Wijzig huurder</text>
<text name="MultiLevelMenu">Multi Level Menu</text>
<text name="Back">Terug</text>
<text name="SuccessfullyRegistered">Met success geregistreerd</text>
<text name="WaitingForEmailActivation">Uw email adres moet geactiveerd worden</text>
<text name="Roles">Rollen</text>
<text name="DisplayName">Weergavenaam</text>
<text name="Edit">Bewerk</text>
<text name="Delete">Verwijder</text>
<text name="CreateNewRole">Maak nieuwe rol</text>
<text name="RoleName">Rol Naam</text>
<text name="Actions">Acties</text>
<text name="CouldNotCompleteLoginOperation">De login operatie kon niet afgewerkt worden. Gelieve later opnieuw te proberen.</text>
<text name="CouldNotValidateExternalUser">De externe gebruiker kon niet gevalideerd worden</text>
<text name="EditRole">Bewerk rol</text>
<text name="EditTenant">Bewerk huurder</text>
<text name="EditUser">Bewerk gebruiker</text>
<text name="TenantIdIsNotActive{0}">HuurderId {0} is niet actief</text>
<text name="UnknownTenantId{0}">Onbekend huurderId {0}</text>
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="pt-BR">
<texts>
<text name="HomePage" value="Página Inicial" />
<text name="About" value="Sobre" />
<text name="WelcomeMessage" value="Bem Vindo ao Hotel!" />
<text name="FormIsNotValidMessage" value="Formulário não é válido. Por favor, verifique e corrija os erros." />
<text name="TenantNameCanNotBeEmpty" value="Tenant não pode estar vazio" />
<text name="InvalidUserNameOrPassword" value="Nome de usuário ou senha inválida" />
<text name="ThereIsNoTenantDefinedWithName{0}" value="Não há Tenant definido com o nome {0}" />
<text name="TenantIsNotActive" value="Tenant {0} não está ativo." />
<text name="UserIsNotActiveAndCanNotLogin" value="Usuário {0} não está ativo e não pode logar." />
<text name="UserEmailIsNotConfirmedAndCanNotLogin">Seu email não foi confirmado. Você não pode fazer login.</text>
<text name="UserLockedOutMessage">Usuário bloqueado. Por favor, tente mais tarde.</text>
<text name="PleaseEnterLoginInformation" value="Por favor insira as informações de login" />
<text name="TenancyName" value="Nome da Tenancy" />
<text name="UserNameOrEmail" value="Nome de usuário ou email" />
<text name="Password" value="Senha" />
<text name="RememberMe" value="Lembre de mim" />
<text name="LogIn" value="Entrar" />
<text name="LoginFailed" value="Falha no login!" />
<text name="NameSurname" value="Nome sobrenome" />
<text name="UserName" value="Nome de usuário" />
<text name="Name" value="Nome" />
<text name="Surname" value="Sobrenome" />
<text name="EmailAddress" value="Endereço de e-mail" />
<text name="Tenants" value="Tenants" />
<text name="SavedSuccessfully" value="Salvo com sucesso" />
<text name="CreateNewTenant" value="Crie um novo tenant" />
<text name="AdminEmailAddress" value="Endereço de e-mail administrador" />
<text name="Save" value="Salvar" />
<text name="Cancel" value="Cancelar" />
<text name="TenantName_Regex_Description" value="Tenant deve ter no mínimo 2 caracteres, começa com uma letra e continuar com letra, número, traço ou sublinhado." />
<text name="DefaultPasswordIs" value="Senha padrão é {0}" />
<text name="CanBeEmptyToLoginAsHost" value="Pode estar vazio para acessar como Host." />
<text name="Register" value="Registrar" />
<text name="OrLoginWith" value="Ou faça o login com" />
<text name="WaitingForActivationMessage" value="A sua conta está esperando para ser ativado pelo administrador do sistema." />
<text name="TenantSelection" value="Seleção de Tenant" />
<text name="TenantSelection_Detail" value="Por favor selecione um dos seguintes tenants." />
<text name="Logout" value="Sair" />
<text name="RegisterFormUserNameInvalidMessage">Por favor, não entre um email no nome de usuário.</text>
<text name="DatabaseConnectionString" value="Conexão com o banco de dados (Connection String)" />
<text name="Users" value="Usuários" />
<text name="IsActive" value="Ativo" />
<text name="FullName" value="Nome completo" />
<text name="CreateNewUser" value="Novo Usuário" />
<text name="Yes" value="Sim" />
<text name="No" value="Não" />
<text name="Optional" value="Opcional" />
<text name="LeaveEmptyToSwitchToHost">Deixe em branco para mudar para o host.</text>
<text name="CurrentTenant">Tenant atual</text>
<text name="NotSelected">Não selecionado</text>
<text name="Change">Alterar</text>
<text name="ChangeTenant">Alterar tenant</text>
<text name="MultiLevelMenu">Menu multinível</text>
<text name="Back">Voltar</text>
<text name="SuccessfullyRegistered">Registrado com sucesso</text>
<text name="WaitingForEmailActivation">Seu endereço de email deve ser ativado</text>
<text name="Roles">Funções</text>
<text name="DisplayName">Nome de apresentação</text>
<text name="Edit">Editar</text>
<text name="Delete">Excluir</text>
<text name="CreateNewRole">Criar nova função</text>
<text name="RoleName">Nome da função</text>
<text name="Actions">Ações</text>
<text name="CouldNotCompleteLoginOperation">Operação de login não foi completada. Tente novamente mais tarde.</text>
<text name="CouldNotValidateExternalUser">Não foi possível validar um usuário externo</text>
<text name="EditRole">Editar Função</text>
<text name="EditTenant">Editar tenant</text>
<text name="EditUser">Editar usuário</text>
<text name="TenantIdIsNotActive{0}">TenantId {0} não está ativo</text>
<text name="UnknownTenantId{0}">TenantId {0} não foi encontrado</text>
<text name="ThisFieldIsRequired">Campo obrigatório</text>
<text name="PleaseWait">Aguarde...</text>
<text name="Administration">Administração</text>
<text name="ClearAll">Limpar todos</text>
<text name="ClearOthers">Limpar outros</text>
<text name="LabelOptions">Opções de Legenda/Rótulo</text>
<text name="Permissions">Permissões</text>
<text name="RoleDescription">Descrição da função</text>
<text name="Refresh">Atualizar</text>
<text name="Create">Criar</text>
<text name="UserDetails">Detalhes do usuário</text>
<text name="UserRoles">Funções de usuário</text>
<text name="ConfirmPassword">Confirme a senha</text>
<text name="Version">Versão</text>
<text name="On">Ligado</text>
<text name="Off">Desligado</text>
<text name="AreYouSureWantToDelete">Tem certeza que deseja excluir {0}?</text>
<text name="StartTyping">Comece a escrever</text>
<text name="Skins">Temas</text>
<text name="Settings">Configurações</text>
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="tr">
<texts>
<text name="HomePage" value="Ana Sayfa" />
<text name="About" value="Hakkında" />
<text name="WelcomeMessage" value="Hotel projesine hoşgeldiniz!" />
<text name="FormIsNotValidMessage" value="Form geçerli değil. Lütfen kontrol edip hataları düzeltin." />
<text name="TenantNameCanNotBeEmpty" value="Müşteri adı boş bırakılamaz." />
<text name="InvalidUserNameOrPassword" value="Kullanıcı adı ya da şifre hatalı." />
<text name="ThereIsNoTenantDefinedWithName{0}" value="{0} isminde bir müşteri tanımlı değildir." />
<text name="TenantIsNotActive" value="{0} isimli müşteri aktif edilmemiştir." />
<text name="UserIsNotActiveAndCanNotLogin" value="{0} isimli kullanıcı pasife alınmıştır ve sisteme giremez." />
<text name="UserEmailIsNotConfirmedAndCanNotLogin">E-posta adresiniz doğrulanmadı, giriş yapamazsınız.</text>
<text name="UserLockedOutMessage">Kullanıcı hesabı kilitlenmiş. Lütfen bir süre sonra tekrar deneyin.</text>
<text name="PleaseEnterLoginInformation" value="Lütfen giriş bilgilerinizi girin" />
<text name="TenancyName" value="Müşteri adı" />
<text name="UserNameOrEmail" value="Kullanıcı adı ya da e-posta" />
<text name="Password" value="Şifre" />
<text name="RememberMe" value="Beni hatırla" />
<text name="LogIn" value="Giriş" />
<text name="LoginFailed" value="Giriş başarısız!" />
<text name="NameSurname" value="Ad soyad" />
<text name="UserName" value="Kullanıcı adı" />
<text name="Name" value="İsim" />
<text name="Surname" value="Soy isim" />
<text name="EmailAddress" value="E-posta adresi" />
<text name="Tenants" value="Müşteriler" />
<text name="SavedSuccessfully" value="Başarıyla kaydedildi" />
<text name="CreateNewTenant" value="Yeni müşteri oluştur" />
<text name="AdminEmailAddress" value="Yönetici e-posta adresi" />
<text name="Save" value="Kaydet" />
<text name="Cancel" value="İptal" />
<text name="TenantName_Regex_Description" value="Müşteri adı en az 2 karakter olmalı, bir harfle başlamalı ve harf, rakam, tire ya da alt çizgi ile devam etmelidir." />
<text name="DefaultPasswordIs" value="Varsayılan şifre {0}" />
<text name="CanBeEmptyToLoginAsHost" value="Host olarak giriş yapmak için boş bırakılabilir." />
<text name="Register" value="Kayıt ol" />
<text name="OrLoginWith" value="Ya da şununla giriş yap" />
<text name="WaitingForActivationMessage" value="Hesabınız sistem yöneticisi tarafından etkinleştirilmek için bekliyor." />
<text name="TenantSelection" value="Müşteri seçimi" />
<text name="TenantSelection_Detail" value="Lütfen aşağıdaki müşterilerden birisini seçin." />
<text name="Logout" value=ıkış" />
<text name="RegisterFormUserNameInvalidMessage">Lütfen kullanıcı adı alanına e-posta adresi girmeyin.</text>
<text name="DatabaseConnectionString" value="Veritabanı bağlantı cümlesi" />
<text name="Users" value="Kullanıcılar" />
<text name="IsActive" value="Etkin mi" />
<text name="FullName" value="Tam adı" />
<text name="CreateNewUser" value="Yeni kullanıcı oluştur" />
<text name="Yes" value="Evet" />
<text name="No" value="Hayır" />
<text name="Optional" value="Opsiyonel" />
<text name="LeaveEmptyToSwitchToHost">Üst kullanıcıya geçiş için boş değer girin.</text>
<text name="CurrentTenant">Geçerli müşteri</text>
<text name="NotSelected">Seçilmemiş</text>
<text name="Change">Değiştir</text>
<text name="ChangeTenant">Müşteri değiştir</text>
<text name="MultiLevelMenu">Çok Seviyeli Menü</text>
<text name="Back">Geri</text>
<text name="SuccessfullyRegistered">Başarıyla kayıt olundu</text>
<text name="WaitingForEmailActivation">E-posta adresiniz etkinleştirilmeli.</text>
<text name="Roles">Roller</text>
<text name="DisplayName">Görünen ad</text>
<text name="Edit">Düzenle</text>
<text name="Delete">Sil</text>
<text name="CreateNewRole">Yeni rol oluştur</text>
<text name="RoleName">Rol adı</text>
<text name="Actions">İşlemler</text>
<text name="CouldNotCompleteLoginOperation">Giriş işlemi başarısız! Lütfen daha sonra tekrar deneyiniz.</text>
<text name="CouldNotValidateExternalUser">Harici kullanıcı doğrulanamadı!</text>
<text name="EditRole">Rolü düzenle</text>
<text name="EditTenant">Müşteri düzenle</text>
<text name="EditUser">Kullanıcı düzenleme</text>
<text name="TenantIdIsNotActive{0}">Müşteri id aktif değil: {0}</text>
<text name="UnknownTenantId{0}">Müşteri id aktif değil: {0}</text>
<text name="ThisFieldIsRequired">Bu alan zorunludur.</text>
<text name="PleaseWait">Lütfen bekleyin...</text>
<text name="Administration">Yönetim</text>
<text name="ClearAll">Hepsini temizle</text>
<text name="ClearOthers">Diğerlerini temizle</text>
<text name="LabelOptions">Etikent seçenekleri</text>
<text name="Permissions">Yetkiler</text>
<text name="RoleDescription">Rol tanımı</text>
<text name="Refresh">Yenile</text>
<text name="Create">Oluştur</text>
<text name="UserDetails">Kullanıcı detayları</text>
<text name="UserRoles">Kullanıcı rolleri</text>
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="zh-Hans">
<texts>
<text name="HomePage" value="主页" />
<text name="About" value="关于我们" />
<text name="WelcomeMessage" value="欢迎使用 Hotel!" />
<text name="FormIsNotValidMessage" value="部分输入信息不符合要求,请检查并改正.." />
<text name="TenantNameCanNotBeEmpty" value="租户名不能为空" />
<text name="InvalidUserNameOrPassword" value="用户名或密码无效" />
<text name="ThereIsNoTenantDefinedWithName{0}" value="租户 {0}不存在" />
<text name="TenantIsNotActive" value="租户 {0} 未激活." />
<text name="UserIsNotActiveAndCanNotLogin" value="用户 {0} 未激活,不能登录." />
<text name="PleaseEnterLoginInformation" value="请输入登录信息" />
<text name="TenancyName" value="租户标识" />
<text name="UserNameOrEmail" value="用户名或邮箱地址" />
<text name="Password" value="密码" />
<text name="RememberMe" value="记住我" />
<text name="ForgetPassword" value="忘记密码"/>
<text name="NotSelected" value="未选"/>
<text name="ChangeTenant" value="更改租户"/>
<text name="LeaveEmptyToSwitchToHost" value="留空以切换到Host"/>
<text name="LogIn" value="登录" />
<text name="LoginFailed" value="登录失败!" />
<text name="AppName" >Hotel</text>
<text name="UserNamePlaceholder" >请输入账户</text>
<text name="PasswordPlaceholder" >请输入密码</text>
<text name="CopyRight" >© 2018 Hotel</text>
<text name="LoginPrompt" >正在登陆,请稍候!</text>
<text name="UserProfile" >用户资料</text>
<text name="Users" >用户</text>
<text name="Roles" >角色</text>
<text name="Tenants" >租户</text>
<text name="Logout" >注销</text>
<text name="ManageMenu" >菜单</text>
<text name="LabelOptions" >页签操作</text>
<text name="ClearAll" >关闭所有</text>
<text name="ClearOthers" >关闭其他</text>
<text name="Create" >创建</text>
<text name="Add" >添加</text>
<text name="Edit" >编辑</text>
<text name="Delete">删除</text>
<text name="Find" >查找</text>
<text name="CreationTime">创建时间</text>
<text name="Actions">操作</text>
<text name="Keyword">关键字</text>
<text name="NoDatas">没有结果</text>
<text name="Select">请选择</text>
<text name="SelectDate">请选择</text>
<text name="Tips">提示</text>
<text name="DeleteConfirm">确定删除?</text>
<text name="Title" >标题</text>
<text name="Content" >内容</text>
<text name="ChangePassword" >修改密码</text>
<text name="PasswordComplexityNotSatisfied">密码复杂度要求不符.</text>
<text name="PasswordRequireDigit">密码至少需要一位是0到9的数字.</text>
<text name="PasswordRequireLowercase">密码至少需要一位是a到z的小写字母.</text>
<text name="PasswordRequireNonAlphanumeric">密码至少需要包含一个特殊字符(非字母或数字的字符).</text>
<text name="PasswordRequireUppercase">密码至少需要一位是A到Z的大写字母.</text>
<text name="PasswordTooShort">密码长度太短</text>
<text name="UserName">用户名</text>
<text name="Name">名称</text>
<text name="IsActive">是否启用</text>
<text name="LastLoginTime">最近登陆时间</text>
<text name="RoleName">角色名</text>
<text name="DisplayName">显示名</text>
<text name="Description">描述</text>
<text name="IsStatic">是否内置</text>
<text name="All">全部</text>
<text name="Actived">启用</text>
<text name="NoActive">未启用</text>
<text name="Yes"></text>
<text name="No"></text>
<text name="Cancel">取消</text>
<text name="OK">确定</text>
<text name="CreateNewRole">创建新角色</text>
<text name="RoleDetails">角色详情</text>
<text name="RolePermission">角色权限</text>
<text name="EditRole">编辑角色</text>
<text name="DeleteRolesConfirm">确认删除该角色?</text>
<text name="CreateNewUser">创建新用户</text>
<text name="UserDetails">用户详情</text>
<text name="UserRoles">用户角色</text>
<text name="ConfirmPassword">确认密码</text>
<text name="EmailAddress">邮箱地址</text>
<text name="Surname"></text>
<text name="DeleteUserConfirm">确认删除该用户?</text>
<text name="EditUser">编辑用户</text>
<text name="CreateNewTenant">创建新租户</text>
<text name="DatabaseConnectionString">数据库连接</text>
<text name="AdminEmailAddress">管理员邮箱地址</text>
<text name="DefaultPasswordIs">默认密码为:{0}</text>
<text name="DeleteTenantConfirm">确认删除该租户?</text>
<text name="EditTenant">编辑租户</text>
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8" ?>
<localizationDictionary culture="en">
<texts>
<text name="HomePage" value="Home page" />
<text name="About" value="About" />
<text name="WelcomeMessage" value="Welcome to Hotel!" />
<text name="FormIsNotValidMessage" value="Form is not valid. Please check and fix errors." />
<text name="TenantNameCanNotBeEmpty" value="Tenant name can not be empty" />
<text name="InvalidUserNameOrPassword" value="Invalid user name or password" />
<text name="ThereIsNoTenantDefinedWithName{0}" value="There is no tenant defined with name {0}" />
<text name="TenantIsNotActive" value="Tenant {0} is not active." />
<text name="UserIsNotActiveAndCanNotLogin" value="User {0} is not active and can not log in." />
<text name="UserEmailIsNotConfirmedAndCanNotLogin">Your email address is not confirmed. You can not login.</text>
<text name="UserLockedOutMessage">The user account has been locked out. Please try again later.</text>
<text name="PleaseEnterLoginInformation" value="Please enter login information" />
<text name="TenancyName" value="Tenancy name" />
<text name="UserNameOrEmail" value="User name or email" />
<text name="Password" value="Password" />
<text name="ResetPassword" value="Reset Password" />
<text name="UpdatePassword" value="Update Password" />
<text name="RememberMe" value="Remember me" />
<text name="LogIn" value="Log in" />
<text name="LoginFailed" value="Login failed!" />
<text name="NameSurname" value="Name surname" />
<text name="UserName" value="User name" />
<text name="Name" value="Name" />
<text name="Surname" value="Surname" />
<text name="EmailAddress" value="Email address" />
<text name="Tenants" value="Tenants" />
<text name="SavedSuccessfully" value="Saved successfully" />
<text name="CreateNewTenant" value="Create new tenant" />
<text name="AdminEmailAddress" value="Admin email address" />
<text name="AdminPassword" value="Admin password" />
<text name="Save" value="Save" />
<text name="Cancel" value="Cancel" />
<text name="TenantName_Regex_Description" value="Tenant name must be at least 2 chars, starts with a letter and continue with letter, number, dash or underscore." />
<text name="DefaultPasswordIs" value="Default password is {0}" />
<text name="CanBeEmptyToLoginAsHost" value="Can be empty to login as host." />
<text name="Register" value="Register" />
<text name="OrLoginWith" value="Or login with" />
<text name="WaitingForActivationMessage" value="Your account is waiting to be activated by system admin." />
<text name="TenantSelection" value="Tenant Selection" />
<text name="TenantSelection_Detail" value="Please select one of the following tenants." />
<text name="Logout" value="Logout" />
<text name="RegisterFormUserNameInvalidMessage">Please don't enter an email address for username.</text>
<text name="DatabaseConnectionString" value="Database connection string" />
<text name="Users" value="Users" />
<text name="IsActive" value="Is active" />
<text name="FullName" value="Full name" />
<text name="CreateNewUser" value="Create new user" />
<text name="Yes" value="Yes" />
<text name="No" value="No" />
<text name="Optional" value="Optional" />
<text name="LeaveEmptyToSwitchToHost">Leave empty to switch to the host</text>
<text name="CurrentTenant">Current tenant</text>
<text name="NotSelected">Not selected</text>
<text name="Change">Change</text>
<text name="ChangeTenant">Change tenant</text>
<text name="MultiLevelMenu">Multi Level Menu</text>
<text name="Back">Back</text>
<text name="SuccessfullyRegistered">Successfully registered</text>
<text name="WaitingForEmailActivation">Your email address should be activated</text>
<text name="Roles">Roles</text>
<text name="DisplayName">Display Name</text>
<text name="Edit">Edit</text>
<text name="Delete">Delete</text>
<text name="CreateNewRole">Create new role</text>
<text name="RoleName">Role Name</text>
<text name="Actions">Actions</text>
<text name="CouldNotCompleteLoginOperation">Could not complete login operation. Please try again later.</text>
<text name="CouldNotValidateExternalUser">Could not validate external user</text>
<text name="EditRole">Edit role</text>
<text name="EditTenant">Edit tenant</text>
<text name="EditUser">Edit user</text>
<text name="TenantIdIsNotActive{0}">TenantId {0} is not active</text>
<text name="UnknownTenantId{0}">Unknown tenantId {0}</text>
<text name="ThisFieldIsRequired">This field is required</text>
<text name="PleaseWait">Please wait...</text>
<text name="Administration">Administration</text>
<text name="ClearAll">Clear all</text>
<text name="ClearOthers">Clear others</text>
<text name="LabelOptions">Label options</text>
<text name="Permissions">Permissions</text>
<text name="RoleDescription">Role description</text>
<text name="Refresh">Refresh</text>
<text name="Create">Create</text>
<text name="UserDetails">User details</text>
<text name="UserRoles">User roles</text>
<text name="ConfirmPassword">Confirm password</text>
<text name="Version">Version</text>
<text name="On">On</text>
<text name="Off">Off</text>
<text name="AreYouSureWantToDelete">Are you sure want to delete {0}?</text>
<text name="StartTyping">Start Typing</text>
<text name="Skins">Skins</text>
<text name="Settings">Settings</text>
<text name="Filter">Filter</text>
</texts>
</localizationDictionary>

Просмотреть файл

@ -0,0 +1,17 @@
using Abp.MultiTenancy;
using Hotel.Authorization.Users;
namespace Hotel.MultiTenancy
{
public class Tenant : AbpTenant<User>
{
public Tenant()
{
}
public Tenant(string tenancyName, string name)
: base(tenancyName, name)
{
}
}
}

Просмотреть файл

@ -0,0 +1,24 @@
using Abp.Application.Features;
using Abp.Domain.Repositories;
using Abp.MultiTenancy;
using Hotel.Authorization.Users;
using Hotel.Editions;
namespace Hotel.MultiTenancy
{
public class TenantManager : AbpTenantManager<Tenant, User>
{
public TenantManager(
IRepository<Tenant> tenantRepository,
IRepository<TenantFeatureSetting, long> tenantFeatureRepository,
EditionManager editionManager,
IAbpZeroFeatureValueStore featureValueStore)
: base(
tenantRepository,
tenantFeatureRepository,
editionManager,
featureValueStore)
{
}
}
}

Просмотреть файл

@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Hotel.Core")]
[assembly: AssemblyTrademark("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("0fa75a5b-ab83-4fd0-b545-279774c01e87")]

Просмотреть файл

@ -0,0 +1,38 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Abp.Domain.Entities;
using Hotel.Guests;
using Hotel.Rooms;
namespace Hotel.Reservations
{
public class Reservation : Entity
{
[ForeignKey("RoomId")]
public Room Room { get; set; }
public int RoomId { get; set; }
[ForeignKey("GuestId")]
public Guest Guest { get; set; }
public int GuestId { get; set; }
[Required]
public DateTime CheckinDate { get; set; }
public DateTime CheckoutDate { get; set; }
public Reservation()
{
}
public Reservation(DateTime checkinDate, DateTime checkoutDate, int roomId, int guestId)
{
CheckinDate = checkinDate;
CheckoutDate = checkoutDate;
RoomId = roomId;
GuestId = guestId;
}
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше