user import improvements
This commit is contained in:
parent
44f093b2fa
commit
98257de005
|
@ -7,16 +7,16 @@
|
|||
|
||||
<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>
|
||||
<Label Class="col-sm-3" For="importfile" HelpText="Upload or select a tab delimited text file containing user information. The file must be in the Template format specified (Roles can be specified as a comma delimited list)." ResourceKey="ImportFile">Import File:</Label>
|
||||
<div class="col-sm-9">
|
||||
<FileManager Id="userfile" @ref="_filemanager" Filter="csv" />
|
||||
<FileManager Id="importfile" @ref="_filemanager" Filter="txt" />
|
||||
</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>
|
||||
<a class="btn btn-info" href="/users.txt" target="_new">@Localizer["Template"]</a>
|
||||
|
||||
@code {
|
||||
private FileManager _filemanager;
|
||||
|
@ -32,14 +32,17 @@
|
|||
var fileid = _filemanager.GetFileId();
|
||||
if (fileid != -1)
|
||||
{
|
||||
if (await UserService.ImportUsersAsync(PageState.Site.SiteId, fileid))
|
||||
ShowProgressIndicator();
|
||||
var results = await UserService.ImportUsersAsync(PageState.Site.SiteId, fileid);
|
||||
if (bool.Parse(results["Success"]))
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Import.Success"], MessageType.Success);
|
||||
AddModuleMessage(string.Format(Localizer["Message.Import.Success"], results["Rows"], results["Users"]), MessageType.Success);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(Localizer["Message.Import.Failure"], MessageType.Error);
|
||||
}
|
||||
HideProgressIndicator();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -117,11 +117,11 @@
|
|||
<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 name="ImportFile.HelpText" xml:space="preserve">
|
||||
<value>Upload or select a tab delimited text file containing user information. The file must be in the Template format specified (Roles can be specified as a comma delimited list).</value>
|
||||
</data>
|
||||
<data name="UserFile.Text" xml:space="preserve">
|
||||
<value>User File:</value>
|
||||
<data name="ImportFile.Text" xml:space="preserve">
|
||||
<value>Import File:</value>
|
||||
</data>
|
||||
<data name="Error.Import" xml:space="preserve">
|
||||
<value>Error Importing Users</value>
|
||||
|
@ -130,10 +130,10 @@
|
|||
<value>Import</value>
|
||||
</data>
|
||||
<data name="Message.Import.Failure" xml:space="preserve">
|
||||
<value>User Import Failed</value>
|
||||
<value>User Import Failed. Please Review Your Event Log For More Detailed Information.</value>
|
||||
</data>
|
||||
<data name="Message.Import.Success" xml:space="preserve">
|
||||
<value>Users Imported Successfully</value>
|
||||
<value>Users Imported Successfully. {0} Rows Processed, {1} Users Imported.</value>
|
||||
</data>
|
||||
<data name="Message.Import.Validation" xml:space="preserve">
|
||||
<value>You Must Specify A User File For Import</value>
|
||||
|
|
|
@ -148,6 +148,6 @@ namespace Oqtane.Services
|
|||
/// </summary>
|
||||
/// <param name="fileId">ID of a <see cref="File"/></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> ImportUsersAsync(int siteId, int fileId);
|
||||
Task<Dictionary<string, string>> ImportUsersAsync(int siteId, int fileId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -127,9 +127,9 @@ namespace Oqtane.Services
|
|||
return string.Format(passwordValidationCriteriaTemplate, minimumlength, uniquecharacters, digitRequirement, uppercaseRequirement, lowercaseRequirement, punctuationRequirement);
|
||||
}
|
||||
|
||||
public async Task<bool> ImportUsersAsync(int siteId, int fileId)
|
||||
public async Task<Dictionary<string, string>> ImportUsersAsync(int siteId, int fileId)
|
||||
{
|
||||
return await PostJsonAsync<bool>($"{Apiurl}/import?siteid={siteId}&fileid={fileId}", true);
|
||||
return await PostJsonAsync<Dictionary<string, string>>($"{Apiurl}/import?siteid={siteId}&fileid={fileId}", null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -375,7 +375,7 @@ namespace Oqtane.Controllers
|
|||
// POST api/<controller>/import?siteid=x&fileid=y
|
||||
[HttpPost("import")]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public async Task<bool> Import(string siteid, string fileid)
|
||||
public async Task<Dictionary<string, string>> Import(string siteid, string fileid)
|
||||
{
|
||||
if (int.TryParse(siteid, out int SiteId) && SiteId == _tenantManager.GetAlias().SiteId && int.TryParse(fileid, out int FileId))
|
||||
{
|
||||
|
@ -385,7 +385,7 @@ namespace Oqtane.Controllers
|
|||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized User Import Attempt {SiteId} {FileId}", siteid, fileid);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Models;
|
||||
|
||||
|
@ -18,6 +19,6 @@ namespace Oqtane.Managers
|
|||
User VerifyTwoFactor(User user, string token);
|
||||
Task<User> LinkExternalAccount(User user, string token, string type, string key, string name);
|
||||
Task<bool> ValidatePassword(string password);
|
||||
Task<bool> ImportUsers(int siteId, int fileId);
|
||||
Task<Dictionary<string, string>> ImportUsers(int siteId, int fileId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
@ -461,9 +460,10 @@ namespace Oqtane.Managers
|
|||
return result.Succeeded;
|
||||
}
|
||||
|
||||
public async Task<bool> ImportUsers(int siteId, int fileId)
|
||||
public async Task<Dictionary<string, string>> ImportUsers(int siteId, int fileId)
|
||||
{
|
||||
var success = true;
|
||||
int rows = 0;
|
||||
int users = 0;
|
||||
|
||||
var file = _files.GetFile(fileId);
|
||||
|
@ -477,127 +477,160 @@ namespace Oqtane.Managers
|
|||
|
||||
try
|
||||
{
|
||||
string row;
|
||||
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)
|
||||
// header row
|
||||
if (reader.Peek() > -1)
|
||||
{
|
||||
var values = row.Replace("\"", "").Split(',');
|
||||
row = reader.ReadLine();
|
||||
}
|
||||
|
||||
if (values.Length > 3)
|
||||
if (!string.IsNullOrEmpty(row.Trim()))
|
||||
{
|
||||
var header = row.Replace("\"", "").Split('\t');
|
||||
|
||||
// detail rows
|
||||
while (reader.Peek() > -1)
|
||||
{
|
||||
// user
|
||||
var user = _users.GetUser(values[1], values[0]);
|
||||
if (user == null)
|
||||
row = reader.ReadLine();
|
||||
rows++;
|
||||
|
||||
if (!string.IsNullOrEmpty(row.Trim()))
|
||||
{
|
||||
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);
|
||||
var values = row.Replace("\"", "").Split('\t');
|
||||
|
||||
// user
|
||||
var email = (values.Length > 0) ? values[0].Trim() : "";
|
||||
var username = (values.Length > 1) ? values[1].Trim() : "";
|
||||
var displayname = (values.Length > 2) ? values[2].Trim() : "";
|
||||
|
||||
var user = _users.GetUser(username, email);
|
||||
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)
|
||||
user = new User();
|
||||
user.SiteId = siteId;
|
||||
user.Email = values[0];
|
||||
user.Username = (!string.IsNullOrEmpty(username)) ? username : user.Email;
|
||||
user.DisplayName = (!string.IsNullOrEmpty(displayname)) ? displayname : user.Username;
|
||||
user = await AddUser(user);
|
||||
if (user == null)
|
||||
{
|
||||
role = new Role();
|
||||
role.SiteId = siteId;
|
||||
role.Name = rolename;
|
||||
role.Description = rolename;
|
||||
role = _roles.AddRole(role);
|
||||
roles.Add(role);
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "Error Importing User {Email} {Username} {DisplayName}", email, username, displayname);
|
||||
success = false;
|
||||
}
|
||||
if (role != null)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!string.IsNullOrEmpty(displayname))
|
||||
{
|
||||
var userrole = _userRoles.GetUserRole(user.UserId, role.RoleId, false);
|
||||
if (userrole == null)
|
||||
user.DisplayName = displayname;
|
||||
user = await UpdateUser(user);
|
||||
}
|
||||
}
|
||||
|
||||
var rolenames = (values.Length > 3) ? values[3].Trim() : "";
|
||||
if (user != null && !string.IsNullOrEmpty(rolenames))
|
||||
{
|
||||
// roles (comma delimited)
|
||||
foreach (var rolename in rolenames.Split(','))
|
||||
{
|
||||
var role = roles.FirstOrDefault(item => item.Name == rolename.Trim());
|
||||
if (role == null)
|
||||
{
|
||||
userrole = new UserRole();
|
||||
userrole.UserId = user.UserId;
|
||||
userrole.RoleId = role.RoleId;
|
||||
_userRoles.AddUserRole(userrole);
|
||||
role = new Role();
|
||||
role.SiteId = siteId;
|
||||
role.Name = rolename.Trim();
|
||||
role.Description = rolename.Trim();
|
||||
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 (user != null && values.Length > 4)
|
||||
{
|
||||
if (header.Length > index && !string.IsNullOrEmpty(values[index]))
|
||||
// profiles
|
||||
var settings = _settings.GetSettings(EntityNames.User, user.UserId);
|
||||
for (int index = 4; index < values.Length - 1; index++)
|
||||
{
|
||||
var profile = profiles.FirstOrDefault(item => item.Name == header[index]);
|
||||
if (profile != null)
|
||||
if (header.Length > index && !string.IsNullOrEmpty(values[index].Trim()))
|
||||
{
|
||||
var setting = settings.FirstOrDefault(item => item.SettingName == profile.Name);
|
||||
if (setting == null)
|
||||
var profile = profiles.FirstOrDefault(item => item.Name == header[index].Trim());
|
||||
if (profile != 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])
|
||||
var setting = settings.FirstOrDefault(item => item.SettingName == profile.Name);
|
||||
if (setting == null)
|
||||
{
|
||||
setting.SettingValue = values[index];
|
||||
_settings.UpdateSetting(setting);
|
||||
setting = new Setting();
|
||||
setting.EntityName = EntityNames.User;
|
||||
setting.EntityId = user.UserId;
|
||||
setting.SettingName = profile.Name;
|
||||
setting.SettingValue = values[index].Trim();
|
||||
_settings.AddSetting(setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (setting.SettingValue != values[index].Trim())
|
||||
{
|
||||
setting.SettingValue = values[index].Trim();
|
||||
_settings.UpdateSetting(setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
users++;
|
||||
}
|
||||
|
||||
users++;
|
||||
}
|
||||
|
||||
row = reader.ReadLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import File Contains No Header Row");
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "{Users} Users Imported", users);
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Create, "User Import: {Rows} Rows Processed, {Users} Users Imported", rows, users);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, ex, "Error Importing User Import File {SiteId} {FileId}", siteId, fileId);
|
||||
success = false;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, ex, "Error Importing User Import File {SiteId} {FileId}", siteId, fileId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create,"User Import File Does Not Exist {Path}", path);
|
||||
success = false;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import File Does Not Exist {Path}", path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import File Does Not Exist {SiteId} {FileId}", siteId, fileId);
|
||||
success = false;
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Create, "User Import File Does Not Exist {SiteId} {FileId}", siteId, fileId);
|
||||
}
|
||||
|
||||
return success;
|
||||
// return results
|
||||
var result = new Dictionary<string, string>();
|
||||
result.Add("Success", success.ToString());
|
||||
result.Add("Rows", rows.ToString());
|
||||
result.Add("Users", users.ToString());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Email,Username,DisplayName,Roles,FirstName,LastName,Street,City,Region,Country,PostalCode,Phone
|
|
1
Oqtane.Server/wwwroot/users.txt
Normal file
1
Oqtane.Server/wwwroot/users.txt
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