This commit is contained in:
@@ -376,6 +376,31 @@ namespace AyaNova.Api.Controllers
|
||||
return Ok(ApiOkResponse.Response(u.UserType != UserType.Customer && u.UserType != UserType.HeadOffice));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate new random credentials for User
|
||||
/// and email them to the user
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="id">User id</param>
|
||||
/// <param name="apiVersion">From route path</param>
|
||||
/// <returns>NoContent</returns>
|
||||
[HttpPost("generate-creds-email/{id}")]
|
||||
public async Task<IActionResult> GenerateCredsAndEmailUser([FromRoute] long id, ApiVersion apiVersion)
|
||||
{
|
||||
if (!serverState.IsOpen)
|
||||
return StatusCode(503, new ApiErrorResponse(serverState.ApiErrorCode, null, serverState.Reason));
|
||||
UserBiz biz = UserBiz.GetBiz(ct, HttpContext);
|
||||
if (!Authorized.HasModifyRole(HttpContext.Items, biz.BizType))
|
||||
return StatusCode(403, new ApiNotAuthorizedResponse());
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(new ApiErrorResponse(ModelState));
|
||||
bool successfulOperation=await biz.GenerateCredsAndEmailUser(id);
|
||||
if (successfulOperation == false)
|
||||
return BadRequest(new ApiErrorResponse(biz.Errors));
|
||||
else
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
//------------
|
||||
|
||||
}//eoc
|
||||
|
||||
@@ -125,6 +125,8 @@ namespace AyaNova.Biz
|
||||
}//eom
|
||||
|
||||
|
||||
|
||||
|
||||
//This is told about an event and then determines if there are any subscriptions related to that event and proceses them accordingly
|
||||
//todo: this should take some kind of general event type like the AyaEvent types (i.e. which CRUD operation is in effect if relevant)
|
||||
//and also a biz object before and after or just before if not a change and also a AyaType
|
||||
|
||||
@@ -41,7 +41,8 @@ namespace AyaNova.Biz
|
||||
QuoteStatusAge = 29,//* Quote object Created / Updated, conditional on exact status selected IdValue, Tags conditional, advance notice can be set
|
||||
WorkorderFinished = 30, //*Service work order is set to any status that is flagged as a "Finished" type of status. Customer & User
|
||||
WorkorderCreatedForCustomer = 31, //*Service work order is created for Customer, only applies to that customer user notify sub for that customer, customer id is in conditional ID value for subscription
|
||||
WorkorderFinishedFollowUp = 32 //* Service workorder closed status follow up again after this many TIMESPAN
|
||||
WorkorderFinishedFollowUp = 32, //* Service workorder closed status follow up again after this many TIMESPAN
|
||||
SendUserCredentials = 33 // Internal System use only: When user generates new credentials and sends them this is the notification type for that see UserBiz GenerateCredsAndEmailUser
|
||||
|
||||
//NEW ITEMS REQUIRE translation KEYS
|
||||
|
||||
|
||||
@@ -310,6 +310,64 @@ namespace AyaNova.Biz
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// GENERATE AND EMAIL CREDS
|
||||
//
|
||||
internal async Task<bool> GenerateCredsAndEmailUser(long userId)
|
||||
{
|
||||
User dbObject = await ct.User.Include(o => o.UserOptions).FirstOrDefaultAsync(z => z.Id == userId);
|
||||
if (dbObject == null)
|
||||
{
|
||||
AddError(ApiErrorCode.NOT_FOUND);
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(dbObject.UserOptions.EmailAddress))
|
||||
{
|
||||
AddError(ApiErrorCode.VALIDATION_REQUIRED, "EmailAddress");
|
||||
return false;
|
||||
}
|
||||
var ServerUrl = ServerGlobalOpsSettingsCache.Notify.AyaNovaServerURL;
|
||||
if (string.IsNullOrWhiteSpace(ServerUrl))
|
||||
{
|
||||
await NotifyEventProcessor.AddOpsProblemEvent("User::GenerateCredsAndEmailUser - The OPS Notification setting is empty for AyaNova Server URL. This prevents Notification system from linking events to openable objects.");
|
||||
AddError(ApiErrorCode.VALIDATION_REQUIRED, "ServerUrl", "Error: no server url configured in notification settings. Can't direct user to server for login. Set server URL and try again.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var newPassword = Hasher.GetRandomAlphanumericString(32);
|
||||
var newLogin = Hasher.GetRandomAlphanumericString(32);
|
||||
dbObject.Password = Hasher.hash(dbObject.Salt, newPassword);
|
||||
dbObject.Login = newLogin;
|
||||
await ct.SaveChangesAsync();
|
||||
|
||||
//send message
|
||||
ServerUrl = ServerUrl.Trim().TrimEnd('/');
|
||||
|
||||
//Translations
|
||||
List<string> TransKeysRequired = new List<string>();
|
||||
TransKeysRequired.Add("UserLogin");
|
||||
TransKeysRequired.Add("UserPassword");
|
||||
TransKeysRequired.Add("NewCredsMessageBody");
|
||||
TransKeysRequired.Add("NewCredsMessageTitle");
|
||||
long EffectiveTranslationId = dbObject.UserOptions.TranslationId;
|
||||
if (EffectiveTranslationId == 0) EffectiveTranslationId = ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID;
|
||||
var TransDict = await TranslationBiz.GetSubsetStaticAsync(TransKeysRequired, EffectiveTranslationId);
|
||||
var Title = TransDict["NewCredsMessageTitle"];
|
||||
var NewCredsMessage = TransDict["NewCredsMessageBody"];
|
||||
var Creds = $"{TransDict["UserLogin"]}:\n{newLogin}\n{TransDict["UserPassword"]}:\n{newPassword}\n";
|
||||
|
||||
IMailer m = AyaNova.Util.ServiceProviderProvider.Mailer;
|
||||
|
||||
await m.SendEmailAsync(dbObject.UserOptions.EmailAddress, Title, $"{NewCredsMessage}{Creds}{ServerUrl}/home-user-settings", ServerGlobalOpsSettingsCache.Notify);
|
||||
|
||||
//Log modification and save context
|
||||
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified, "GeneratedNewCredentialsAndEmailedToUser"), ct);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task SearchIndexAsync(User obj, bool isNew)
|
||||
{
|
||||
//SEARCH INDEXING
|
||||
@@ -592,7 +650,7 @@ namespace AyaNova.Biz
|
||||
return DownloadUser;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||
namespace AyaNova.Util
|
||||
@@ -32,6 +34,39 @@ namespace AyaNova.Util
|
||||
return Convert.ToBase64String(salt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string GetRandomAlphanumericString(int length)
|
||||
{
|
||||
const string alphanumericCharacters = "0123456789abcdefghijkmnopqrstuvwxyz";
|
||||
return GetRandomString(length, alphanumericCharacters);
|
||||
}
|
||||
|
||||
public static string GetRandomString(int length, IEnumerable<char> characterSet)
|
||||
{
|
||||
if (length < 0)
|
||||
throw new ArgumentException("length must not be negative", "length");
|
||||
if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody
|
||||
throw new ArgumentException("length is too big", "length");
|
||||
if (characterSet == null)
|
||||
throw new ArgumentNullException("characterSet");
|
||||
var characterArray = characterSet.Distinct().ToArray();
|
||||
if (characterArray.Length == 0)
|
||||
throw new ArgumentException("characterSet must not be empty", "characterSet");
|
||||
|
||||
var bytes = new byte[length * 8];
|
||||
new RNGCryptoServiceProvider().GetBytes(bytes);
|
||||
var result = new char[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
ulong value = BitConverter.ToUInt64(bytes, i * 8);
|
||||
result[i] = characterArray[value % (uint)characterArray.Length];
|
||||
}
|
||||
return new string(result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}//eoc
|
||||
|
||||
}//eons
|
||||
Reference in New Issue
Block a user