Files
Umbraco-CMS/src/Umbraco.Web.BackOffice/Controllers/UsersController.cs

870 lines
37 KiB
C#
Raw Normal View History

using System;
2017-09-12 16:22:16 +02:00
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
Merge remote-tracking branch 'origin/v8/dev' into netcore/feature/merge-v8-18-01-2021 # Conflicts: # .gitignore # build/NuSpecs/UmbracoCms.Core.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Configuration/UmbracoSettings/BackOfficeElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs # src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs # src/Umbraco.Core/IO/SystemFiles.cs # src/Umbraco.Core/Models/ContentBase.cs # src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs # src/Umbraco.Core/Persistence/UmbracoDatabaseExtensions.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/RuntimeOptions.cs # src/Umbraco.Core/RuntimeState.cs # src/Umbraco.Core/Telemetry/TelemetryMarkerComponent.cs # src/Umbraco.Core/Telemetry/TelemetryMarkerComposer.cs # src/Umbraco.Examine/Umbraco.Examine.csproj # src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs # src/Umbraco.Infrastructure/Install/InstallStepCollection.cs # src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs # src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs # src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs # src/Umbraco.Tests/Runtimes/StandaloneTests.cs # src/Umbraco.Tests/Testing/TestDatabase.cs # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.UI.Client/src/installer/steps/database.controller.js # src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/TextString.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml # src/Umbraco.Web.UI/config/umbracoSettings.Release.config # src/Umbraco.Web/Composing/CompositionExtensions/Installer.cs # src/Umbraco.Web/Editors/PreviewController.cs # src/Umbraco.Web/Editors/UsersController.cs # src/Umbraco.Web/JavaScript/PreviewInitialize.js # src/Umbraco.Web/Telemetry/TelemetryComponent.cs # src/Umbraco.Web/UmbracoApplication.cs
2021-01-18 15:40:22 +01:00
using System.Globalization;
2017-09-12 16:22:16 +02:00
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Security.Cryptography;
Merge remote-tracking branch 'origin/v8/dev' into netcore/feature/merge-v8-18-01-2021 # Conflicts: # .gitignore # build/NuSpecs/UmbracoCms.Core.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Configuration/UmbracoSettings/BackOfficeElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs # src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs # src/Umbraco.Core/IO/SystemFiles.cs # src/Umbraco.Core/Models/ContentBase.cs # src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs # src/Umbraco.Core/Persistence/UmbracoDatabaseExtensions.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/RuntimeOptions.cs # src/Umbraco.Core/RuntimeState.cs # src/Umbraco.Core/Telemetry/TelemetryMarkerComponent.cs # src/Umbraco.Core/Telemetry/TelemetryMarkerComposer.cs # src/Umbraco.Examine/Umbraco.Examine.csproj # src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs # src/Umbraco.Infrastructure/Install/InstallStepCollection.cs # src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs # src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs # src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs # src/Umbraco.Tests/Runtimes/StandaloneTests.cs # src/Umbraco.Tests/Testing/TestDatabase.cs # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.UI.Client/src/installer/steps/database.controller.js # src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/TextString.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml # src/Umbraco.Web.UI/config/umbracoSettings.Release.config # src/Umbraco.Web/Composing/CompositionExtensions/Installer.cs # src/Umbraco.Web/Editors/PreviewController.cs # src/Umbraco.Web/Editors/UsersController.cs # src/Umbraco.Web/JavaScript/PreviewInitialize.js # src/Umbraco.Web/Telemetry/TelemetryComponent.cs # src/Umbraco.Web/UmbracoApplication.cs
2021-01-18 15:40:22 +01:00
using System.Threading;
2017-09-12 16:22:16 +02:00
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Editors;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Mail;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Media;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
2021-06-04 09:50:49 +02:00
using Umbraco.Cms.Core.Models.Email;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Infrastructure;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Web.BackOffice.ActionResults;
using Umbraco.Cms.Web.BackOffice.Extensions;
using Umbraco.Cms.Web.BackOffice.Filters;
using Umbraco.Cms.Web.BackOffice.ModelBinders;
using Umbraco.Cms.Web.BackOffice.Security;
2021-02-10 11:42:04 +01:00
using Umbraco.Cms.Web.Common.ActionsResults;
using Umbraco.Cms.Web.Common.Attributes;
using Umbraco.Cms.Web.Common.Authorization;
2021-02-26 14:21:23 +00:00
using Umbraco.Cms.Web.Common.Security;
2020-05-18 13:00:32 +01:00
using Umbraco.Extensions;
using Constants = Umbraco.Cms.Core.Constants;
namespace Umbraco.Cms.Web.BackOffice.Controllers
2017-09-12 16:22:16 +02:00
{
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
[Authorize(Policy = AuthorizationPolicies.SectionAccessUsers)]
2017-09-12 16:22:16 +02:00
[PrefixlessBodyModelValidator]
[IsCurrentUserModelFilter]
public class UsersController : UmbracoAuthorizedJsonController
{
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
private readonly MediaFileManager _mediaFileManager;
private readonly ContentSettings _contentSettings;
private readonly IHostingEnvironment _hostingEnvironment;
private readonly ISqlContext _sqlContext;
private readonly IImageUrlGenerator _imageUrlGenerator;
private readonly SecuritySettings _securitySettings;
2020-05-20 11:42:23 +02:00
private readonly IEmailSender _emailSender;
2021-02-26 14:52:54 +00:00
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
private readonly AppCaches _appCaches;
private readonly IShortStringHelper _shortStringHelper;
private readonly IUserService _userService;
private readonly ILocalizedTextService _localizedTextService;
Merge remote-tracking branch 'origin/v8/dev' into netcore/dev # Conflicts: # build/NuSpecs/UmbracoCms.Web.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Cache/MediaCacheRefresher.cs # src/Umbraco.Core/Composing/ComponentCollection.cs # src/Umbraco.Core/Composing/Composers.cs # src/Umbraco.Core/Composing/TypeFinder.cs # src/Umbraco.Core/Composing/TypeLoader.cs # src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs # src/Umbraco.Core/Constants-SvgSanitizer.cs # src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs # src/Umbraco.Core/Extensions/PublishedContentExtensions.cs # src/Umbraco.Core/Extensions/PublishedPropertyExtension.cs # src/Umbraco.Core/Extensions/StringExtensions.cs # src/Umbraco.Core/HealthChecks/Checks/Security/ExcessiveHeadersCheck.cs # src/Umbraco.Core/HealthChecks/HealthCheckResults.cs # src/Umbraco.Core/IO/FileSystems.cs # src/Umbraco.Core/IO/IOHelper.cs # src/Umbraco.Core/IO/MediaFileSystem.cs # src/Umbraco.Core/IO/PhysicalFileSystem.cs # src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs # src/Umbraco.Core/Logging/DisposableTimer.cs # src/Umbraco.Core/Logging/ILogger.cs # src/Umbraco.Core/Logging/LogProfiler.cs # src/Umbraco.Core/Logging/OwinLogger.cs # src/Umbraco.Core/Manifest/ManifestWatcher.cs # src/Umbraco.Core/Mapping/UmbracoMapper.cs # src/Umbraco.Core/Media/UploadAutoFillProperties.cs # src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs # src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollection.cs # src/Umbraco.Core/Models/Mapping/ContentPropertyBasicMapper.cs # src/Umbraco.Core/Models/Mapping/DataTypeMapDefinition.cs # src/Umbraco.Core/Models/Mapping/MacroMapDefinition.cs # src/Umbraco.Core/Models/Member.cs # src/Umbraco.Core/Packaging/PackageActionRunner.cs # src/Umbraco.Core/PropertyEditors/DataValueEditor.cs # src/Umbraco.Core/PropertyEditors/Validators/EyeDropperColorPickerConfigurationEditor.cs # src/Umbraco.Core/PropertyEditors/Validators/EyeDropperColorPickerPropertyEditor.cs # src/Umbraco.Core/Routing/DefaultUrlProvider.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/Runtime/MainDom.cs # src/Umbraco.Core/RuntimeState.cs # src/Umbraco.Core/Scoping/ScopeProvider.cs # src/Umbraco.Core/Sync/DatabaseServerMessenger.cs # src/Umbraco.Core/Templates/HtmlUrlParser.cs # src/Umbraco.Core/UriExtensions.cs # src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs # src/Umbraco.Examine.Lucene/UmbracoExamineIndex.cs # src/Umbraco.Infrastructure/Examine/IndexRebuilder.cs # src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs # src/Umbraco.Infrastructure/Manifest/ManifestParser.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs # src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs # src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs # src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs # src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs # src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs # src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/GridValueConverter.cs # src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs # src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs # src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs # src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs # src/Umbraco.Infrastructure/Scoping/Scope.cs # src/Umbraco.Infrastructure/Search/ExamineNotificationHandler.cs # src/Umbraco.Infrastructure/Services/Implement/ContentService.cs # src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs # src/Umbraco.Infrastructure/Services/Implement/LocalizedTextServiceFileSources.cs # src/Umbraco.Infrastructure/Services/Implement/MediaService.cs # src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs # src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs # src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs # src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs # src/Umbraco.PublishedCache.NuCache/ContentStore.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Mapping/MappingTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs # src/Umbraco.Tests/Composing/TypeLoaderTests.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/DictionaryPublishedContent.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/BackgroundTaskRunner.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStoreFilePersister.cs # src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs # src/Umbraco.Tests/Services/PerformanceTests.cs # src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs # src/Umbraco.Tests/Testing/TestingTests/MockTests.cs # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/ContentController.cs # src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs # src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs # src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs # src/Umbraco.Web.BackOffice/PropertyEditors/RteEmbedController.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs # src/Umbraco.Web.Common/Extensions/FormCollectionExtensions.cs # src/Umbraco.Web.Common/Install/InstallApiController.cs # src/Umbraco.Web.Common/Macros/MacroRenderer.cs # src/Umbraco.Web.Common/ModelsBuilder/PureLiveModelFactory.cs # src/Umbraco.Web.UI.Client/package-lock.json # src/Umbraco.Web.UI.Client/src/views/memberTypes/copy.controller.js # src/Umbraco.Web.UI.Client/src/views/memberTypes/copy.html # src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/config/splashes/noNodes.aspx # src/Umbraco.Web/AspNet/AspNetHttpContextAccessor.cs # src/Umbraco.Web/Cache/DistributedCacheBinder.cs # src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs # src/Umbraco.Web/Editors/ContentControllerBase.cs # src/Umbraco.Web/Editors/ContentTypeController.cs # src/Umbraco.Web/Editors/DictionaryController.cs # src/Umbraco.Web/Editors/MemberTypeController.cs # src/Umbraco.Web/Editors/PasswordChanger.cs # src/Umbraco.Web/Editors/RelationTypeController.cs # src/Umbraco.Web/Editors/TinyMceController.cs # src/Umbraco.Web/HealthCheck/Checks/Security/HttpsCheck.cs # src/Umbraco.Web/HtmlHelperRenderExtensions.cs # src/Umbraco.Web/HttpUrlHelperExtensions.cs # src/Umbraco.Web/HybridEventMessagesAccessor.cs # src/Umbraco.Web/ImageCropperTemplateExtensions.cs # src/Umbraco.Web/JavaScript/ClientDependencyConfiguration.cs # src/Umbraco.Web/Mvc/RenderMvcController.cs # src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs # src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs # src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs # src/Umbraco.Web/Routing/ContentFinderByIdPath.cs # src/Umbraco.Web/Routing/ContentFinderByRedirectUrl.cs # src/Umbraco.Web/Routing/ContentFinderByUrl.cs # src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs # src/Umbraco.Web/Routing/ContentFinderByUrlAndTemplate.cs # src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs # src/Umbraco.Web/Routing/PublishedRouter.cs # src/Umbraco.Web/Runtime/WebInitialComposer.cs # src/Umbraco.Web/Scheduling/KeepAlive.cs # src/Umbraco.Web/Scheduling/ScheduledPublishing.cs # src/Umbraco.Web/Scheduling/TempFileCleanup.cs # src/Umbraco.Web/Security/MembershipHelper.cs # src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs # src/Umbraco.Web/Trees/MemberTreeController.cs # src/Umbraco.Web/Trees/MemberTypeAndGroupTreeControllerBase.cs # src/Umbraco.Web/Trees/MemberTypeTreeController.cs # src/Umbraco.Web/UmbracoApplicationBase.cs # src/Umbraco.Web/UmbracoInjectedModule.cs # src/Umbraco.Web/UmbracoModule.cs # src/Umbraco.Web/WebApi/AngularJsonMediaTypeFormatter.cs # src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs # src/Umbraco.Web/WebApi/UnhandledExceptionLogger.cs
2021-04-20 19:34:18 +02:00
private readonly IUmbracoMapper _umbracoMapper;
private readonly GlobalSettings _globalSettings;
2020-10-23 14:18:53 +11:00
private readonly IBackOfficeUserManager _userManager;
private readonly ILoggerFactory _loggerFactory;
private readonly LinkGenerator _linkGenerator;
2020-10-23 14:18:53 +11:00
private readonly IBackOfficeExternalLoginProviders _externalLogins;
private readonly UserEditorAuthorizationHelper _userEditorAuthorizationHelper;
2021-02-20 19:16:31 +00:00
private readonly IPasswordChanger<BackOfficeIdentityUser> _passwordChanger;
2020-10-23 14:18:53 +11:00
private readonly ILogger<UsersController> _logger;
public UsersController(
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
MediaFileManager mediaFileManager,
IOptions<ContentSettings> contentSettings,
IHostingEnvironment hostingEnvironment,
ISqlContext sqlContext,
IImageUrlGenerator imageUrlGenerator,
IOptions<SecuritySettings> securitySettings,
IEmailSender emailSender,
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
AppCaches appCaches,
IShortStringHelper shortStringHelper,
IUserService userService,
ILocalizedTextService localizedTextService,
Merge remote-tracking branch 'origin/v8/dev' into netcore/dev # Conflicts: # build/NuSpecs/UmbracoCms.Web.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Cache/MediaCacheRefresher.cs # src/Umbraco.Core/Composing/ComponentCollection.cs # src/Umbraco.Core/Composing/Composers.cs # src/Umbraco.Core/Composing/TypeFinder.cs # src/Umbraco.Core/Composing/TypeLoader.cs # src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs # src/Umbraco.Core/Constants-SvgSanitizer.cs # src/Umbraco.Core/ContentApps/ContentAppFactoryCollection.cs # src/Umbraco.Core/Extensions/PublishedContentExtensions.cs # src/Umbraco.Core/Extensions/PublishedPropertyExtension.cs # src/Umbraco.Core/Extensions/StringExtensions.cs # src/Umbraco.Core/HealthChecks/Checks/Security/ExcessiveHeadersCheck.cs # src/Umbraco.Core/HealthChecks/HealthCheckResults.cs # src/Umbraco.Core/IO/FileSystems.cs # src/Umbraco.Core/IO/IOHelper.cs # src/Umbraco.Core/IO/MediaFileSystem.cs # src/Umbraco.Core/IO/PhysicalFileSystem.cs # src/Umbraco.Core/Logging/DebugDiagnosticsLogger.cs # src/Umbraco.Core/Logging/DisposableTimer.cs # src/Umbraco.Core/Logging/ILogger.cs # src/Umbraco.Core/Logging/LogProfiler.cs # src/Umbraco.Core/Logging/OwinLogger.cs # src/Umbraco.Core/Manifest/ManifestWatcher.cs # src/Umbraco.Core/Mapping/UmbracoMapper.cs # src/Umbraco.Core/Media/UploadAutoFillProperties.cs # src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs # src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DataTypes/PreValueMigratorCollection.cs # src/Umbraco.Core/Models/Mapping/ContentPropertyBasicMapper.cs # src/Umbraco.Core/Models/Mapping/DataTypeMapDefinition.cs # src/Umbraco.Core/Models/Mapping/MacroMapDefinition.cs # src/Umbraco.Core/Models/Member.cs # src/Umbraco.Core/Packaging/PackageActionRunner.cs # src/Umbraco.Core/PropertyEditors/DataValueEditor.cs # src/Umbraco.Core/PropertyEditors/Validators/EyeDropperColorPickerConfigurationEditor.cs # src/Umbraco.Core/PropertyEditors/Validators/EyeDropperColorPickerPropertyEditor.cs # src/Umbraco.Core/Routing/DefaultUrlProvider.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/Runtime/MainDom.cs # src/Umbraco.Core/RuntimeState.cs # src/Umbraco.Core/Scoping/ScopeProvider.cs # src/Umbraco.Core/Sync/DatabaseServerMessenger.cs # src/Umbraco.Core/Templates/HtmlUrlParser.cs # src/Umbraco.Core/UriExtensions.cs # src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs # src/Umbraco.Examine.Lucene/UmbracoExamineIndex.cs # src/Umbraco.Infrastructure/Examine/IndexRebuilder.cs # src/Umbraco.Infrastructure/Manifest/DataEditorConverter.cs # src/Umbraco.Infrastructure/Manifest/ManifestParser.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs # src/Umbraco.Infrastructure/Migrations/MigrationPlan.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DataTypeMigration.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/DropDownPropertyEditorsMigration.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/MergeDateAndDateTimePropertyEditor.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/V_8_0_0/RadioAndCheckboxPropertyEditorsMigration.cs # src/Umbraco.Infrastructure/Packaging/PackageDataInstallation.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs # src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs # src/Umbraco.Infrastructure/Persistence/UmbracoDatabase.cs # src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseFactory.cs # src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs # src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorPastedImages.cs # src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/GridValueConverter.cs # src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs # src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/JsonValueConverter.cs # src/Umbraco.Infrastructure/PublishedCache/PublishedContentTypeCache.cs # src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs # src/Umbraco.Infrastructure/Scoping/Scope.cs # src/Umbraco.Infrastructure/Search/ExamineNotificationHandler.cs # src/Umbraco.Infrastructure/Services/Implement/ContentService.cs # src/Umbraco.Infrastructure/Services/Implement/LocalizedTextService.cs # src/Umbraco.Infrastructure/Services/Implement/LocalizedTextServiceFileSources.cs # src/Umbraco.Infrastructure/Services/Implement/MediaService.cs # src/Umbraco.Infrastructure/Services/Implement/NotificationService.cs # src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs # src/Umbraco.ModelsBuilder.Embedded/Compose/ModelsBuilderComposer.cs # src/Umbraco.ModelsBuilder.Embedded/LiveModelsProvider.cs # src/Umbraco.PublishedCache.NuCache/ContentStore.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentEventsTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Mapping/MappingTests.cs # src/Umbraco.Tests.UnitTests/Umbraco.ModelsBuilder.Embedded/BuilderTests.cs # src/Umbraco.Tests/Composing/TypeLoaderTests.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/DictionaryPublishedContent.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/LegacyBackgroundTask/BackgroundTaskRunner.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/PreviewContent.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedMediaCache.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStore.cs # src/Umbraco.Tests/LegacyXmlPublishedCache/XmlStoreFilePersister.cs # src/Umbraco.Tests/Services/ContentServicePerformanceTest.cs # src/Umbraco.Tests/Services/PerformanceTests.cs # src/Umbraco.Tests/TestHelpers/ConsoleLogger.cs # src/Umbraco.Tests/Testing/TestingTests/MockTests.cs # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/ContentController.cs # src/Umbraco.Web.BackOffice/Controllers/DashboardController.cs # src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs # src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs # src/Umbraco.Web.BackOffice/PropertyEditors/RteEmbedController.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.BackOffice/Trees/ContentTreeControllerBase.cs # src/Umbraco.Web.Common/Extensions/FormCollectionExtensions.cs # src/Umbraco.Web.Common/Install/InstallApiController.cs # src/Umbraco.Web.Common/Macros/MacroRenderer.cs # src/Umbraco.Web.Common/ModelsBuilder/PureLiveModelFactory.cs # src/Umbraco.Web.UI.Client/package-lock.json # src/Umbraco.Web.UI.Client/src/views/memberTypes/copy.controller.js # src/Umbraco.Web.UI.Client/src/views/memberTypes/copy.html # src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/config/splashes/noNodes.aspx # src/Umbraco.Web/AspNet/AspNetHttpContextAccessor.cs # src/Umbraco.Web/Cache/DistributedCacheBinder.cs # src/Umbraco.Web/Cache/DistributedCacheBinder_Handlers.cs # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Binders/ContentModelBinderHelper.cs # src/Umbraco.Web/Editors/ContentControllerBase.cs # src/Umbraco.Web/Editors/ContentTypeController.cs # src/Umbraco.Web/Editors/DictionaryController.cs # src/Umbraco.Web/Editors/MemberTypeController.cs # src/Umbraco.Web/Editors/PasswordChanger.cs # src/Umbraco.Web/Editors/RelationTypeController.cs # src/Umbraco.Web/Editors/TinyMceController.cs # src/Umbraco.Web/HealthCheck/Checks/Security/HttpsCheck.cs # src/Umbraco.Web/HtmlHelperRenderExtensions.cs # src/Umbraco.Web/HttpUrlHelperExtensions.cs # src/Umbraco.Web/HybridEventMessagesAccessor.cs # src/Umbraco.Web/ImageCropperTemplateExtensions.cs # src/Umbraco.Web/JavaScript/ClientDependencyConfiguration.cs # src/Umbraco.Web/Mvc/RenderMvcController.cs # src/Umbraco.Web/PublishedCache/NuCache/DataSource/DatabaseDataSource.cs # src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs # src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs # src/Umbraco.Web/Routing/ContentFinderByIdPath.cs # src/Umbraco.Web/Routing/ContentFinderByRedirectUrl.cs # src/Umbraco.Web/Routing/ContentFinderByUrl.cs # src/Umbraco.Web/Routing/ContentFinderByUrlAlias.cs # src/Umbraco.Web/Routing/ContentFinderByUrlAndTemplate.cs # src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs # src/Umbraco.Web/Routing/PublishedRouter.cs # src/Umbraco.Web/Runtime/WebInitialComposer.cs # src/Umbraco.Web/Scheduling/KeepAlive.cs # src/Umbraco.Web/Scheduling/ScheduledPublishing.cs # src/Umbraco.Web/Scheduling/TempFileCleanup.cs # src/Umbraco.Web/Security/MembershipHelper.cs # src/Umbraco.Web/Security/Providers/UmbracoMembershipProvider.cs # src/Umbraco.Web/Trees/MemberTreeController.cs # src/Umbraco.Web/Trees/MemberTypeAndGroupTreeControllerBase.cs # src/Umbraco.Web/Trees/MemberTypeTreeController.cs # src/Umbraco.Web/UmbracoApplicationBase.cs # src/Umbraco.Web/UmbracoInjectedModule.cs # src/Umbraco.Web/UmbracoModule.cs # src/Umbraco.Web/WebApi/AngularJsonMediaTypeFormatter.cs # src/Umbraco.Web/WebApi/Filters/FileUploadCleanupFilterAttribute.cs # src/Umbraco.Web/WebApi/UnhandledExceptionLogger.cs
2021-04-20 19:34:18 +02:00
IUmbracoMapper umbracoMapper,
IOptions<GlobalSettings> globalSettings,
IBackOfficeUserManager backOfficeUserManager,
ILoggerFactory loggerFactory,
2020-10-23 14:18:53 +11:00
LinkGenerator linkGenerator,
IBackOfficeExternalLoginProviders externalLogins,
2021-02-20 19:16:31 +00:00
UserEditorAuthorizationHelper userEditorAuthorizationHelper,
IPasswordChanger<BackOfficeIdentityUser> passwordChanger)
{
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
_mediaFileManager = mediaFileManager;
_contentSettings = contentSettings.Value;
_hostingEnvironment = hostingEnvironment;
_sqlContext = sqlContext;
_imageUrlGenerator = imageUrlGenerator;
_securitySettings = securitySettings.Value;
2020-05-20 11:42:23 +02:00
_emailSender = emailSender;
2021-02-26 14:52:54 +00:00
_backofficeSecurityAccessor = backofficeSecurityAccessor;
_appCaches = appCaches;
_shortStringHelper = shortStringHelper;
_userService = userService;
_localizedTextService = localizedTextService;
_umbracoMapper = umbracoMapper;
_globalSettings = globalSettings.Value;
2020-10-23 14:18:53 +11:00
_userManager = backOfficeUserManager;
_loggerFactory = loggerFactory;
_linkGenerator = linkGenerator;
2020-10-23 14:18:53 +11:00
_externalLogins = externalLogins;
_userEditorAuthorizationHelper = userEditorAuthorizationHelper;
2021-02-20 19:16:31 +00:00
_passwordChanger = passwordChanger;
2020-10-23 14:18:53 +11:00
_logger = _loggerFactory.CreateLogger<UsersController>();
}
2017-09-12 16:22:16 +02:00
/// <summary>
2020-10-05 20:48:38 +02:00
/// Returns a list of the sizes of gravatar URLs for the user or null if the gravatar server cannot be reached
2017-09-12 16:22:16 +02:00
/// </summary>
/// <returns></returns>
public ActionResult<string[]> GetCurrentUserAvatarUrls()
2017-09-12 16:22:16 +02:00
{
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
var urls = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator);
2017-09-12 16:22:16 +02:00
if (urls == null)
return new ValidationErrorResult("Could not access Gravatar endpoint");
2017-09-12 16:22:16 +02:00
return urls;
}
[AppendUserModifiedHeader("id")]
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public IActionResult PostSetAvatar(int id, IList<IFormFile> file)
2017-09-12 16:22:16 +02:00
{
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
return PostSetAvatarInternal(file, _userService, _appCaches.RuntimeCache, _mediaFileManager, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, id);
2017-09-12 16:22:16 +02:00
}
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
internal static IActionResult PostSetAvatarInternal(IList<IFormFile> files, IUserService userService, IAppCache cache, MediaFileManager mediaFileManager, IShortStringHelper shortStringHelper, ContentSettings contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, int id)
2017-09-12 16:22:16 +02:00
{
if (files is null)
2017-09-12 16:22:16 +02:00
{
return new UnsupportedMediaTypeResult();
2017-09-12 16:22:16 +02:00
}
var root = hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempFileUploads);
2017-09-12 16:22:16 +02:00
//ensure it exists
Directory.CreateDirectory(root);
//must have a file
if (files.Count == 0)
2017-09-12 16:22:16 +02:00
{
return new NotFoundResult();
2017-09-12 16:22:16 +02:00
}
var user = userService.GetUserById(id);
if (user == null)
return new NotFoundResult();
2017-09-12 16:22:16 +02:00
if (files.Count > 1)
return new ValidationErrorResult("The request was not formatted correctly, only one file can be attached to the request");
2017-09-12 16:22:16 +02:00
//get the file info
var file = files.First();
var fileName = file.FileName.Trim(new[] { '\"' }).TrimEnd();
var safeFileName = fileName.ToSafeFileName(shortStringHelper);
2017-09-12 16:22:16 +02:00
var ext = safeFileName.Substring(safeFileName.LastIndexOf('.') + 1).ToLower();
2020-03-12 15:30:22 +01:00
if (contentSettings.DisallowedUploadFiles.Contains(ext) == false)
2017-09-12 16:22:16 +02:00
{
//generate a path of known data, we don't want this path to be guessable
user.Avatar = "UserAvatars/" + (user.Id + safeFileName).GenerateHash<SHA1>() + "." + ext;
2017-09-12 16:22:16 +02:00
using (var fs = file.OpenReadStream())
2017-09-12 16:22:16 +02:00
{
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
mediaFileManager.FileSystem.AddFile(user.Avatar, fs, true);
2017-09-12 16:22:16 +02:00
}
userService.Save(user);
}
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
return new OkObjectResult(user.GetUserAvatarUrls(cache, mediaFileManager, imageUrlGenerator));
2017-09-12 16:22:16 +02:00
}
[AppendUserModifiedHeader("id")]
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public ActionResult<string[]> PostClearAvatar(int id)
2017-09-12 16:22:16 +02:00
{
var found = _userService.GetUserById(id);
2017-09-12 16:22:16 +02:00
if (found == null)
return NotFound();
2017-09-12 16:22:16 +02:00
var filePath = found.Avatar;
//if the filePath is already null it will mean that the user doesn't have a custom avatar and their gravatar is currently
2017-09-19 15:51:47 +02:00
//being used (if they have one). This means they want to remove their gravatar too which we can do by setting a special value
2017-09-12 16:22:16 +02:00
//for the avatar.
if (filePath.IsNullOrWhiteSpace() == false)
{
found.Avatar = null;
}
else
{
//set a special value to indicate to not have any avatar
found.Avatar = "none";
}
_userService.Save(found);
2017-09-12 16:22:16 +02:00
if (filePath.IsNullOrWhiteSpace() == false)
{
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
if (_mediaFileManager.FileSystem.FileExists(filePath))
_mediaFileManager.FileSystem.DeleteFile(filePath);
2017-09-12 16:22:16 +02:00
}
Netcore: File systems rework (#10181) * Allow IMediaFileSystem to be replace in the DI, or registered with inner filesystem * Remove GetFileSystem from Filesystems It was only used by tests. * Make MediaFileSystem inherit from PhysicalFileSystem directly * Remove FileSystemWrapper * Remove inner filesystem from MediaFileSystem * Add MediaFileManager and bare minimum to make it testable * Remove MediaFileSystem * Fix unit tests using MediaFileManager * Remove IFileSystem and rely only on FileSystem * Hide dangerous methods in FileSystems and do some cleaning * Apply stylecop warnings to MediaFileManager * Add FilesystemsCreator to Tests.Common This allows you to create an instance if FileSystems with your own specified IFileSystem for testing purposes outside our own test suite. * Allow the stylesheet filesystem to be replaced. * Fix tests * Don't save stylesheetWrapper in a temporary var * refactor(FileSystems): change how stylesheet filesystem is registered * fix(FileSystems): unable to overwrite media filesystem SetMediaFileSystem added the MediaManager as a Singleton instead of replacing the existing instance. * fix(FileSystems): calling AddFileSystems replaces MediaManager When calling AddFileSystems after SetMediaFileSystem the MediaManager gets replaced by the default PhysicalFileSystem, so instead of calling SetMediaFileSystem in AddFileSystems we now call TrySetMediaFileSystem instead. This method will not replace any existing instance of the MediaManager if there's already a MediaManager registered. * Use SetMediaFileSystem instead of TrySet, and rename AddFilesystems to ConfigureFileSystems Also don't call AddFileSystems again in ConfigureFilesystems * Don't wrap CSS filesystem twice * Add CreateShadowWrapperInternal to avoid casting * Throw UnauthorizedAccessException isntead of InvalidOperationException * Remove ResetShadowId Co-authored-by: Rasmus John Pedersen <mail@rjp.dk>
2021-04-27 09:52:17 +02:00
return found.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator);
2017-09-12 16:22:16 +02:00
}
/// <summary>
/// Gets a user by Id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public ActionResult<UserDisplay> GetById(int id)
2017-09-12 16:22:16 +02:00
{
var user = _userService.GetUserById(id);
2017-09-12 16:22:16 +02:00
if (user == null)
{
return NotFound();
2017-09-12 16:22:16 +02:00
}
var result = _umbracoMapper.Map<IUser, UserDisplay>(user);
2017-09-19 15:51:47 +02:00
return result;
2017-09-12 16:22:16 +02:00
}
/// <summary>
/// Get users by integer ids
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[OutgoingEditorModelEvent]
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public ActionResult<IEnumerable<UserDisplay>> GetByIds([FromJsonPath]int[] ids)
{
if (ids == null)
{
return NotFound();
}
if (ids.Length == 0)
return Enumerable.Empty<UserDisplay>().ToList();
var users = _userService.GetUsersById(ids);
if (users == null)
{
return NotFound();
}
var result = _umbracoMapper.MapEnumerable<IUser, UserDisplay>(users);
return result;
}
2017-09-12 16:22:16 +02:00
/// <summary>
/// Returns a paged users collection
/// </summary>
/// <param name="pageNumber"></param>
/// <param name="pageSize"></param>
/// <param name="orderBy"></param>
/// <param name="orderDirection"></param>
/// <param name="userGroups"></param>
/// <param name="userStates"></param>
/// <param name="filter"></param>
/// <returns></returns>
public PagedUserResult GetPagedUsers(
int pageNumber = 1,
int pageSize = 10,
string orderBy = "username",
Direction orderDirection = Direction.Ascending,
[FromQuery]string[] userGroups = null,
[FromQuery]UserState[] userStates = null,
2017-09-12 16:22:16 +02:00
string filter = "")
{
2017-09-19 15:51:47 +02:00
//following the same principle we had in previous versions, we would only show admins to admins, see
// https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/umbraco.presentation/umbraco/Trees/loadUsers.cs#L91
// so to do that here, we'll need to check if this current user is an admin and if not we should exclude all user who are
// also admins
var hideDisabledUsers = _securitySettings.HideDisabledUsersInBackOffice;
2017-09-19 15:51:47 +02:00
var excludeUserGroups = new string[0];
2021-02-26 14:52:54 +00:00
var isAdmin = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.IsAdmin();
2017-09-19 15:51:47 +02:00
if (isAdmin == false)
{
//this user is not an admin so in that case we need to exclude all admin users
2017-09-19 15:51:47 +02:00
excludeUserGroups = new[] {Constants.Security.AdminGroupAlias};
}
var filterQuery = _sqlContext.Query<IUser>();
2017-09-19 15:51:47 +02:00
2021-02-26 14:52:54 +00:00
if (!_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.IsSuper())
2017-09-19 15:51:47 +02:00
{
2019-01-21 15:57:48 +01:00
// only super can see super - but don't use IsSuper, cannot be mapped to SQL
2018-03-16 09:06:44 +01:00
//filterQuery.Where(x => !x.IsSuper());
filterQuery.Where(x => x.Id != Constants.Security.SuperUserId);
2017-09-19 15:51:47 +02:00
}
if (filter.IsNullOrWhiteSpace() == false)
{
filterQuery.Where(x => x.Name.Contains(filter) || x.Username.Contains(filter));
}
if (hideDisabledUsers)
{
if (userStates == null || userStates.Any() == false)
{
userStates = new[] { UserState.Active, UserState.Invited, UserState.LockedOut, UserState.Inactive };
}
}
2017-09-12 16:22:16 +02:00
long pageIndex = pageNumber - 1;
long total;
var result = _userService.GetAll(pageIndex, pageSize, out total, orderBy, orderDirection, userStates, userGroups, excludeUserGroups, filterQuery);
2017-09-19 15:51:47 +02:00
2017-09-12 16:22:16 +02:00
var paged = new PagedUserResult(total, pageNumber, pageSize)
{
Items = _umbracoMapper.MapEnumerable<IUser, UserBasic>(result),
UserStates = _userService.GetUserStates()
2017-09-12 16:22:16 +02:00
};
return paged;
}
/// <summary>
/// Creates a new user
/// </summary>
/// <param name="userSave"></param>
/// <returns></returns>
public async Task<ActionResult<UserDisplay>> PostCreateUser(UserInvite userSave)
2017-09-12 16:22:16 +02:00
{
if (userSave == null) throw new ArgumentNullException("userSave");
if (ModelState.IsValid == false)
{
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
2017-09-12 16:22:16 +02:00
}
if (_securitySettings.UsernameIsEmail)
2017-09-12 16:22:16 +02:00
{
2017-09-19 15:51:47 +02:00
//ensure they are the same if we're using it
userSave.Username = userSave.Email;
}
else
{
//first validate the username if were showing it
CheckUniqueUsername(userSave.Username, null);
}
CheckUniqueEmail(userSave.Email, null);
if (ModelState.IsValid == false)
{
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
}
2017-09-19 15:51:47 +02:00
//Perform authorization here to see if the current user can actually save this user with the info being requested
2021-02-26 14:52:54 +00:00
var canSaveUser = _userEditorAuthorizationHelper.IsAuthorized(_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser, null, null, null, userSave.UserGroups);
2017-09-19 15:51:47 +02:00
if (canSaveUser == false)
{
return Unauthorized(canSaveUser.Result);
2017-09-12 16:22:16 +02:00
}
//we want to create the user with the UserManager, this ensures the 'empty' (special) password
//format is applied without us having to duplicate that logic
var identityUser = BackOfficeIdentityUser.CreateNew(_globalSettings, userSave.Username, userSave.Email, _globalSettings.DefaultUILanguage);
2017-09-12 16:22:16 +02:00
identityUser.Name = userSave.Name;
2020-10-23 14:18:53 +11:00
var created = await _userManager.CreateAsync(identityUser);
2017-09-12 16:22:16 +02:00
if (created.Succeeded == false)
{
return ValidationErrorResult.CreateNotificationValidationErrorResult(created.Errors.ToErrorMessage());
2017-09-12 16:22:16 +02:00
}
string resetPassword;
2020-10-23 14:18:53 +11:00
var password = _userManager.GeneratePassword();
2017-09-12 16:22:16 +02:00
2020-10-23 14:18:53 +11:00
var result = await _userManager.AddPasswordAsync(identityUser, password);
if (result.Succeeded == false)
{
return ValidationErrorResult.CreateNotificationValidationErrorResult(created.Errors.ToErrorMessage());
2017-09-12 16:22:16 +02:00
}
resetPassword = password;
2017-09-12 16:22:16 +02:00
//now re-look the user back up which will now exist
var user = _userService.GetByEmail(userSave.Email);
2017-09-12 16:22:16 +02:00
//map the save info over onto the user
user = _umbracoMapper.Map(userSave, user);
2017-09-12 16:22:16 +02:00
//since the back office user is creating this user, they will be set to approved
user.IsApproved = true;
_userService.Save(user);
2017-09-12 16:22:16 +02:00
var display = _umbracoMapper.Map<UserDisplay>(user);
2017-09-12 16:22:16 +02:00
display.ResetPasswordValue = resetPassword;
return display;
}
/// <summary>
/// Invites a user
/// </summary>
2017-09-19 15:51:47 +02:00
/// <param name="userSave"></param>
2017-09-12 16:22:16 +02:00
/// <returns></returns>
/// <remarks>
/// This will email the user an invite and generate a token that will be validated in the email
/// </remarks>
2020-10-23 14:18:53 +11:00
public async Task<ActionResult<UserDisplay>> PostInviteUser(UserInvite userSave)
2017-09-12 16:22:16 +02:00
{
if (userSave == null) throw new ArgumentNullException("userSave");
if (userSave.Message.IsNullOrWhiteSpace())
ModelState.AddModelError("Message", "Message cannot be empty");
2017-09-19 15:51:47 +02:00
IUser user;
if (_securitySettings.UsernameIsEmail)
2017-09-12 16:22:16 +02:00
{
2017-09-19 15:51:47 +02:00
//ensure it's the same
userSave.Username = userSave.Email;
}
else
{
//first validate the username if we're showing it
var userResult = CheckUniqueUsername(userSave.Username, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);
if (!(userResult.Result is null))
{
return userResult.Result;
}
user = userResult.Value;
Merge branch 'netcore/dev' into netcore/task/6973-migrating-authenticationcontroller # Conflicts: # src/Umbraco.Core/Constants-Security.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeClaimsPrincipalFactory.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/DenyLocalLoginAuthorizationAttribute.cs # src/Umbraco.Web.BackOffice/Controllers/UsersController.cs # src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.Common/Security/ExternalSignInAutoLinkOptions.cs # src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js # src/Umbraco.Web.UI.Client/src/common/interceptors/requiredheaders.interceptor.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Filters/IsCurrentUserModelFilterAttribute.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/AuthenticationOptionsExtensions.cs # src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
2020-10-23 10:10:02 +11:00
}
user = CheckUniqueEmail(userSave.Email, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);
if (ModelState.IsValid == false)
{
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
}
Merge branch 'netcore/dev' into netcore/task/6973-migrating-authenticationcontroller # Conflicts: # src/Umbraco.Core/Constants-Security.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeClaimsPrincipalFactory.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/DenyLocalLoginAuthorizationAttribute.cs # src/Umbraco.Web.BackOffice/Controllers/UsersController.cs # src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.Common/Security/ExternalSignInAutoLinkOptions.cs # src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js # src/Umbraco.Web.UI.Client/src/common/interceptors/requiredheaders.interceptor.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Filters/IsCurrentUserModelFilterAttribute.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/AuthenticationOptionsExtensions.cs # src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
2020-10-23 10:10:02 +11:00
if (!_emailSender.CanSendRequiredEmail())
Merge branch 'netcore/dev' into netcore/task/6973-migrating-authenticationcontroller # Conflicts: # src/Umbraco.Core/Constants-Security.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeClaimsPrincipalFactory.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/DenyLocalLoginAuthorizationAttribute.cs # src/Umbraco.Web.BackOffice/Controllers/UsersController.cs # src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.Common/Security/ExternalSignInAutoLinkOptions.cs # src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js # src/Umbraco.Web.UI.Client/src/common/interceptors/requiredheaders.interceptor.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Filters/IsCurrentUserModelFilterAttribute.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/AuthenticationOptionsExtensions.cs # src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
2020-10-23 10:10:02 +11:00
{
2020-10-23 14:18:53 +11:00
return new ValidationErrorResult("No Email server is configured");
2017-09-19 15:51:47 +02:00
}
//Perform authorization here to see if the current user can actually save this user with the info being requested
2021-02-26 14:52:54 +00:00
var canSaveUser = _userEditorAuthorizationHelper.IsAuthorized(_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser, user, null, null, userSave.UserGroups);
2017-09-19 15:51:47 +02:00
if (canSaveUser == false)
{
2020-10-23 14:18:53 +11:00
return new ValidationErrorResult(canSaveUser.Result, StatusCodes.Status401Unauthorized);
2017-09-12 16:22:16 +02:00
}
if (user == null)
{
//we want to create the user with the UserManager, this ensures the 'empty' (special) password
//format is applied without us having to duplicate that logic
var identityUser = BackOfficeIdentityUser.CreateNew(_globalSettings, userSave.Username, userSave.Email, _globalSettings.DefaultUILanguage);
2017-09-12 16:22:16 +02:00
identityUser.Name = userSave.Name;
2020-10-23 14:18:53 +11:00
var created = await _userManager.CreateAsync(identityUser);
2017-09-12 16:22:16 +02:00
if (created.Succeeded == false)
{
2020-10-23 14:18:53 +11:00
return ValidationErrorResult.CreateNotificationValidationErrorResult(created.Errors.ToErrorMessage());
2017-09-12 16:22:16 +02:00
}
//now re-look the user back up
user = _userService.GetByEmail(userSave.Email);
2017-09-12 16:22:16 +02:00
}
//map the save info over onto the user
user = _umbracoMapper.Map(userSave, user);
2017-09-12 16:22:16 +02:00
//ensure the invited date is set
user.InvitedDate = DateTime.Now;
Merge branch 'netcore/dev' into netcore/task/6973-migrating-authenticationcontroller # Conflicts: # src/Umbraco.Core/Constants-Security.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeClaimsPrincipalFactory.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/DenyLocalLoginAuthorizationAttribute.cs # src/Umbraco.Web.BackOffice/Controllers/UsersController.cs # src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.Common/Security/ExternalSignInAutoLinkOptions.cs # src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js # src/Umbraco.Web.UI.Client/src/common/interceptors/requiredheaders.interceptor.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Filters/IsCurrentUserModelFilterAttribute.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/AuthenticationOptionsExtensions.cs # src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
2020-10-23 10:10:02 +11:00
//Save the updated user (which will process the user groups too)
_userService.Save(user);
var display = _umbracoMapper.Map<UserDisplay>(user);
2017-09-12 16:22:16 +02:00
//send the email
await SendUserInviteEmailAsync(display, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Name, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Email, user, userSave.Message);
Merge branch 'netcore/dev' into netcore/task/6973-migrating-authenticationcontroller # Conflicts: # src/Umbraco.Core/Constants-Security.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeClaimsPrincipalFactory.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/DenyLocalLoginAuthorizationAttribute.cs # src/Umbraco.Web.BackOffice/Controllers/UsersController.cs # src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.Common/Security/ExternalSignInAutoLinkOptions.cs # src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js # src/Umbraco.Web.UI.Client/src/common/interceptors/requiredheaders.interceptor.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Filters/IsCurrentUserModelFilterAttribute.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/AuthenticationOptionsExtensions.cs # src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
2020-10-23 10:10:02 +11:00
display.AddSuccessNotification(_localizedTextService.Localize("speechBubbles/resendInviteHeader"), _localizedTextService.Localize("speechBubbles/resendInviteSuccess", new[] { user.Name }));
2017-09-12 16:22:16 +02:00
return display;
}
2017-09-19 15:51:47 +02:00
private IUser CheckUniqueEmail(string email, Func<IUser, bool> extraCheck)
{
var user = _userService.GetByEmail(email);
2017-09-19 15:51:47 +02:00
if (user != null && (extraCheck == null || extraCheck(user)))
{
ModelState.AddModelError("Email", "A user with the email already exists");
}
return user;
}
private ActionResult<IUser> CheckUniqueUsername(string username, Func<IUser, bool> extraCheck)
2017-09-19 15:51:47 +02:00
{
var user = _userService.GetByUsername(username);
2017-09-19 15:51:47 +02:00
if (user != null && (extraCheck == null || extraCheck(user)))
{
ModelState.AddModelError(
_securitySettings.UsernameIsEmail ? "Email" : "Username",
2017-09-19 15:51:47 +02:00
"A user with the username already exists");
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
2017-09-19 15:51:47 +02:00
}
return new ActionResult<IUser>(user);
2017-09-19 15:51:47 +02:00
}
2017-09-12 16:22:16 +02:00
2018-03-27 10:04:07 +02:00
private async Task SendUserInviteEmailAsync(UserBasic userDisplay, string from, string fromEmail, IUser to, string message)
2017-09-12 16:22:16 +02:00
{
2020-10-23 14:18:53 +11:00
var user = await _userManager.FindByIdAsync(((int) userDisplay.Id).ToString());
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
2017-09-12 16:22:16 +02:00
var inviteToken = string.Format("{0}{1}{2}",
(int)userDisplay.Id,
WebUtility.UrlEncode("|"),
token.ToUrlBase64());
2020-10-05 20:48:38 +02:00
// Get an mvc helper to get the URL
var action = _linkGenerator.GetPathByAction(
nameof(BackOfficeController.VerifyInvite),
ControllerExtensions.GetControllerName<BackOfficeController>(),
new
2017-09-12 16:22:16 +02:00
{
area = Constants.Web.Mvc.BackOfficeArea,
2017-09-12 16:22:16 +02:00
invite = inviteToken
});
// Construct full URL using configured application URL (which will fall back to request)
var applicationUri = _hostingEnvironment.ApplicationMainUrl;
2017-09-12 16:22:16 +02:00
var inviteUri = new Uri(applicationUri, action);
var emailSubject = _localizedTextService.Localize("user/inviteEmailCopySubject",
2017-09-12 16:22:16 +02:00
//Ensure the culture of the found user is used for the email!
UmbracoUserExtensions.GetUserCulture(to.Language, _localizedTextService, _globalSettings));
var emailBody = _localizedTextService.Localize("user/inviteEmailCopyFormat",
2017-09-12 16:22:16 +02:00
//Ensure the culture of the found user is used for the email!
UmbracoUserExtensions.GetUserCulture(to.Language, _localizedTextService, _globalSettings),
2018-03-27 10:04:07 +02:00
new[] { userDisplay.Name, from, message, inviteUri.ToString(), fromEmail });
2017-09-12 16:22:16 +02:00
var mailMessage = new EmailMessage(fromEmail, to.Email, emailSubject, emailBody, true);
2017-09-12 16:22:16 +02:00
await _emailSender.SendAsync(mailMessage, true);
2017-09-12 16:22:16 +02:00
}
/// <summary>
/// Saves a user
/// </summary>
/// <param name="userSave"></param>
/// <returns></returns>
[OutgoingEditorModelEvent]
public ActionResult<UserDisplay> PostSaveUser(UserSave userSave)
2017-09-12 16:22:16 +02:00
{
if (userSave == null) throw new ArgumentNullException(nameof(userSave));
2017-09-12 16:22:16 +02:00
if (ModelState.IsValid == false)
{
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
2017-09-12 16:22:16 +02:00
}
var intId = userSave.Id.TryConvertTo<int>();
if (intId.Success == false)
return NotFound();
2017-09-12 16:22:16 +02:00
var found = _userService.GetUserById(intId.Result);
2017-09-12 16:22:16 +02:00
if (found == null)
return NotFound();
2017-09-12 16:22:16 +02:00
2017-09-19 15:51:47 +02:00
//Perform authorization here to see if the current user can actually save this user with the info being requested
2021-02-26 14:52:54 +00:00
var canSaveUser = _userEditorAuthorizationHelper.IsAuthorized(_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser, found, userSave.StartContentIds, userSave.StartMediaIds, userSave.UserGroups);
2017-09-19 15:51:47 +02:00
if (canSaveUser == false)
{
return Unauthorized(canSaveUser.Result);
2017-09-19 15:51:47 +02:00
}
2017-09-12 16:22:16 +02:00
var hasErrors = false;
Merge branch 'netcore/dev' into netcore/task/6973-migrating-authenticationcontroller # Conflicts: # src/Umbraco.Core/Constants-Security.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeClaimsPrincipalFactory.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/DenyLocalLoginAuthorizationAttribute.cs # src/Umbraco.Web.BackOffice/Controllers/UsersController.cs # src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.Common/Security/ExternalSignInAutoLinkOptions.cs # src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js # src/Umbraco.Web.UI.Client/src/common/interceptors/requiredheaders.interceptor.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Filters/IsCurrentUserModelFilterAttribute.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/AuthenticationOptionsExtensions.cs # src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
2020-10-23 10:10:02 +11:00
// we need to check if there's any Deny Local login providers present, if so we need to ensure that the user's email address cannot be changed
2020-10-23 14:18:53 +11:00
var hasDenyLocalLogin = _externalLogins.HasDenyLocalLogin();
Merge branch 'netcore/dev' into netcore/task/6973-migrating-authenticationcontroller # Conflicts: # src/Umbraco.Core/Constants-Security.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeClaimsPrincipalFactory.cs # src/Umbraco.Infrastructure/BackOffice/BackOfficeUserManager.cs # src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs # src/Umbraco.Tests.AcceptanceTest/cypress/integration/Tour/backofficeTour.ts # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.BackOffice/Controllers/DenyLocalLoginAuthorizationAttribute.cs # src/Umbraco.Web.BackOffice/Controllers/UsersController.cs # src/Umbraco.Web.BackOffice/Extensions/HtmlHelperBackOfficeExtensions.cs # src/Umbraco.Web.BackOffice/Services/IconService.cs # src/Umbraco.Web.Common/Security/ExternalSignInAutoLinkOptions.cs # src/Umbraco.Web.UI.Client/src/common/interceptors/_module.js # src/Umbraco.Web.UI.Client/src/common/interceptors/requiredheaders.interceptor.js # src/Umbraco.Web.UI.Client/src/views/common/overlays/user/user.controller.js # src/Umbraco.Web.UI.NetCore/umbraco/UmbracoBackOffice/Default.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/Views/AuthorizeUpgrade.cshtml # src/Umbraco.Web/Editors/AuthenticationController.cs # src/Umbraco.Web/Editors/BackOfficeController.cs # src/Umbraco.Web/Editors/Filters/IsCurrentUserModelFilterAttribute.cs # src/Umbraco.Web/Security/AppBuilderExtensions.cs # src/Umbraco.Web/Security/AuthenticationOptionsExtensions.cs # src/Umbraco.Web/UmbracoDefaultOwinStartup.cs
2020-10-23 10:10:02 +11:00
if (hasDenyLocalLogin)
{
userSave.Email = found.Email; // it cannot change, this would only happen if people are mucking around with the request
}
var existing = _userService.GetByEmail(userSave.Email);
2017-09-12 16:22:16 +02:00
if (existing != null && existing.Id != userSave.Id)
{
ModelState.AddModelError("Email", "A user with the email already exists");
hasErrors = true;
}
existing = _userService.GetByUsername(userSave.Username);
2017-09-12 16:22:16 +02:00
if (existing != null && existing.Id != userSave.Id)
{
ModelState.AddModelError("Username", "A user with the username already exists");
hasErrors = true;
}
// going forward we prefer to align usernames with email, so we should cross-check to make sure
// the email or username isn't somehow being used by anyone.
existing = _userService.GetByEmail(userSave.Username);
2017-09-12 16:22:16 +02:00
if (existing != null && existing.Id != userSave.Id)
{
ModelState.AddModelError("Username", "A user using this as their email already exists");
hasErrors = true;
}
existing = _userService.GetByUsername(userSave.Email);
2017-09-12 16:22:16 +02:00
if (existing != null && existing.Id != userSave.Id)
{
ModelState.AddModelError("Email", "A user using this as their username already exists");
hasErrors = true;
}
2019-09-30 22:26:21 +01:00
// if the found user has their email for username, we want to keep this synced when changing the email.
2017-09-12 16:22:16 +02:00
// we have already cross-checked above that the email isn't colliding with anything, so we can safely assign it here.
if (_securitySettings.UsernameIsEmail && found.Username == found.Email && userSave.Username != userSave.Email)
2017-09-12 16:22:16 +02:00
{
userSave.Username = userSave.Email;
}
if (hasErrors)
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
2017-09-12 16:22:16 +02:00
//merge the save data onto the user
var user = _umbracoMapper.Map(userSave, found);
2017-09-12 16:22:16 +02:00
_userService.Save(user);
2017-09-12 16:22:16 +02:00
var display = _umbracoMapper.Map<UserDisplay>(user);
2017-09-12 16:22:16 +02:00
Merge remote-tracking branch 'origin/v8/dev' into netcore/feature/merge-v8-18-01-2021 # Conflicts: # .gitignore # build/NuSpecs/UmbracoCms.Core.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Configuration/UmbracoSettings/BackOfficeElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs # src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs # src/Umbraco.Core/IO/SystemFiles.cs # src/Umbraco.Core/Models/ContentBase.cs # src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs # src/Umbraco.Core/Persistence/UmbracoDatabaseExtensions.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/RuntimeOptions.cs # src/Umbraco.Core/RuntimeState.cs # src/Umbraco.Core/Telemetry/TelemetryMarkerComponent.cs # src/Umbraco.Core/Telemetry/TelemetryMarkerComposer.cs # src/Umbraco.Examine/Umbraco.Examine.csproj # src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs # src/Umbraco.Infrastructure/Install/InstallStepCollection.cs # src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs # src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs # src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs # src/Umbraco.Tests/Runtimes/StandaloneTests.cs # src/Umbraco.Tests/Testing/TestDatabase.cs # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.UI.Client/src/installer/steps/database.controller.js # src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/TextString.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml # src/Umbraco.Web.UI/config/umbracoSettings.Release.config # src/Umbraco.Web/Composing/CompositionExtensions/Installer.cs # src/Umbraco.Web/Editors/PreviewController.cs # src/Umbraco.Web/Editors/UsersController.cs # src/Umbraco.Web/JavaScript/PreviewInitialize.js # src/Umbraco.Web/Telemetry/TelemetryComponent.cs # src/Umbraco.Web/UmbracoApplication.cs
2021-01-18 15:40:22 +01:00
// determine if the user has changed their own language;
2021-02-26 14:52:54 +00:00
var currentUser = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
Merge remote-tracking branch 'origin/v8/dev' into netcore/feature/merge-v8-18-01-2021 # Conflicts: # .gitignore # build/NuSpecs/UmbracoCms.Core.nuspec # src/SolutionInfo.cs # src/Umbraco.Core/Configuration/UmbracoSettings/BackOfficeElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/ContentElement.cs # src/Umbraco.Core/Configuration/UmbracoSettings/IBackOfficeSection.cs # src/Umbraco.Core/Configuration/UmbracoSettings/IContentSection.cs # src/Umbraco.Core/IO/SystemFiles.cs # src/Umbraco.Core/Models/ContentBase.cs # src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs # src/Umbraco.Core/Persistence/UmbracoDatabaseExtensions.cs # src/Umbraco.Core/Runtime/CoreRuntime.cs # src/Umbraco.Core/RuntimeOptions.cs # src/Umbraco.Core/RuntimeState.cs # src/Umbraco.Core/Telemetry/TelemetryMarkerComponent.cs # src/Umbraco.Core/Telemetry/TelemetryMarkerComposer.cs # src/Umbraco.Examine/Umbraco.Examine.csproj # src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs # src/Umbraco.Infrastructure/Install/InstallStepCollection.cs # src/Umbraco.Infrastructure/Install/InstallSteps/NewInstallStep.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseBuilder.cs # src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs # src/Umbraco.Infrastructure/Runtime/SqlMainDomLock.cs # src/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs # src/Umbraco.Tests/Runtimes/CoreRuntimeTests.cs # src/Umbraco.Tests/Runtimes/StandaloneTests.cs # src/Umbraco.Tests/Testing/TestDatabase.cs # src/Umbraco.Web.BackOffice/Controllers/BackOfficeServerVariables.cs # src/Umbraco.Web.UI.Client/src/installer/steps/database.controller.js # src/Umbraco.Web.UI.NetCore/Views/Partials/Grid/Editors/TextString.cshtml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en.xml # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/en_us.xml # src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml # src/Umbraco.Web.UI/config/umbracoSettings.Release.config # src/Umbraco.Web/Composing/CompositionExtensions/Installer.cs # src/Umbraco.Web/Editors/PreviewController.cs # src/Umbraco.Web/Editors/UsersController.cs # src/Umbraco.Web/JavaScript/PreviewInitialize.js # src/Umbraco.Web/Telemetry/TelemetryComponent.cs # src/Umbraco.Web/UmbracoApplication.cs
2021-01-18 15:40:22 +01:00
var userHasChangedOwnLanguage =
user.Id == currentUser.Id && currentUser.Language != user.Language;
var textToLocalise = userHasChangedOwnLanguage ? "speechBubbles/operationSavedHeaderReloadUser" : "speechBubbles/operationSavedHeader";
var culture = userHasChangedOwnLanguage
? CultureInfo.GetCultureInfo(user.Language)
: Thread.CurrentThread.CurrentUICulture;
display.AddSuccessNotification(_localizedTextService.Localize(textToLocalise, culture), _localizedTextService.Localize("speechBubbles/editUserSaved", culture));
2017-09-12 16:22:16 +02:00
return display;
2017-09-19 15:51:47 +02:00
}
2017-09-12 16:22:16 +02:00
/// <summary>
///
/// </summary>
/// <param name="changingPasswordModel"></param>
/// <returns></returns>
public async Task<ActionResult<ModelWithNotifications<string>>> PostChangePassword(ChangingPasswordModel changingPasswordModel)
{
changingPasswordModel = changingPasswordModel ?? throw new ArgumentNullException(nameof(changingPasswordModel));
if (ModelState.IsValid == false)
{
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
}
2021-02-20 19:16:31 +00:00
Attempt<int> intId = changingPasswordModel.Id.TryConvertTo<int>();
if (intId.Success == false)
{
return NotFound();
}
2021-02-20 19:16:31 +00:00
IUser found = _userService.GetUserById(intId.Result);
if (found == null)
{
return NotFound();
}
2021-02-26 14:52:54 +00:00
IUser currentUser = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
// if it's the current user, the current user cannot reset their own password without providing their old password
if (currentUser.Username == found.Username && string.IsNullOrEmpty(changingPasswordModel.OldPassword))
{
return ValidationErrorResult.CreateNotificationValidationErrorResult("Password reset is not allowed without providing old password");
}
if (!currentUser.IsAdmin() && found.IsAdmin())
{
return ValidationErrorResult.CreateNotificationValidationErrorResult("The current user cannot change the password for the specified user");
}
2021-02-20 19:16:31 +00:00
Attempt<PasswordChangedModel> passwordChangeResult = await _passwordChanger.ChangePasswordWithIdentityAsync(changingPasswordModel, _userManager);
if (passwordChangeResult.Success)
{
var result = new ModelWithNotifications<string>(passwordChangeResult.Result.ResetPassword);
result.AddSuccessNotification(_localizedTextService.Localize("general/success"), _localizedTextService.Localize("user/passwordChangedGeneric"));
return result;
}
2021-02-20 19:16:31 +00:00
foreach (string memberName in passwordChangeResult.Result.ChangeError.MemberNames)
{
ModelState.AddModelError(memberName, passwordChangeResult.Result.ChangeError.ErrorMessage);
}
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
}
2017-09-12 16:22:16 +02:00
/// <summary>
/// Disables the users with the given user ids
/// </summary>
/// <param name="userIds"></param>
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public IActionResult PostDisableUsers([FromQuery]int[] userIds)
2017-09-12 16:22:16 +02:00
{
2021-02-26 14:52:54 +00:00
var tryGetCurrentUserId = _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId();
2018-03-02 15:48:21 +01:00
if (tryGetCurrentUserId && userIds.Contains(tryGetCurrentUserId.Result))
2017-09-12 16:22:16 +02:00
{
return ValidationErrorResult.CreateNotificationValidationErrorResult("The current user cannot disable itself");
2017-09-12 16:22:16 +02:00
}
var users = _userService.GetUsersById(userIds).ToArray();
2017-09-12 16:22:16 +02:00
foreach (var u in users)
{
u.IsApproved = false;
u.InvitedDate = null;
}
_userService.Save(users);
2017-09-12 16:22:16 +02:00
if (users.Length > 1)
{
return new UmbracoNotificationSuccessResponse(
_localizedTextService.Localize("speechBubbles/disableUsersSuccess", new[] {userIds.Length.ToString()}));
2017-09-12 16:22:16 +02:00
}
return new UmbracoNotificationSuccessResponse(
_localizedTextService.Localize("speechBubbles/disableUserSuccess", new[] { users[0].Name }));
2017-09-12 16:22:16 +02:00
}
/// <summary>
/// Enables the users with the given user ids
/// </summary>
/// <param name="userIds"></param>
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public IActionResult PostEnableUsers([FromQuery]int[] userIds)
2017-09-12 16:22:16 +02:00
{
var users = _userService.GetUsersById(userIds).ToArray();
2017-09-12 16:22:16 +02:00
foreach (var u in users)
{
u.IsApproved = true;
}
_userService.Save(users);
2017-09-12 16:22:16 +02:00
if (users.Length > 1)
{
return new UmbracoNotificationSuccessResponse(
_localizedTextService.Localize("speechBubbles/enableUsersSuccess", new[] { userIds.Length.ToString() }));
2017-09-12 16:22:16 +02:00
}
return new UmbracoNotificationSuccessResponse(
_localizedTextService.Localize("speechBubbles/enableUserSuccess", new[] { users[0].Name }));
2017-09-19 15:51:47 +02:00
}
/// <summary>
/// Unlocks the users with the given user ids
/// </summary>
/// <param name="userIds"></param>
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public async Task<IActionResult> PostUnlockUsers([FromQuery]int[] userIds)
2017-09-19 15:51:47 +02:00
{
if (userIds.Length <= 0) return Ok();
2020-09-04 01:40:46 +10:00
var notFound = new List<int>();
2017-09-19 15:51:47 +02:00
foreach (var u in userIds)
2017-09-19 15:51:47 +02:00
{
2020-10-23 14:18:53 +11:00
var user = await _userManager.FindByIdAsync(u.ToString());
2020-09-04 01:40:46 +10:00
if (user == null)
{
notFound.Add(u);
continue;
}
var unlockResult = await _userManager.SetLockoutEndDateAsync(user, DateTimeOffset.Now.AddMinutes(-1));
2017-09-19 15:51:47 +02:00
if (unlockResult.Succeeded == false)
{
return new ValidationErrorResult(
$"Could not unlock for user {u} - error {unlockResult.Errors.ToErrorMessage()}");
2017-09-19 15:51:47 +02:00
}
if (userIds.Length == 1)
2017-09-19 15:51:47 +02:00
{
return new UmbracoNotificationSuccessResponse(
_localizedTextService.Localize("speechBubbles/unlockUserSuccess", new[] {user.Name}));
2017-09-19 15:51:47 +02:00
}
}
return new UmbracoNotificationSuccessResponse(
2020-09-04 01:40:46 +10:00
_localizedTextService.Localize("speechBubbles/unlockUsersSuccess", new[] {(userIds.Length - notFound.Count).ToString()}));
2017-09-12 16:22:16 +02:00
}
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public IActionResult PostSetUserGroupsOnUsers([FromQuery]string[] userGroupAliases, [FromQuery]int[] userIds)
2017-09-12 16:22:16 +02:00
{
var users = _userService.GetUsersById(userIds).ToArray();
var userGroups = _userService.GetUserGroupsByAlias(userGroupAliases).Select(x => x.ToReadOnlyGroup()).ToArray();
2017-09-12 16:22:16 +02:00
foreach (var u in users)
{
u.ClearGroups();
foreach (var userGroup in userGroups)
{
u.AddGroup(userGroup);
}
}
_userService.Save(users);
return new UmbracoNotificationSuccessResponse(
_localizedTextService.Localize("speechBubbles/setUserGroupOnUsersSuccess"));
2017-09-12 16:22:16 +02:00
}
/// <summary>
/// Deletes the non-logged in user provided id
/// </summary>
/// <param name="id">User Id</param>
/// <remarks>
/// Limited to users that haven't logged in to avoid issues with related records constrained
/// with a foreign key on the user Id
/// </remarks>
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
public IActionResult PostDeleteNonLoggedInUser(int id)
{
var user = _userService.GetUserById(id);
if (user == null)
{
return NotFound();
}
// Check user hasn't logged in. If they have they may have made content changes which will mean
// the Id is associated with audit trails, versions etc. and can't be removed.
if (user.LastLoginDate != default(DateTime))
{
return BadRequest();
}
var userName = user.Name;
_userService.Delete(user, true);
return new UmbracoNotificationSuccessResponse(
_localizedTextService.Localize("speechBubbles/deleteUserSuccess", new[] { userName }));
}
2017-09-12 16:22:16 +02:00
public class PagedUserResult : PagedResult<UserBasic>
{
public PagedUserResult(long totalItems, long pageNumber, long pageSize) : base(totalItems, pageNumber, pageSize)
{
UserStates = new Dictionary<UserState, int>();
}
/// <summary>
/// This is basically facets of UserStates key = state, value = count
/// </summary>
[DataMember(Name = "userStates")]
public IDictionary<UserState, int> UserStates { get; set; }
}
2017-09-19 15:51:47 +02:00
2017-09-12 16:22:16 +02:00
}
2017-09-23 10:08:18 +02:00
}