Merge remote-tracking branch 'upstream/dev' into Bootstrap
This commit is contained in:
@ -22,7 +22,6 @@ using Microsoft.AspNetCore.Cors;
|
||||
using System.IO.Compression;
|
||||
using Oqtane.Services;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
// ReSharper disable StringIndexOfIsCultureSpecific.1
|
||||
|
@ -9,6 +9,7 @@ using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Security;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
@ -20,18 +21,22 @@ namespace Oqtane.Controllers
|
||||
private readonly IPageRepository _pages;
|
||||
private readonly IModuleDefinitionRepository _moduleDefinitions;
|
||||
private readonly ISettingRepository _settings;
|
||||
private readonly IFolderRepository _folders;
|
||||
private readonly IFileRepository _files;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
|
||||
public ModuleController(IModuleRepository modules, IPageModuleRepository pageModules, IPageRepository pages, IModuleDefinitionRepository moduleDefinitions, ISettingRepository settings, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
public ModuleController(IModuleRepository modules, IPageModuleRepository pageModules, IPageRepository pages, IModuleDefinitionRepository moduleDefinitions, ISettingRepository settings, IFolderRepository folders, IFileRepository files, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger)
|
||||
{
|
||||
_modules = modules;
|
||||
_pageModules = pageModules;
|
||||
_pages = pages;
|
||||
_moduleDefinitions = moduleDefinitions;
|
||||
_settings = settings;
|
||||
_folders = folders;
|
||||
_files = files;
|
||||
_userPermissions = userPermissions;
|
||||
_syncManager = syncManager;
|
||||
_logger = logger;
|
||||
@ -248,6 +253,61 @@ namespace Oqtane.Controllers
|
||||
return content;
|
||||
}
|
||||
|
||||
// POST api/<controller>/export?moduleid=x&pageid=y&folderid=z&filename=a
|
||||
[HttpPost("export")]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
public int Export(int moduleid, int pageid, int folderid, string filename)
|
||||
{
|
||||
var fileid = -1;
|
||||
var module = _modules.GetModule(moduleid);
|
||||
if (module != null && module.SiteId == _alias.SiteId && _userPermissions.IsAuthorized(User, module.SiteId, EntityNames.Page, pageid, PermissionNames.Edit) &&
|
||||
_userPermissions.IsAuthorized(User, module.SiteId, EntityNames.Folder, folderid, PermissionNames.Edit) && !string.IsNullOrEmpty(filename))
|
||||
{
|
||||
// get content
|
||||
var content = _modules.ExportModule(moduleid);
|
||||
|
||||
// get folder
|
||||
var folder = _folders.GetFolder(folderid, false);
|
||||
string folderPath = _folders.GetFolderPath(folder);
|
||||
if (!Directory.Exists(folderPath))
|
||||
{
|
||||
Directory.CreateDirectory(folderPath);
|
||||
}
|
||||
|
||||
// create json file
|
||||
filename = Utilities.GetFriendlyUrl(Path.GetFileNameWithoutExtension(filename)) + ".json";
|
||||
string filepath = Path.Combine(folderPath, filename);
|
||||
if (System.IO.File.Exists(filepath))
|
||||
{
|
||||
System.IO.File.Delete(filepath);
|
||||
}
|
||||
System.IO.File.WriteAllText(filepath, content);
|
||||
|
||||
// register file
|
||||
var file = _files.GetFile(folderid, filename);
|
||||
if (file == null)
|
||||
{
|
||||
file = new Models.File { FolderId = folderid, Name = filename, Extension = "json", Size = (int)new FileInfo(filepath).Length, ImageWidth = 0, ImageHeight = 0 };
|
||||
_files.AddFile(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
file.Size = (int)new FileInfo(filepath).Length;
|
||||
_files.UpdateFile(file);
|
||||
}
|
||||
fileid = file.FileId;
|
||||
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Read, "Content Exported For Module {ModuleId} To Folder {FolderId}", moduleid, folderid);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Export Attempt For Module {Module} To Folder {FolderId}", moduleid, folderid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
|
||||
return fileid;
|
||||
}
|
||||
|
||||
// POST api/<controller>/import?moduleid=x&pageid=y
|
||||
[HttpPost("import")]
|
||||
[Authorize(Roles = RoleNames.Registered)]
|
||||
|
@ -24,26 +24,50 @@ namespace Oqtane.Controllers
|
||||
private readonly IPageModuleRepository _pageModules;
|
||||
private readonly IUserPermissions _userPermissions;
|
||||
private readonly ISyncManager _syncManager;
|
||||
private readonly IAliasAccessor _aliasAccessor;
|
||||
private readonly IOptionsMonitorCache<CookieAuthenticationOptions> _cookieCache;
|
||||
private readonly IOptionsMonitorCache<OpenIdConnectOptions> _oidcCache;
|
||||
private readonly IOptionsMonitorCache<OAuthOptions> _oauthCache;
|
||||
private readonly IOptionsMonitorCache<IdentityOptions> _identityCache;
|
||||
|
||||
private readonly IOptions<CookieAuthenticationOptions> _cookieOptions;
|
||||
private readonly IOptionsSnapshot<CookieAuthenticationOptions> _cookieOptionsSnapshot;
|
||||
private readonly IOptionsMonitorCache<CookieAuthenticationOptions> _cookieOptionsMonitorCache;
|
||||
|
||||
private readonly IOptions<OpenIdConnectOptions> _oidcOptions;
|
||||
private readonly IOptionsSnapshot<OpenIdConnectOptions> _oidcOptionsSnapshot;
|
||||
private readonly IOptionsMonitorCache<OpenIdConnectOptions> _oidcOptionsMonitorCache;
|
||||
|
||||
private readonly IOptions<OAuthOptions> _oauthOptions;
|
||||
private readonly IOptionsSnapshot<OAuthOptions> _oauthOptionsSnapshot;
|
||||
private readonly IOptionsMonitorCache<OAuthOptions> _oauthOptionsMonitorCache;
|
||||
|
||||
private readonly IOptions<IdentityOptions> _identityOptions;
|
||||
private readonly IOptionsSnapshot<IdentityOptions> _identityOptionsSnapshot;
|
||||
private readonly IOptionsMonitorCache<IdentityOptions> _identityOptionsMonitorCache;
|
||||
|
||||
private readonly ILogManager _logger;
|
||||
private readonly Alias _alias;
|
||||
private readonly string _visitorCookie;
|
||||
|
||||
public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager, IAliasAccessor aliasAccessor, IOptionsMonitorCache<CookieAuthenticationOptions> cookieCache, IOptionsMonitorCache<OpenIdConnectOptions> oidcCache, IOptionsMonitorCache<OAuthOptions> oauthCache, IOptionsMonitorCache<IdentityOptions> identityCache, ILogManager logger)
|
||||
public SettingController(ISettingRepository settings, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantManager tenantManager, ISyncManager syncManager,
|
||||
IOptions<CookieAuthenticationOptions> cookieOptions, IOptionsSnapshot<CookieAuthenticationOptions> cookieOptionsSnapshot, IOptionsMonitorCache<CookieAuthenticationOptions> cookieOptionsMonitorCache,
|
||||
IOptions<OpenIdConnectOptions> oidcOptions, IOptionsSnapshot<OpenIdConnectOptions> oidcOptionsSnapshot, IOptionsMonitorCache<OpenIdConnectOptions> oidcOptionsMonitorCache,
|
||||
IOptions<OAuthOptions> oauthOptions, IOptionsSnapshot<OAuthOptions> oauthOptionsSnapshot, IOptionsMonitorCache<OAuthOptions> oauthOptionsMonitorCache,
|
||||
IOptions<IdentityOptions> identityOptions, IOptionsSnapshot<IdentityOptions> identityOptionsSnapshot, IOptionsMonitorCache<IdentityOptions> identityOptionsMonitorCache,
|
||||
ILogManager logger)
|
||||
{
|
||||
_settings = settings;
|
||||
_pageModules = pageModules;
|
||||
_userPermissions = userPermissions;
|
||||
_syncManager = syncManager;
|
||||
_aliasAccessor = aliasAccessor;
|
||||
_cookieCache = cookieCache;
|
||||
_oidcCache = oidcCache;
|
||||
_oauthCache = oauthCache;
|
||||
_identityCache = identityCache;
|
||||
_cookieOptions = cookieOptions;
|
||||
_cookieOptionsSnapshot = cookieOptionsSnapshot;
|
||||
_cookieOptionsMonitorCache = cookieOptionsMonitorCache;
|
||||
_oidcOptions = oidcOptions;
|
||||
_oidcOptionsSnapshot = oidcOptionsSnapshot;
|
||||
_oidcOptionsMonitorCache = oidcOptionsMonitorCache;
|
||||
_oauthOptions = oauthOptions;
|
||||
_oauthOptionsSnapshot = oauthOptionsSnapshot;
|
||||
_oauthOptionsMonitorCache = oauthOptionsMonitorCache;
|
||||
_identityOptions = identityOptions;
|
||||
_identityOptionsSnapshot = identityOptionsSnapshot;
|
||||
_identityOptionsMonitorCache = identityOptionsMonitorCache;
|
||||
_logger = logger;
|
||||
_alias = tenantManager.GetAlias();
|
||||
_visitorCookie = Constants.VisitorCookiePrefix + _alias.SiteId.ToString();
|
||||
@ -210,21 +234,21 @@ namespace Oqtane.Controllers
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Clear()
|
||||
{
|
||||
// clear SiteOptionsCache for each option type
|
||||
var cookieCache = new SiteOptionsCache<CookieAuthenticationOptions>(_aliasAccessor);
|
||||
cookieCache.Clear();
|
||||
var oidcCache = new SiteOptionsCache<OpenIdConnectOptions>(_aliasAccessor);
|
||||
oidcCache.Clear();
|
||||
var oauthCache = new SiteOptionsCache<OAuthOptions>(_aliasAccessor);
|
||||
oauthCache.Clear();
|
||||
var identityCache = new SiteOptionsCache<IdentityOptions>(_aliasAccessor);
|
||||
identityCache.Clear();
|
||||
(_cookieOptions as SiteOptionsManager<CookieAuthenticationOptions>).Reset();
|
||||
(_cookieOptionsSnapshot as SiteOptionsManager<CookieAuthenticationOptions>).Reset();
|
||||
_cookieOptionsMonitorCache.Clear();
|
||||
|
||||
// clear IOptionsMonitorCache for each option type
|
||||
_cookieCache.Clear();
|
||||
_oidcCache.Clear();
|
||||
_oauthCache.Clear();
|
||||
_identityCache.Clear();
|
||||
(_oidcOptions as SiteOptionsManager<OpenIdConnectOptions>).Reset();
|
||||
(_oidcOptionsSnapshot as SiteOptionsManager<OpenIdConnectOptions>).Reset();
|
||||
_oidcOptionsMonitorCache.Clear();
|
||||
|
||||
(_oauthOptions as SiteOptionsManager<OAuthOptions>).Reset();
|
||||
(_oauthOptionsSnapshot as SiteOptionsManager<OAuthOptions>).Reset();
|
||||
_oauthOptionsMonitorCache.Clear();
|
||||
|
||||
(_identityOptions as SiteOptionsManager<IdentityOptions>).Reset();
|
||||
(_identityOptionsSnapshot as SiteOptionsManager<IdentityOptions>).Reset();
|
||||
_identityOptionsMonitorCache.Clear();
|
||||
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Other, "Site Options Cache Cleared");
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ namespace Oqtane.Controllers
|
||||
filtered.TwoFactorCode = "";
|
||||
filtered.SecurityStamp = "";
|
||||
|
||||
// include private properties if authenticated user is accessing their own user account os is an administrator
|
||||
// include private properties if authenticated user is accessing their own user account or is an administrator
|
||||
if (_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin) || _userPermissions.GetUser(User).UserId == user.UserId)
|
||||
{
|
||||
filtered.Email = user.Email;
|
||||
@ -140,6 +140,7 @@ namespace Oqtane.Controllers
|
||||
filtered.LastLoginOn = user.LastLoginOn;
|
||||
filtered.LastIPAddress = user.LastIPAddress;
|
||||
filtered.TwoFactorRequired = user.TwoFactorRequired;
|
||||
filtered.EmailConfirmed = user.EmailConfirmed;
|
||||
filtered.Roles = user.Roles;
|
||||
filtered.CreatedBy = user.CreatedBy;
|
||||
filtered.CreatedOn = user.CreatedOn;
|
||||
@ -200,10 +201,15 @@ namespace Oqtane.Controllers
|
||||
[Authorize]
|
||||
public async Task<User> Put(int id, [FromBody] User user)
|
||||
{
|
||||
if (ModelState.IsValid && user.SiteId == _tenantManager.GetAlias().SiteId && user.UserId == id && _users.GetUser(user.UserId, false) != null
|
||||
var existing = _userManager.GetUser(user.UserId, user.SiteId);
|
||||
if (ModelState.IsValid && user.SiteId == _tenantManager.GetAlias().SiteId && user.UserId == id && existing != null
|
||||
&& (_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin) || User.Identity.Name == user.Username))
|
||||
{
|
||||
user.EmailConfirmed = User.IsInRole(RoleNames.Admin);
|
||||
// only authorized users can update the email confirmation
|
||||
if (!_userPermissions.IsAuthorized(User, user.SiteId, EntityNames.User, -1, PermissionNames.Write, RoleNames.Admin))
|
||||
{
|
||||
user.EmailConfirmed = existing.EmailConfirmed;
|
||||
}
|
||||
user = await _userManager.UpdateUser(user);
|
||||
}
|
||||
else
|
||||
|
@ -1,5 +1,4 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Oqtane.Models;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using System;
|
||||
|
||||
|
@ -19,7 +19,6 @@ namespace Oqtane.Infrastructure
|
||||
{
|
||||
var cache = map.GetOrAdd(GetKey(), new OptionsCache<TOptions>());
|
||||
cache.Clear();
|
||||
|
||||
}
|
||||
|
||||
public TOptions GetOrAdd(string name, Func<TOptions> createOptions)
|
||||
|
@ -65,7 +65,12 @@ namespace Oqtane.Managers
|
||||
{
|
||||
user.SiteId = siteid;
|
||||
user.Roles = GetUserRoles(user.UserId, user.SiteId);
|
||||
user.SecurityStamp = _identityUserManager.FindByNameAsync(user.Username).GetAwaiter().GetResult()?.SecurityStamp;
|
||||
var identityuser = _identityUserManager.FindByNameAsync(user.Username).GetAwaiter().GetResult();
|
||||
if (identityuser != null)
|
||||
{
|
||||
user.SecurityStamp = identityuser.SecurityStamp;
|
||||
user.EmailConfirmed = identityuser.EmailConfirmed;
|
||||
}
|
||||
user.Settings = _settings.GetSettings(EntityNames.User, user.UserId)
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
}
|
||||
@ -245,22 +250,30 @@ namespace Oqtane.Managers
|
||||
{
|
||||
identityuser.Email = user.Email;
|
||||
await _identityUserManager.UpdateAsync(identityuser); // security stamp not updated
|
||||
|
||||
// if email address changed and it is not confirmed, verification is required for new email address
|
||||
if (!user.EmailConfirmed)
|
||||
{
|
||||
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string body = "Dear " + user.DisplayName + ",\n\nIn Order To Verify The Email Address Associated To Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
||||
var notification = new Notification(user.SiteId, user, "User Account Verification", body);
|
||||
_notifications.AddNotification(notification);
|
||||
}
|
||||
}
|
||||
|
||||
if (user.EmailConfirmed)
|
||||
{
|
||||
var emailConfirmationToken = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
await _identityUserManager.ConfirmEmailAsync(identityuser, emailConfirmationToken);
|
||||
if (!identityuser.EmailConfirmed)
|
||||
{
|
||||
var emailConfirmationToken = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
await _identityUserManager.ConfirmEmailAsync(identityuser, emailConfirmationToken);
|
||||
|
||||
string body = "Dear " + user.DisplayName + ",\n\nThe Email Address For Your User Account Has Been Verified. You Can Now Login With Your Username And Password.";
|
||||
var notification = new Notification(user.SiteId, user, "User Account Verification", body);
|
||||
_notifications.AddNotification(notification);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
identityuser.EmailConfirmed = false;
|
||||
await _identityUserManager.UpdateAsync(identityuser); // security stamp not updated
|
||||
|
||||
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string body = "Dear " + user.DisplayName + ",\n\nIn Order To Verify The Email Address Associated To Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
||||
var notification = new Notification(user.SiteId, user, "User Account Verification", body);
|
||||
_notifications.AddNotification(notification);
|
||||
}
|
||||
|
||||
user = _users.UpdateUser(user);
|
||||
|
@ -48,7 +48,7 @@
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.11" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.8" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.2" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Oqtane.Client\Oqtane.Client.csproj" />
|
||||
|
Reference in New Issue
Block a user