Skip to content

Commit

Permalink
User Accounts and Custom User Settings Deployment (#14208)
Browse files Browse the repository at this point in the history
Co-authored-by: Mike Alhayek <[email protected]>
Co-authored-by: Hisham Bin Ateya <[email protected]>
  • Loading branch information
3 people authored Oct 21, 2023
1 parent 2491c18 commit 841925d
Show file tree
Hide file tree
Showing 21 changed files with 628 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using OrchardCore.Deployment;
using OrchardCore.Users.Models;
using OrchardCore.Users.Recipes;
using YesSql;

namespace OrchardCore.Users.Deployment;

public class AllUsersDeploymentSource : IDeploymentSource
{
private readonly ISession _session;

public AllUsersDeploymentSource(ISession session)
{
_session = session;
}

public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlanResult result)
{
if (step is not AllUsersDeploymentStep allRolesStep)
{
return;
}

var allUsers = await _session.Query<User>().ListAsync();
var users = new JArray();

foreach (var user in allUsers)
{
users.Add(JObject.FromObject(
new UsersStepUserModel
{
UserName = user.UserName,
UserId = user.UserId,
Id = user.Id,
Email = user.Email,
EmailConfirmed = user.EmailConfirmed,
PasswordHash = user.PasswordHash,
IsEnabled = user.IsEnabled,
NormalizedEmail = user.NormalizedEmail,
NormalizedUserName = user.NormalizedUserName,
SecurityStamp = user.SecurityStamp,
ResetToken = user.ResetToken,
PhoneNumber = user.PhoneNumber,
PhoneNumberConfirmed = user.PhoneNumberConfirmed,
TwoFactorEnabled = user.TwoFactorEnabled,
IsLockoutEnabled = user.IsLockoutEnabled,
AccessFailedCount = user.AccessFailedCount,
RoleNames = user.RoleNames,
}));
}

result.Steps.Add(new JObject(
new JProperty("name", "Users"),
new JProperty("Users", users)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using OrchardCore.Deployment;

namespace OrchardCore.Users.Deployment;

/// <summary>
/// Adds users to a <see cref="DeploymentPlanResult"/>.
/// </summary>
public class AllUsersDeploymentStep : DeploymentStep
{
public AllUsersDeploymentStep()
{
Name = "AllUsers";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using OrchardCore.Deployment;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Views;

namespace OrchardCore.Users.Deployment;

public class AllUsersDeploymentStepDriver : DisplayDriver<DeploymentStep, AllUsersDeploymentStep>
{
public override IDisplayResult Display(AllUsersDeploymentStep step)
{
return Combine(
View("AllUsersDeploymentStep_Summary", step).Location("Summary", "Content"),
View("AllUsersDeploymentStep_Thumbnail", step).Location("Thumbnail", "Content"));
}

public override IDisplayResult Edit(AllUsersDeploymentStep step)
{
return View("AllUsersDeploymentStep_Edit", step).Location("Content");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using OrchardCore.Deployment;
using OrchardCore.Users.Models;
using OrchardCore.Users.Services;
using YesSql;

namespace OrchardCore.Users.Deployment;

public class CustomUserSettingsDeploymentSource : IDeploymentSource
{
private readonly CustomUserSettingsService _customUserSettingsService;
private readonly ISession _session;

public CustomUserSettingsDeploymentSource(CustomUserSettingsService customUserSettingsService, ISession session)
{
_customUserSettingsService = customUserSettingsService;
_session = session;
}

public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlanResult result)
{
var customUserSettingsStep = step as CustomUserSettingsDeploymentStep;
if (customUserSettingsStep == null)
{
return;
}

var settingsTypes = customUserSettingsStep.IncludeAll
? _customUserSettingsService.GetAllSettingsTypes().ToList()
: _customUserSettingsService.GetSettingsTypes(customUserSettingsStep.SettingsTypeNames).ToList();

// Todo: check permissions for each settings type
var userData = new JArray();
var allUsers = await _session.Query<User>().ListAsync();

foreach (var user in allUsers)
{
var userSettingsData = new JArray();
foreach (var settingsType in settingsTypes)
{
var userSetting = await _customUserSettingsService.GetSettingsAsync(user, settingsType);
userSettingsData.Add(JObject.FromObject(userSetting));
}

userData.Add(new JObject(
new JProperty("userId", user.UserId),
new JProperty("user-custom-user-settings", userSettingsData)));
}

// Adding custom user settings
result.Steps.Add(new JObject(
new JProperty("name", "custom-user-settings"),
new JProperty("custom-user-settings", userData)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using OrchardCore.Deployment;

namespace OrchardCore.Users.Deployment;

public class CustomUserSettingsDeploymentStep : DeploymentStep
{
public CustomUserSettingsDeploymentStep()
{
Name = "CustomUserSettings";
}

public bool IncludeAll { get; set; } = true;

public string[] SettingsTypeNames { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using OrchardCore.Deployment;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.ModelBinding;
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Users.Services;
using OrchardCore.Users.ViewModels;

namespace OrchardCore.Users.Deployment
{
public class CustomUserSettingsDeploymentStepDriver : DisplayDriver<DeploymentStep, CustomUserSettingsDeploymentStep>
{
private readonly CustomUserSettingsService _customUserSettingsService;

public CustomUserSettingsDeploymentStepDriver(CustomUserSettingsService customUserSettingsService)
{
_customUserSettingsService = customUserSettingsService;
}

public override IDisplayResult Display(CustomUserSettingsDeploymentStep step)
{
return Combine(
View("CustomUserSettingsDeploymentStep_Fields_Summary", step).Location("Summary", "Content"),
View("CustomUserSettingsDeploymentStep_Fields_Thumbnail", step).Location("Thumbnail", "Content"));
}

public override IDisplayResult Edit(CustomUserSettingsDeploymentStep step)
{
return Initialize<CustomUserSettingsDeploymentStepViewModel>("CustomUserSettingsDeploymentStep_Fields_Edit", model =>
{
model.IncludeAll = step.IncludeAll;
model.SettingsTypeNames = step.SettingsTypeNames;
model.AllSettingsTypeNames = _customUserSettingsService.GetAllSettingsTypeNames().ToArray();
})
.Location("Content");
}

public override async Task<IDisplayResult> UpdateAsync(CustomUserSettingsDeploymentStep step, IUpdateModel updater)
{
step.SettingsTypeNames = Array.Empty<string>();
await updater.TryUpdateModelAsync(step, Prefix);

if (step.IncludeAll)
{
step.SettingsTypeNames = Array.Empty<string>();
}

return Edit(step);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace OrchardCore.Users.Models;

public class UsersStepModel
{
public UsersStepUserModel[] Users { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Collections.Generic;

namespace OrchardCore.Users.Models;

public class UsersStepUserModel
{
public long Id { get; set; }

public string UserId { get; set; }

public string UserName { get; set; }

public string Email { get; set; }

public string PasswordHash { get; set; }

public bool EmailConfirmed { get; set; }

public bool IsEnabled { get; set; } = true;

public string NormalizedEmail { get; set; }

public string NormalizedUserName { get; set; }

public string SecurityStamp { get; set; }

public string ResetToken { get; set; }
public string PhoneNumber { get; set; }

public bool PhoneNumberConfirmed { get; set; }

public bool TwoFactorEnabled { get; set; }

public bool IsLockoutEnabled { get; set; }

public int AccessFailedCount { get; set; }

public IList<string> RoleNames { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using OrchardCore.ContentManagement;
using OrchardCore.Recipes.Models;
using OrchardCore.Recipes.Services;
using OrchardCore.Users.Models;
using YesSql;

namespace OrchardCore.Users.Recipes;

/// <summary>
/// This recipe step updates the custom user settings.
/// </summary>
public class CustomUserSettingsStep : IRecipeStepHandler
{
private readonly ISession _session;

public CustomUserSettingsStep(ISession session)
{
_session = session;
}

public async Task ExecuteAsync(RecipeExecutionContext context)
{
if (!string.Equals(context.Name, "custom-user-settings", StringComparison.OrdinalIgnoreCase))
{
return;
}

var model = context.Step;

var customUserSettingsList = (JArray)model
.Properties()
.Where(p => p.Name != "name")
.FirstOrDefault()
?.Value;

var allUsers = await _session.Query<User>().ListAsync();

foreach (JObject userCustomUserSettings in customUserSettingsList.Cast<JObject>())
{
var userId = userCustomUserSettings
.Properties()
.FirstOrDefault(p => p.Name == "userId")?
.Value
?.ToString();

var user = allUsers.FirstOrDefault(u => u.UserId == userId);
if (user is not User _)
{
continue;
}

var userSettings = (JArray)userCustomUserSettings
.Properties()
.FirstOrDefault(p => p.Name == "user-custom-user-settings")
?.Value;

foreach (JObject userSetting in userSettings.Cast<JObject>())
{
var contentItem = userSetting.ToObject<ContentItem>();
user.Properties[contentItem.ContentType] = userSetting;
}

_session.Save(user);
}
}
}
Loading

0 comments on commit 841925d

Please sign in to comment.