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));
|
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
|
}//eoc
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ namespace AyaNova.Biz
|
|||||||
}//eom
|
}//eom
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//This is told about an event and then determines if there are any subscriptions related to that event and proceses them accordingly
|
//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)
|
//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
|
//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
|
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
|
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
|
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
|
//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)
|
private async Task SearchIndexAsync(User obj, bool isNew)
|
||||||
{
|
{
|
||||||
//SEARCH INDEXING
|
//SEARCH INDEXING
|
||||||
@@ -592,7 +650,7 @@ namespace AyaNova.Biz
|
|||||||
return DownloadUser;
|
return DownloadUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||||
namespace AyaNova.Util
|
namespace AyaNova.Util
|
||||||
@@ -32,6 +34,39 @@ namespace AyaNova.Util
|
|||||||
return Convert.ToBase64String(salt);
|
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
|
}//eoc
|
||||||
|
|
||||||
}//eons
|
}//eons
|
||||||
Reference in New Issue
Block a user