add ability to import users
This commit is contained in:
parent
886df69058
commit
8e5e79a799
|
@ -20,7 +20,8 @@ else
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row mb-1 align-items-center">
|
<div class="row mb-1 align-items-center">
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
<ActionLink Action="Add" Text="Add User" Security="SecurityAccessLevel.Edit" ResourceKey="AddUser" />
|
||||||
|
<ActionLink Text="Import Users" Class="btn btn-secondary" Action="Users" Security="SecurityAccessLevel.Admin" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-4">
|
||||||
<input class="form-control" @bind="@_search" />
|
<input class="form-control" @bind="@_search" />
|
||||||
|
|
55
Oqtane.Client/Modules/Admin/Users/Users.razor
Normal file
55
Oqtane.Client/Modules/Admin/Users/Users.razor
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
@namespace Oqtane.Modules.Admin.Users
|
||||||
|
@inherits ModuleBase
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject IUserService UserService
|
||||||
|
@inject IStringLocalizer<Users> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="userfile" HelpText="Select or upload a CSV file containing user information. The CSV file must be in the Template format specified." ResourceKey="UserFile">User File:</Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<FileManager Id="userfile" @ref="_filemanager" Filter="csv" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
<button type="button" class="btn btn-success" @onclick="ImportUsers">@Localizer["Import"]</button>
|
||||||
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
<a class="btn btn-info" href="/users.csv" target="_new">@Localizer["Template"]</a>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private FileManager _filemanager;
|
||||||
|
|
||||||
|
public override string Title => "Import Users";
|
||||||
|
|
||||||
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||||
|
|
||||||
|
private async Task ImportUsers()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fileid = _filemanager.GetFileId();
|
||||||
|
if (fileid != -1)
|
||||||
|
{
|
||||||
|
if (await UserService.ImportUsersAsync(PageState.Site.SiteId, fileid))
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Import.Success"], MessageType.Success);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Import.Failure"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(Localizer["Message.Import.Validation"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Importing Users {Error}", ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.Import"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
Oqtane.Client/Resources/Modules/Admin/Users/Users.resx
Normal file
144
Oqtane.Client/Resources/Modules/Admin/Users/Users.resx
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="UserFile.HelpText" xml:space="preserve">
|
||||||
|
<value>Select or upload a CSV file containing user information. The CSV file must be in the Template format specified.</value>
|
||||||
|
</data>
|
||||||
|
<data name="UserFile.Text" xml:space="preserve">
|
||||||
|
<value>User File:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Error.Import" xml:space="preserve">
|
||||||
|
<value>Error Importing Users</value>
|
||||||
|
</data>
|
||||||
|
<data name="Import" xml:space="preserve">
|
||||||
|
<value>Import</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Import.Failure" xml:space="preserve">
|
||||||
|
<value>User Import Failed</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Import.Success" xml:space="preserve">
|
||||||
|
<value>Users Imported Successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="Message.Import.Validation" xml:space="preserve">
|
||||||
|
<value>You Must Specify A User File For Import</value>
|
||||||
|
</data>
|
||||||
|
<data name="Template" xml:space="preserve">
|
||||||
|
<value>Template</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
|
@ -142,5 +142,12 @@ namespace Oqtane.Services
|
||||||
/// <param name="siteId">ID of a <see cref="Site"/></param>
|
/// <param name="siteId">ID of a <see cref="Site"/></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<string> GetPasswordRequirementsAsync(int siteId);
|
Task<string> GetPasswordRequirementsAsync(int siteId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Bulk import of users
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileId">ID of a <see cref="File"/></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<bool> ImportUsersAsync(int siteId, int fileId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ using Oqtane.Documentation;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Localization;
|
using Microsoft.Extensions.Localization;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||||
|
using Oqtane.Modules.Admin.Roles;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Oqtane.Services
|
namespace Oqtane.Services
|
||||||
{
|
{
|
||||||
|
@ -123,5 +126,10 @@ namespace Oqtane.Services
|
||||||
// format requirements
|
// format requirements
|
||||||
return string.Format(passwordValidationCriteriaTemplate, minimumlength, uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
return string.Format(passwordValidationCriteriaTemplate, minimumlength, uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ImportUsersAsync(int siteId, int fileId)
|
||||||
|
{
|
||||||
|
return await PostJsonAsync<bool>($"{Apiurl}/import?siteid={siteId}&fileid={fileId}", true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,10 @@ namespace Oqtane.Controllers
|
||||||
private readonly IUserPermissions _userPermissions;
|
private readonly IUserPermissions _userPermissions;
|
||||||
private readonly ISettingRepository _settings;
|
private readonly ISettingRepository _settings;
|
||||||
private readonly IJwtManager _jwtManager;
|
private readonly IJwtManager _jwtManager;
|
||||||
|
private readonly IFileRepository _files;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
|
|
||||||
public UserController(IUserRepository users, ITenantManager tenantManager, IUserManager userManager, ISiteRepository sites, IUserPermissions userPermissions, ISettingRepository settings, IJwtManager jwtManager, ILogManager logger)
|
public UserController(IUserRepository users, ITenantManager tenantManager, IUserManager userManager, ISiteRepository sites, IUserPermissions userPermissions, ISettingRepository settings, IJwtManager jwtManager, IFileRepository files, ILogManager logger)
|
||||||
{
|
{
|
||||||
_users = users;
|
_users = users;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
|
@ -39,6 +40,7 @@ namespace Oqtane.Controllers
|
||||||
_userPermissions = userPermissions;
|
_userPermissions = userPermissions;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_jwtManager = jwtManager;
|
_jwtManager = jwtManager;
|
||||||
|
_files = files;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,5 +371,22 @@ namespace Oqtane.Controllers
|
||||||
|
|
||||||
return requirements;
|
return requirements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST api/<controller>/import?siteid=x&fileid=y
|
||||||
|
[HttpPost("import")]
|
||||||
|
[Authorize(Roles = RoleNames.Admin)]
|
||||||
|
public async Task<bool> Import(string siteid, string fileid)
|
||||||
|
{
|
||||||
|
if (int.TryParse(siteid, out int SiteId) && SiteId == _tenantManager.GetAlias().SiteId && int.TryParse(fileid, out int FileId))
|
||||||
|
{
|
||||||
|
return await _userManager.ImportUsers(SiteId, FileId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Import Attempt {SiteId} {FileId}", siteid, fileid);
|
||||||
|
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,5 +18,6 @@ namespace Oqtane.Managers
|
||||||
User VerifyTwoFactor(User user, string token);
|
User VerifyTwoFactor(User user, string token);
|
||||||
Task<User> LinkExternalAccount(User user, string token, string type, string key, string name);
|
Task<User> LinkExternalAccount(User user, string token, string type, string key, string name);
|
||||||
Task<bool> ValidatePassword(string password);
|
Task<bool> ValidatePassword(string password);
|
||||||
|
Task<bool> ImportUsers(int siteId, int fileId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
@ -16,24 +17,32 @@ namespace Oqtane.Managers
|
||||||
public class UserManager : IUserManager
|
public class UserManager : IUserManager
|
||||||
{
|
{
|
||||||
private readonly IUserRepository _users;
|
private readonly IUserRepository _users;
|
||||||
|
private readonly IRoleRepository _roles;
|
||||||
private readonly IUserRoleRepository _userRoles;
|
private readonly IUserRoleRepository _userRoles;
|
||||||
private readonly UserManager<IdentityUser> _identityUserManager;
|
private readonly UserManager<IdentityUser> _identityUserManager;
|
||||||
private readonly SignInManager<IdentityUser> _identitySignInManager;
|
private readonly SignInManager<IdentityUser> _identitySignInManager;
|
||||||
private readonly ITenantManager _tenantManager;
|
private readonly ITenantManager _tenantManager;
|
||||||
private readonly INotificationRepository _notifications;
|
private readonly INotificationRepository _notifications;
|
||||||
private readonly IFolderRepository _folders;
|
private readonly IFolderRepository _folders;
|
||||||
|
private readonly IFileRepository _files;
|
||||||
|
private readonly IProfileRepository _profiles;
|
||||||
|
private readonly ISettingRepository _settings;
|
||||||
private readonly ISyncManager _syncManager;
|
private readonly ISyncManager _syncManager;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
|
|
||||||
public UserManager(IUserRepository users, IUserRoleRepository userRoles, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, ISyncManager syncManager, ILogManager logger)
|
public UserManager(IUserRepository users, IRoleRepository roles, IUserRoleRepository userRoles, UserManager<IdentityUser> identityUserManager, SignInManager<IdentityUser> identitySignInManager, ITenantManager tenantManager, INotificationRepository notifications, IFolderRepository folders, IFileRepository files, IProfileRepository profiles, ISettingRepository settings, ISyncManager syncManager, ILogManager logger)
|
||||||
{
|
{
|
||||||
_users = users;
|
_users = users;
|
||||||
|
_roles = roles;
|
||||||
_userRoles = userRoles;
|
_userRoles = userRoles;
|
||||||
_identityUserManager = identityUserManager;
|
_identityUserManager = identityUserManager;
|
||||||
_identitySignInManager = identitySignInManager;
|
_identitySignInManager = identitySignInManager;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
_notifications = notifications;
|
_notifications = notifications;
|
||||||
_folders = folders;
|
_folders = folders;
|
||||||
|
_files = files;
|
||||||
|
_profiles = profiles;
|
||||||
|
_settings = settings;
|
||||||
_syncManager = syncManager;
|
_syncManager = syncManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
@ -95,6 +104,12 @@ namespace Oqtane.Managers
|
||||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||||
if (identityuser == null)
|
if (identityuser == null)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(user.Password))
|
||||||
|
{
|
||||||
|
// create random password ie. Jan-01-2023+12:00:00!
|
||||||
|
Random rnd = new Random();
|
||||||
|
user.Password = DateTime.UtcNow.ToString("MMM-dd-yyyy+HH:mm:ss", CultureInfo.InvariantCulture) + (char)rnd.Next(33, 47);
|
||||||
|
}
|
||||||
identityuser = new IdentityUser();
|
identityuser = new IdentityUser();
|
||||||
identityuser.UserName = user.Username;
|
identityuser.UserName = user.Username;
|
||||||
identityuser.Email = user.Email;
|
identityuser.Email = user.Email;
|
||||||
|
@ -443,5 +458,144 @@ namespace Oqtane.Managers
|
||||||
var result = await validator.ValidateAsync(_identityUserManager, null, password);
|
var result = await validator.ValidateAsync(_identityUserManager, null, password);
|
||||||
return result.Succeeded;
|
return result.Succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ImportUsers(int siteId, int fileId)
|
||||||
|
{
|
||||||
|
var success = true;
|
||||||
|
int users = 0;
|
||||||
|
|
||||||
|
var file = _files.GetFile(fileId);
|
||||||
|
if (file != null)
|
||||||
|
{
|
||||||
|
var path = _files.GetFilePath(file);
|
||||||
|
if (System.IO.File.Exists(path))
|
||||||
|
{
|
||||||
|
var roles = _roles.GetRoles(siteId).ToList();
|
||||||
|
var profiles = _profiles.GetProfiles(siteId).ToList();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string row;
|
||||||
|
using (var reader = new StreamReader(path))
|
||||||
|
{
|
||||||
|
// get header row
|
||||||
|
row = reader.ReadLine();
|
||||||
|
var header = row.Replace("\"", "").Split(',');
|
||||||
|
|
||||||
|
row = reader.ReadLine();
|
||||||
|
while (row != null)
|
||||||
|
{
|
||||||
|
var values = row.Replace("\"", "").Split(',');
|
||||||
|
|
||||||
|
if (values.Length > 3)
|
||||||
|
{
|
||||||
|
// user
|
||||||
|
var user = _users.GetUser(values[1], values[0]);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
user = new User();
|
||||||
|
user.SiteId = siteId;
|
||||||
|
user.Email = values[0];
|
||||||
|
user.Username = (!string.IsNullOrEmpty(values[1])) ? values[1] : user.Email;
|
||||||
|
user.DisplayName = (!string.IsNullOrEmpty(values[2])) ? values[2] : user.Username;
|
||||||
|
user = await AddUser(user);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "Error Creating User {Email}", values[0]);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user != null && !string.IsNullOrEmpty(values[3]))
|
||||||
|
{
|
||||||
|
// roles (comma delimited)
|
||||||
|
foreach (var rolename in values[3].Split(','))
|
||||||
|
{
|
||||||
|
var role = roles.FirstOrDefault(item => item.Name == rolename);
|
||||||
|
if (role == null)
|
||||||
|
{
|
||||||
|
role = new Role();
|
||||||
|
role.SiteId = siteId;
|
||||||
|
role.Name = rolename;
|
||||||
|
role.Description = rolename;
|
||||||
|
role = _roles.AddRole(role);
|
||||||
|
roles.Add(role);
|
||||||
|
}
|
||||||
|
if (role != null)
|
||||||
|
{
|
||||||
|
var userrole = _userRoles.GetUserRole(user.UserId, role.RoleId, false);
|
||||||
|
if (userrole == null)
|
||||||
|
{
|
||||||
|
userrole = new UserRole();
|
||||||
|
userrole.UserId = user.UserId;
|
||||||
|
userrole.RoleId = role.RoleId;
|
||||||
|
_userRoles.AddUserRole(userrole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user != null && values.Length > 4)
|
||||||
|
{
|
||||||
|
var settings = _settings.GetSettings(EntityNames.User, user.UserId);
|
||||||
|
for (int index = 4; index < values.Length - 1; index++)
|
||||||
|
{
|
||||||
|
if (header.Length > index && !string.IsNullOrEmpty(values[index]))
|
||||||
|
{
|
||||||
|
var profile = profiles.FirstOrDefault(item => item.Name == header[index]);
|
||||||
|
if (profile != null)
|
||||||
|
{
|
||||||
|
var setting = settings.FirstOrDefault(item => item.SettingName == profile.Name);
|
||||||
|
if (setting == null)
|
||||||
|
{
|
||||||
|
setting = new Setting();
|
||||||
|
setting.EntityName = EntityNames.User;
|
||||||
|
setting.EntityId = user.UserId;
|
||||||
|
setting.SettingName = profile.Name;
|
||||||
|
setting.SettingValue = values[index];
|
||||||
|
_settings.AddSetting(setting);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (setting.SettingValue != values[index])
|
||||||
|
{
|
||||||
|
setting.SettingValue = values[index];
|
||||||
|
_settings.UpdateSetting(setting);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
users++;
|
||||||
|
}
|
||||||
|
|
||||||
|
row = reader.ReadLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Log(LogLevel.Information, this, LogFunction.Create, "{Users} Users Imported", users);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, ex, "Error Importing User Import File {SiteId} {FileId}", siteId, fileId);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create,"User Import File Does Not Exist {Path}", path);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import File Does Not Exist {SiteId} {FileId}", siteId, fileId);
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@ namespace Oqtane.Repository
|
||||||
UserRole UpdateUserRole(UserRole userRole);
|
UserRole UpdateUserRole(UserRole userRole);
|
||||||
UserRole GetUserRole(int userRoleId);
|
UserRole GetUserRole(int userRoleId);
|
||||||
UserRole GetUserRole(int userRoleId, bool tracking);
|
UserRole GetUserRole(int userRoleId, bool tracking);
|
||||||
|
UserRole GetUserRole(int userId, int roleId);
|
||||||
|
UserRole GetUserRole(int userId, int roleId, bool tracking);
|
||||||
void DeleteUserRole(int userRoleId);
|
void DeleteUserRole(int userRoleId);
|
||||||
void DeleteUserRoles(int userId);
|
void DeleteUserRoles(int userId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,29 @@ namespace Oqtane.Repository
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UserRole GetUserRole(int userId, int roleId)
|
||||||
|
{
|
||||||
|
return GetUserRole(userId, roleId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UserRole GetUserRole(int userId, int roleId, bool tracking)
|
||||||
|
{
|
||||||
|
if (tracking)
|
||||||
|
{
|
||||||
|
return _db.UserRole
|
||||||
|
.Include(item => item.Role) // eager load roles
|
||||||
|
.Include(item => item.User) // eager load users
|
||||||
|
.FirstOrDefault(item => item.UserId == userId && item.RoleId == roleId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _db.UserRole.AsNoTracking()
|
||||||
|
.Include(item => item.Role) // eager load roles
|
||||||
|
.Include(item => item.User) // eager load users
|
||||||
|
.FirstOrDefault(item => item.UserId == userId && item.RoleId == roleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteUserRole(int userRoleId)
|
public void DeleteUserRole(int userRoleId)
|
||||||
{
|
{
|
||||||
UserRole userRole = _db.UserRole.Find(userRoleId);
|
UserRole userRole = _db.UserRole.Find(userRoleId);
|
||||||
|
|
1
Oqtane.Server/wwwroot/users.csv
Normal file
1
Oqtane.Server/wwwroot/users.csv
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Email,Username,DisplayName,Roles,FirstName,LastName,Street,City,Region,Country,PostalCode,Phone
|
|
Loading…
Reference in New Issue
Block a user