public async Task <string> UpdateUserInfo([FromBody] JObject user) { try { if (user != null) //Confirm non-null input data { StringConversion stringConversion = new StringConversion(); Guid myId = Guid.Parse(stringConversion.DecryptString(Convert.ToString(user["UpdatedId"]))); bool confirmed = false; string emailConfirmed = Convert.ToString(user["EmailConfirmed"]); if (!string.IsNullOrEmpty(emailConfirmed)) { confirmed = true; } User edituser = new User { Id = myId, Active = Convert.ToBoolean(user["Active"]), Email = Convert.ToString(user["Email"]), FirstName = Convert.ToString(user["FirstName"]), LastName = Convert.ToString(user["LastName"]), Username = Convert.ToString(user["Username"]), EmailConfirmed = Convert.ToBoolean(confirmed), Deleted = false }; var extendUserResponse = await _bosAuthClient.ExtendUserAsync(edituser); if (extendUserResponse != null && extendUserResponse.IsSuccessStatusCode) { return("User's information updated successfully"); //On success, returning the message } else if (extendUserResponse != null && extendUserResponse.StatusCode == System.Net.HttpStatusCode.Unauthorized) { return("Token Expired, Please try again");//Token Expired } else { //Else, return the BOS error message. An example could be, if there is no user with the id return(extendUserResponse != null ? extendUserResponse.BOSErrors[0].Message : "We are unable to update this user's information at this time. Please try again."); } } else { return("User data cannot be null. Please try again"); } } catch (Exception ex) { Logger.LogException("Users", "UpdateUserInfo", ex); return(ex.Message); } }
public void TryParseGBWithUSDate() { var expected = new DateTime(1799, 01, 02); var dtString = GetFormattedDate(expected, @"MM/dd/yyyy"); var actual = StringConversion.StringToDateTime(dtString, @"dd/MM/yyyy", "/", ":", false); // this should be parsed Assert.IsNotNull(actual); // but its wrong Assert.AreNotEqual(expected, actual); expected = new DateTime(1799, 12, 31); dtString = GetFormattedDate(expected, @"MM/dd/yyyy"); actual = StringConversion.StringToDateTime(dtString, @"dd/MM/yyyy", ".", ":", false); // this should not be read Assert.IsNull(actual); }
public void ParseStringToDateTimeSerialDate() { // 01:00:00 var actual = StringConversion.StringToDateTime("0.0416666666666667", @"mm\dd\yyyy", @"\", ":", true); Assert.AreEqual(new DateTime(1899, 12, 30, 1, 0, 0, 0), actual); // 00:00:00 actual = StringConversion.StringToDateTime("1", @"mm\dd\yyyy", @"\", ":", true); Assert.AreEqual(new DateTime(1899, 12, 31, 0, 0, 0, 0), actual); // 29/06/1968 15:23:00 actual = StringConversion.StringToDateTime("25018.6409722222", @"mm\dd\yyyy", @"\", ":", true); Assert.AreEqual(new DateTime(1968, 06, 29, 15, 23, 00, 0), actual); //22/07/2014 12:50:00 actual = StringConversion.StringToDateTime("41842.5347222222", @"mm\dd\yyyy", @"\", ":", true); Assert.AreEqual(new DateTime(2014, 07, 22, 12, 50, 00, 0), actual); }
public static UserDTO Map(UserBO user, IZeus zeus) { UserDTO self = new UserDTO { UserId = user.Id, Email = user.Email, Username = user.StaffUserName, FirstName = user.FirstName, LastName = user.LastName, MiddleName = user.MiddleName, FullName = user.FirstName + " " + user.LastName, JobDescription = user.JobDescription, }; self.OrganizationId = user.OrganizationId; self.Roles = StringConversion.ConvertToString(self.UserRoles); return(self); }
public void DateTimeToStringOK() { // Assert.AreEqual("01/01/2010", StringConversion.DateTimeToString(new DateTime(2010, 01, 1), null)); Assert.AreEqual("13/01/2010 10:11", StringConversion.DateTimeToString(new DateTime(2010, 1, 13, 10, 11, 14, 0), new ValueFormatMutable { DateFormat = @"dd/MM/yyyy HH:mm" })); // Make sure exchanging the default separators do not mess with the result Assert.AreEqual("13:01:2010 10/11", StringConversion.DateTimeToString(new DateTime(2010, 1, 13, 10, 11, 14, 0), new ValueFormatMutable { DateFormat = @"dd/MM/yyyy HH:mm", TimeSeparator = "/", DateSeparator = ":" })); // 24 + 24 + 7 = 55 hrs Assert.AreEqual("055:11", StringConversion.DateTimeToString( StringConversion.GetTimeFromTicks(new TimeSpan(2, 7, 11, 0).Ticks), new ValueFormatMutable { DateFormat = @"HHH:mm", TimeSeparator = ":", DateSeparator = "." })); }
protected override void Prepare() { Schema = DefaultWhereNull(Schema, () => "dbo"); DbTable = Root !.DbTables.Where(x => x.Name == Name && x.Schema == Schema).SingleOrDefault(); if (DbTable == null) { throw new CodeGenException($"Specified Schema.Table '{Schema}.{Name}' not found in database."); } Alias = DefaultWhereNull(Alias, () => new string(StringConversion.ToSentenceCase(Name) !.Split(' ').Select(x => x.Substring(0, 1).ToLower(System.Globalization.CultureInfo.InvariantCulture).ToCharArray()[0]).ToArray())); foreach (var c in DbTable.Columns) { if ((ExcludeColumns == null || !ExcludeColumns.Contains(c.Name)) && (IncludeColumns == null || IncludeColumns.Contains(c.Name))) { DbColumns.Add(c); } } }
public async Task ForcePasswordChange_returns_error_message_when_password_is_null() { //Arrange var controller = new AuthController(_bosAuthClient, _bosIAClient, _bosEmailClient, _configuration); dynamic passwordInfo = new ExpandoObject(); StringConversion stringConversion = new StringConversion(); string userId = stringConversion.EncryptString(Guid.NewGuid().ToString()); passwordInfo.userId = userId; passwordInfo.password = null; JObject data = JObject.FromObject(passwordInfo); //Act var result = await controller.ForcePasswordChange(data); //Assert var errorMessage = Assert.IsType <string>(result); //Asserting that the return is a string Assert.Contains("Something went wrong", errorMessage.ToString()); //Asserting that the returned message matches to the one mentioned }
private async Task <dynamic> GetPageData() { var moduleOperations = HttpContext.Session.GetObject <List <Module> >("ModuleOperations"); Guid currentModuleId = new Guid(); try { currentModuleId = moduleOperations.Where(i => i.Code == "USERS").Select(i => i.Id).ToList()[0]; } catch (ArgumentNullException) { currentModuleId = Guid.Empty; } var currentOperations = moduleOperations.Where(i => i.Id == currentModuleId).Select(i => i.Operations).ToList()[0]; string operationsString = String.Join(",", currentOperations.Select(i => i.Code)); dynamic model = new ExpandoObject(); model.ModuleOperations = HttpContext.Session.GetObject <List <Module> >("ModuleOperations"); model.Operations = operationsString; model.CurrentModuleId = currentModuleId; if (User.FindFirst(c => c.Type == "Username") != null || User.FindFirst(c => c.Type == "Role") != null) { model.Username = User.FindFirst(c => c.Type == "Username").Value.ToString(); model.Roles = User.FindFirst(c => c.Type == "Role").Value.ToString(); } StringConversion stringConversion = new StringConversion(); var userList = await _bosAuthClient.GetUsersWithRolesAsync <User>(); if (userList.IsSuccessStatusCode) { var updatedUserList = userList.Users.Select(c => { c.UpdatedId = stringConversion.EncryptString(c.Id.ToString()); return(c); }).ToList(); model.UserList = updatedUserList; } return(model); }
public async Task ForcePasswordChange_returns_error_string_when_userid_is_invalid() { //Arrange var controller = new AuthController(_configuration, _contextAccessor, multitenantService); dynamic passwordInfo = new ExpandoObject(); StringConversion stringConversion = new StringConversion(); string userId = stringConversion.EncryptString(Guid.NewGuid().ToString()); passwordInfo.userId = userId; passwordInfo.password = "******"; JObject data = JObject.FromObject(passwordInfo); //Act var result = await controller.ForcePasswordChange(data); //Assert var errorMessage = Assert.IsType <string>(result); //Asserting that the return is a string Assert.Contains("Something went wrong.", errorMessage.ToString()); //Asserting that the returned message matches to the one mentioned }
private async Task <dynamic> GetPageData() { var modules = HttpContext.Session.GetObject <List <Module> >("Modules"); dynamic model = new ExpandoObject(); model.Modules = modules; if (User.FindFirst(c => c.Type == "Username") != null || User.FindFirst(c => c.Type == "Role") != null) { model.Username = User.FindFirst(c => c.Type == "Username").Value.ToString(); model.Roles = User.FindFirst(c => c.Type == "Role").Value.ToString(); } StringConversion stringConversion = new StringConversion(); var userList = await _bosAuthClient.GetUsersWithRolesAsync <User>(); if (userList.IsSuccessStatusCode) { var updatedUserList = userList.Users.Select(c => { c.UpdatedId = stringConversion.EncryptString(c.Id.ToString()); return(c); }).ToList(); model.UserList = updatedUserList; } return(model); }
/// <summary> /// Writes the XML attribues as YAML. /// </summary> private static void WriteAttributes(YamlFormatArgs args, ConfigType ct, ConfigurationEntity ce, Type type, XElement xml) { var needsComma = false; foreach (var att in xml.Attributes()) { var jname = XmlYamlTranslate.GetYamlName(ct, ce, att.Name.LocalName); var pi = type.GetProperty(StringConversion.ToPascalCase(jname) !); var val = XmlYamlTranslate.GetYamlValue(ct, ce, att.Name.LocalName, att.Value); if (val == null) { continue; } if (pi == null || pi.GetCustomAttribute <JsonPropertyAttribute>() == null) { jname = att.Name.LocalName; args.UnknownAttributes.Add($"{xml.Name.LocalName}.{jname} = {val}"); } if (needsComma) { args.Writer.Write(", "); } args.HasAttributes = true; args.Writer.Write($"{jname}: {val}"); if (args.Indent > 0) { needsComma = true; } else { args.Writer.WriteLine(); } } }
/// <remarks> /// See <a href="https://support.office.com/en-gb/article/ROUNDUP-function-f8bc9b23-e795-47db-8703-db171d0c42a7">this link</a> for more information. /// </remarks> private static void RoundUpFunction(IFunctionArgs args, IExcelCaller caller) { if (args.Parameters.Length != 2) { throw new ArgumentException("ROUNDUP function takes 2 arguments, " + $"got {args.Parameters.Length}"); } var arg1 = args.Parameters[0].Evaluate(); if (arg1 is ErrorValue) { args.Result = arg1; return; } var arg2 = args.Parameters[1].Evaluate(); if (arg2 is ErrorValue) { args.Result = arg2; return; } var @double = StringConversion.ToDouble(arg1); var negative = @double < 0; // This code snippet based on example at http://stackoverflow.com/a/13483008 var @decimal = new decimal(Math.Abs(@double)); var places = Convert.ToInt32(arg2); var factor = RoundFactor(places); @decimal *= factor; @decimal = Math.Ceiling(@decimal); @decimal /= factor; args.Result = Convert.ToDouble(negative ? -@decimal : @decimal); }
/// <summary> /// Gets all possible formats based on the provided value /// </summary> /// <param name="value">The value.</param> /// <returns></returns> public static IEnumerable <ValueFormat> GetAllPossibleFormats(string value, CultureInfo culture = null) { if (culture == null) { culture = CultureInfo.CurrentCulture; } // Standard Date Time formats foreach (var fmt in StringConversion.StandardDateTimeFormats.MatchingforLength(value.Length, true)) { foreach (var sep in StringConversion.DateSeparators) { if (StringConversion.StringToDateTimeExact(value, fmt, sep, culture.DateTimeFormat.TimeSeparator, culture).HasValue) { yield return(new ValueFormat(DataType.DateTime) { DateFormat = fmt, DateSeparator = sep, }); } } } }
public void TestConvertDateToString() { var dateTime = new DateTime(2001, 10, 17, 12, 01, 02, 00); var actual = StringConversion.DateTimeToString(dateTime, @"yyyyMMdd", "", "-"); Assert.AreEqual("20011017", actual); actual = StringConversion.DateTimeToString(dateTime, @"yyyy/MM/dd HH:mm:ss", "/", ":"); Assert.AreEqual("2001/10/17 12:01:02", actual); dateTime = new DateTime(2001, 10, 17, 12, 01, 02, 09); actual = StringConversion.DateTimeToString(dateTime, @"yyyyMMdd HH:mm:ss.fff", "", "-"); Assert.AreEqual("20011017 12-01-02.009", actual); actual = StringConversion.DateTimeToString(dateTime, @"yyyy/MM/dd HH:mm:ss.fff", "/", ":"); Assert.AreEqual("2001/10/17 12:01:02.009", actual); // nonsense value for date separator actual = StringConversion.DateTimeToString(dateTime, @"yyyy-MM-dd HH:mm:ss.fff", "-", ":"); Assert.AreEqual("2001-10-17 12:01:02.009", actual); }
public bool TrySetValue(ICommand target, IEnumerable <string> values) { var pi = target.GetType().GetProperty(_propertyName); var destinationType = pi.PropertyType; if (IsValueRequired == false && values.Count() == 0) { if (destinationType == typeof(bool)) { pi.SetValue(target, true, null); } else if (destinationType.IsValueType) { pi.SetValue(target, Activator.CreateInstance(destinationType), null); } else { pi.SetValue(target, null, null); } return(true); } object value; if (!StringConversion.TryConvert(destinationType, values, out value)) { return(false); } try { pi.SetValue(target, value, null); return(true); } catch { } return(false); }
public async Task <string> ForcePasswordChange([FromBody] JObject data) { try { if (data != null) { StringConversion stringConversion = new StringConversion(); string userId = stringConversion.DecryptString(data["userId"].ToString()); //Decrypting the userId sent from the View string password = data["password"].ToString(); var response = await _bosAuthClient.ForcePasswordChangeAsync(Guid.Parse(userId), password); //Making an call to the BOS API to ForceChange the Password. This is done because at this point there is no way of knowing the user's original password if (response != null && response.StatusCode == System.Net.HttpStatusCode.Unauthorized) { return("Token Expired, Please login again"); } if (response != null && response.IsSuccessStatusCode) { return("Password updated successfully"); //On success, returing a message } else { Logger.LogException("Auth", "ForcePasswordChange", null); return("Something went wrong. We are not able to change the password at this moment. Please try again later."); } } else { return("Data cannot be null"); } } catch (Exception ex) { Logger.LogException("Auth", "ForcePasswordChange", ex); return("Something went wrong. We are not able to change the password at this moment. Please try again later."); } }
public async Task <string> DeleteUser([FromBody] string userId) { try { if (!string.IsNullOrEmpty(userId)) //Confirming a non-null, non-empty userId { StringConversion stringConversion = new StringConversion(); string actualUserId = stringConversion.DecryptString(userId); //Since the userId sent to the view is encrypted, before sending it to the BOS API, we have to decrypt it var response = await _bosAuthClient.DeleteUserAsync(Guid.Parse(actualUserId)); //Making an API call to BOS to delete the user if (response != null && response.IsSuccessStatusCode) { return("User deleted successfully"); //On success, return the message } else if (response != null && response.StatusCode == System.Net.HttpStatusCode.Unauthorized) { return("Token Expired, Please try again");//Token Expired } else { return(response != null ? response.BOSErrors[0].Message : "We are unable to delete this user at this time. Please try again."); //Else, return the BOS error message //An example could be, if there is no user with the id } } else { return("UserId cannot be null. Please check and try again."); } } catch (Exception ex) { Logger.LogException("Users", "DeleteUser", ex); return(ex.Message); } }
public static UserTaskDTO Map(UserTaskBO userTask, IZeus zeus) { UserTaskDTO self = new UserTaskDTO { UserTaskId = userTask.Id, TaskTitle = userTask.Title, Description = userTask.Description, AssignedToId = userTask.UserId, Percentage = DateExtension.PercentageProgressBetweenDates(userTask.BeginDate, userTask.EndDate), PercentageComplete = DateExtension.PercentageProgressBetweenDates(userTask.BeginDate, userTask.EndDate).ToString() + "%", DateCreated = DateExtension.ConvertDateToShort(userTask.DateCreated), Deadline = DateExtension.ConvertDateToShort(userTask.EndDate), BeginDate = DateExtension.ConvertDateToShort(userTask.BeginDate), CreateDate = userTask.DateCreated, UserTaskHtmlId = StringConversion.ConvertGuidToString(userTask.Id), TaskHtmlId = StringConversion.ConvertGuidToString(userTask.Id) }; self.AssignedTo = userTask.User == null ? "" : userTask.User.FirstName + " " + userTask.User.LastName; //get list of measure/target return(self); }
protected string TextEncodeField([NotNull] IFileFormat fileFormat, object dataObject, [NotNull] WriterColumn columnInfo, bool isHeader, [CanBeNull] IDataReader reader, [CanBeNull] Func <string, DataType, IFileFormat, string> handleQualify) { if (columnInfo is null) { throw new ArgumentNullException(nameof(columnInfo)); } if (fileFormat.IsFixedLength && columnInfo.FieldLength == 0) { throw new FileWriterException("For fix length output the length of the columns needs to be specified."); } string displayAs; if (isHeader) { if (dataObject is null) { throw new ArgumentNullException(nameof(dataObject)); } displayAs = dataObject.ToString(); } else { try { if (dataObject == null || dataObject is DBNull) { displayAs = columnInfo.ValueFormat.DisplayNullAs; } else { switch (columnInfo.ValueFormat.DataType) { case DataType.Integer: displayAs = Convert.ToInt64(dataObject).ToString(columnInfo.ValueFormat.NumberFormat, CultureInfo.InvariantCulture).Replace( CultureInfo.InvariantCulture.NumberFormat.NumberGroupSeparator, columnInfo.ValueFormat.GroupSeparator); break; case DataType.Boolean: displayAs = (bool)dataObject ? columnInfo.ValueFormat.True : columnInfo.ValueFormat.False; break; case DataType.Double: displayAs = StringConversion.DoubleToString( dataObject is double d ? d : Convert.ToDouble(dataObject.ToString(), CultureInfo.InvariantCulture), columnInfo.ValueFormat); break; case DataType.Numeric: displayAs = StringConversion.DecimalToString( dataObject is decimal @decimal ? @decimal : Convert.ToDecimal(dataObject.ToString(), CultureInfo.InvariantCulture), columnInfo.ValueFormat); break; case DataType.DateTime: displayAs = reader == null ? StringConversion.DateTimeToString((DateTime)dataObject, columnInfo.ValueFormat) : StringConversion.DateTimeToString(HandleTimeZone((DateTime)dataObject, columnInfo, reader), columnInfo.ValueFormat); break; case DataType.Guid: // 382c74c3-721d-4f34-80e5-57657b6cbc27 displayAs = ((Guid)dataObject).ToString(); break; case DataType.String: case DataType.TextToHtml: case DataType.TextToHtmlFull: case DataType.TextPart: displayAs = dataObject.ToString(); if (columnInfo.ValueFormat.DataType == DataType.TextToHtml) { displayAs = HTMLStyle.TextToHtmlEncode(displayAs); } // a new line of any kind will be replaced with the placeholder if set if (fileFormat.NewLinePlaceholder.Length > 0) { displayAs = StringUtils.HandleCRLFCombinations(displayAs, fileFormat.NewLinePlaceholder); } if (fileFormat.DelimiterPlaceholder.Length > 0 && fileFormat.FieldDelimiterChar != '\0') { displayAs = displayAs.Replace(fileFormat.FieldDelimiterChar.ToStringHandle0(), fileFormat.DelimiterPlaceholder); } if (fileFormat.QuotePlaceholder.Length > 0 && fileFormat.FieldQualifierChar != '\0') { displayAs = displayAs.Replace(fileFormat.FieldQualifierChar.ToStringHandle0(), fileFormat.QuotePlaceholder); } break; default: displayAs = string.Empty; break; } } } catch (Exception ex) { // In case a cast did fail (eg.g trying to format as integer and providing a text, use the // original value displayAs = dataObject?.ToString() ?? string.Empty; if (string.IsNullOrEmpty(displayAs)) { HandleError(columnInfo.Name, ex.Message); } else { HandleWarning(columnInfo.Name, "Value stored as: " + displayAs + $"\nExpected {columnInfo.ValueFormat.DataType} but was {dataObject?.GetType()}" + ex.Message); } } } // Adjust the output in case its is fixed length if (fileFormat.IsFixedLength) { if (displayAs.Length <= columnInfo.FieldLength || columnInfo.FieldLength <= 0) { return(displayAs.PadRight(columnInfo.FieldLength, ' ')); } HandleWarning(columnInfo.Name, $"Text with length of {displayAs.Length} has been cut off after {columnInfo.FieldLength} character"); return(displayAs.Substring(0, columnInfo.FieldLength)); } // Qualify text if required if (fileFormat.FieldQualifierChar != '\0' && handleQualify != null) { return(handleQualify(displayAs, columnInfo.ValueFormat.DataType, fileFormat)); } return(displayAs); }
/// <summary> /// <inheritdoc/> /// </summary> protected override void Prepare() { DefaultWhereNull(Text, () => StringConversion.ToSentenceCase(Name)); }
/// <summary> /// Author: BOS Framework, Inc /// Description: Is triggered when the 'Edit' link is clicked. Returns the view with the form to edit the selected user, with the information pre-filled. /// </summary> /// <param name="userId"></param> /// <returns></returns> public async Task <IActionResult> EditUser(string userId) { try { /*-------- LOGIC ---------- * Confirm non-null userId sent as the input * Decrypt the userId to get the actual userId * Get the user's information and associated roles via BOS API call * Get all the roles in the application * Prepare the model object that is required to render the page * Navigate to the "EditUsewr" view with data */ if (!string.IsNullOrEmpty(userId)) //Checking for a non-null, non-empty userId { dynamic model = await GetPageData(); //Getting the data that is required for rendering the page if (model == null) { model = new ExpandoObject(); //If the method returns null, then re-ininitate a dynamic object } StringConversion stringConversion = new StringConversion(); string actualUserId = stringConversion.DecryptString(userId); //The userID that is sent to the view is encrypted. Before sending it to the BOS API, we'll have to decrypt it var userInfo = await _bosAuthClient.GetUserByIdWithRolesAsync <User>(Guid.Parse(actualUserId)); //Making an API call to BOS to get the user's information together with the associated roles if (userInfo != null && userInfo.IsSuccessStatusCode && userInfo.User != null) { userInfo.User.UpdatedId = userId; //Setting rhe updated (encrypted) userID, so it can be used in the View model.UserInfo = userInfo.User; //User's data is assigned to the model List <string> rolesList = new List <string>(); foreach (UserRole role in userInfo.User.Roles) { rolesList.Add(role.Role.Name); } model.RolesList = rolesList; //All the roles that the user is already associated with } var availableRoles = await _bosAuthClient.GetRolesAsync <Role>(); //Making a BOS API Call to fetch all the Roles in the application if (availableRoles != null && availableRoles.IsSuccessStatusCode) { model.AvailableRoles = availableRoles.Roles; //On success, setting the complete Roles list } return(View("EditUser", model)); //Returning to the "EditUser" view, that has the form to edit user's information and roles, with the data required to render the page } else { ModelState.AddModelError("CustomError", "The selected user has inaccurate id. Please try again."); return(View("Index", await GetPageData())); } } catch (Exception ex) { Logger.LogException("Users", "EditUser", ex); dynamic model = new ExpandoObject(); model.Message = ex.Message; model.StackTrace = ex.StackTrace; return(View("ErrorPage", model)); } }
/// <summary> /// Author: BOS Framework, Inc /// Description: Private method to fetch the data necessary to render the page /// </summary> /// <returns></returns> private async Task <dynamic> GetPageData() { try { //Checking if Sessions are enabled and non-null if (HttpContext != null && HttpContext.Session != null) { var moduleOperations = HttpContext.Session.GetObject <List <Module> >("ModuleOperations"); //This is the list of permitted modules and operations to the logged-in user Guid currentModuleId = new Guid(); // A new variable to save the current or selected module Id. This is being used, especially in the custom modules → more for the UI purposes try { currentModuleId = moduleOperations.Where(i => i.Code == "USERS").Select(i => i.Id).ToList()[0]; //Selecting the moduledD for MyProfile } catch { currentModuleId = Guid.Empty; } var operationsList = moduleOperations.Where(i => i.Id == currentModuleId).Select(i => i.Operations).ToList(); //Fetching the allowed operations in this module for the given user string operationsString = string.Empty; if (operationsList.Count > 0) { var currentOperations = operationsList[0]; operationsString = String.Join(",", currentOperations.Select(i => i.Code)); //Converting the list of operations to a string, so it can be used in the View } //Preparing the dynamic object that has data used for rendering the page dynamic model = new ExpandoObject(); model.ModuleOperations = moduleOperations; model.Operations = operationsString; model.CurrentModuleId = currentModuleId; //Checking for non-null claims object if (User != null) { model.Initials = User.FindFirst(c => c.Type == "Initials")?.Value.ToString(); model.Username = User.FindFirst(c => c.Type == "Username")?.Value.ToString(); model.Roles = User.FindFirst(c => c.Type == "Role")?.Value.ToString(); } StringConversion stringConversion = new StringConversion(); var userList = await _bosAuthClient.GetUsersWithRolesAsync <User>(); //Getting the list of all the users in the application using the BOS API if (userList != null && userList.IsSuccessStatusCode) { var updatedUserList = userList.Users.Select(c => { c.UpdatedId = stringConversion.EncryptString(c.Id.ToString()); return(c); }).ToList(); //Updating the user object with the encrypted userid, which will be used in the View and for passing into APIs from the view to the controller model.UserList = updatedUserList; } return(model); //Returning the mode with all the data that is required to render the page } else { return(null); } } catch (Exception ex) { Logger.LogException("Users", "GetPageData", ex); return(null); } }
public async Task <string> ChangeUserActiveStatus([FromBody] JObject data) { try { if (data != null) { if (data["UserId"] == null) { return("UserId cannot be null"); } else if (data["Action"] == null) { return("Action cannot be null"); } StringConversion stringConversion = new StringConversion(); string actualUserId = stringConversion.DecryptString(data["UserId"]?.ToString()); //Since the userId sent to the view is encrypted, before sending it to the BOS API, we have to decrypt it var action = data["Action"]?.ToString(); //Based on the action that has been requested, we either make a call to the BOS' ActivateUser API or DeactivateUser API if (action == "activate") { var response = await _bosAuthClient.ActivateUserAsync(Guid.Parse(actualUserId)); //Making the BOS API call with the userId if (response != null && response.IsSuccessStatusCode) { return("The user has been activated successfully"); //On success, returning an appropriate message } else { return(response.BOSErrors[0].Message); //On error, returing the BOS error message } } else if (action == "deactivate") { var response = await _bosAuthClient.DeactivateUserAsync(Guid.Parse(actualUserId)); //Making the BOS API call with the userId if (response != null && response.IsSuccessStatusCode) { return("The user has been deactivated successfully"); //On success, returning an appropriate message } else { return(response.BOSErrors[0].Message); //On error, returing the BOS error message } } else { return("You are trying to perform an unrecognized operation"); } } else { return("Data cannot be null"); } } catch (Exception ex) { Logger.LogException("Users", "ChangeUserActiveStatus", ex); return(ex.Message); } }
/// <summary> /// Registers all of the required Handlebars helpers. /// </summary> public static void RegisterHelpers() { if (_areRegiestered) { return; } _areRegiestered = true; // Will check that the first argument equals at least one of the subsequent arguments. Handlebars.RegisterHelper("ifeq", (writer, context, parameters, args) => { if (!CheckArgs("ifeq", writer, args)) { return; } if (IfEq(args)) { context.Template(writer, parameters); } else { context.Inverse(writer, parameters); } }); // Will check that the first argument does not equal any of the subsequent arguments. Handlebars.RegisterHelper("ifne", (writer, context, parameters, args) => { if (!CheckArgs("ifne", writer, args)) { return; } if (IfEq(args)) { context.Inverse(writer, parameters); } else { context.Template(writer, parameters); } }); // Will check that all of the arguments have a non-<c>null</c> value. Handlebars.RegisterHelper("ifval", (writer, context, parameters, args) => { if (!CheckArgs("ifval", writer, args)) { return; } foreach (var arg in args) { if (arg == null) { context.Inverse(writer, parameters); return; } } context.Template(writer, parameters); }); // Will check that all of the arguments have a <c>null</c> value. Handlebars.RegisterHelper("ifnull", (writer, context, parameters, args) => { if (!CheckArgs("ifnull", writer, args)) { return; } foreach (var arg in args) { if (arg != null) { context.Inverse(writer, parameters); return; } } context.Template(writer, parameters); }); // Will check that all of the arguments have a <c>true</c> value where bool; otherwise, non-null. Handlebars.RegisterHelper("ifor", (writer, context, parameters, args) => { if (!CheckArgs("ifor", writer, args)) { return; } foreach (var arg in args) { if (arg is bool opt) { if (opt) { context.Template(writer, parameters); return; } } else if (arg != null) { context.Template(writer, parameters); return; } } context.Inverse(writer, parameters); }); // Converts a value to lowercase. #pragma warning disable CA1308 // Normalize strings to uppercase; this is an explicit and required call to lowercase. Handlebars.RegisterHelper("lower", (writer, context, parameters) => writer.WriteSafeString(parameters.FirstOrDefault()?.ToString()?.ToLowerInvariant() ?? "")); #pragma warning restore CA1308 // Converts a value to camelcase. Handlebars.RegisterHelper("camel", (writer, context, parameters) => writer.WriteSafeString(StringConversion.ToCamelCase(parameters.FirstOrDefault()?.ToString()) ?? "")); // Converts a value to pascalcase. Handlebars.RegisterHelper("pascal", (writer, context, parameters) => writer.WriteSafeString(StringConversion.ToPascalCase(parameters.FirstOrDefault()?.ToString()) ?? "")); // Converts a value to the c# '<see cref="value"/>' comments equivalent. Handlebars.RegisterHelper("seecomments", (writer, context, parameters) => writer.WriteSafeString(Beef.CodeGen.CodeGenerator.ToSeeComments(parameters.FirstOrDefault()?.ToString()))); // Adds a value to a value. Handlebars.RegisterHelper("add", (writer, context, parameters) => { int sum = 0; foreach (var p in parameters) { if (p is int pi) { sum += pi; } else if (p is string ps) { sum += int.Parse(ps, NumberStyles.Integer, CultureInfo.InvariantCulture); } else { writer.WriteSafeString("!!! add with invalid integer !!!"); } } writer.WriteSafeString(sum); }); }
/// <summary> /// Guesses the value format. /// </summary> /// <param name="cancellationToken">A cancellation token</param> /// <param name="samples">The samples.</param> /// <param name="minRequiredSamples">The minimum required samples.</param> /// <param name="trueValue">The text to be regarded as <c>true</c></param> /// <param name="falseValue">The text to be regarded as <c>false</c></param> /// <param name="guessBoolean">Try to identify a boolean</param> /// <param name="guessGuid">Try to determine if its a GUID</param> /// <param name="guessNumeric">Try to determine if its a Number</param> /// <param name="guessDateTime">Try to determine if it is a date time</param> /// <param name="guessPercentage">Accept percentage values</param> /// <param name="serialDateTime">Allow serial Date time</param> /// <param name="checkNamedDates">if set to <c>true</c> [check named dates].</param> /// <returns><c>Null</c> if no format could be determined otherwise a <see cref="ValueFormat" /></returns> public static CheckResult GuessValueFormat(IList <string> samples, int minRequiredSamples, string trueValue, string falseValue, bool guessBoolean, bool guessGuid, bool guessNumeric, bool guessDateTime, bool guessPercentage, bool serialDateTime, bool checkNamedDates, ValueFormat othersValueFormatDate, CancellationToken cancellationToken) { Contract.Requires(samples != null); if (samples.IsEmpty()) { return(null); } var count = samples.Count(); var checkResult = new CheckResult { FoundValueFormat = new ValueFormat() }; // if it only one sample value and its false, assume its a boolean if (guessBoolean && count == 1 && !string.IsNullOrEmpty(falseValue)) { foreach (var value in samples) { if (value.Equals(falseValue, StringComparison.OrdinalIgnoreCase)) { checkResult.FoundValueFormat.DataType = DataType.Boolean; return(checkResult); } break; } } if (cancellationToken.IsCancellationRequested) { return(null); } // this could be a boolean if (guessBoolean && count <= 2) { var allParsed = true; string usedTrueValue = null; string usedFalseValue = null; foreach (var value in samples) { var result = StringConversion.StringToBooleanStrict(value, trueValue, falseValue); if (result == null) { allParsed = false; break; } if (result.Item1) { usedTrueValue = result.Item2; } else { usedFalseValue = result.Item2; } } if (allParsed) { checkResult.FoundValueFormat.DataType = DataType.Boolean; if (!string.IsNullOrEmpty(usedTrueValue)) { checkResult.FoundValueFormat.True = usedTrueValue; } if (!string.IsNullOrEmpty(usedFalseValue)) { checkResult.FoundValueFormat.False = usedFalseValue; } return(checkResult); } } if (cancellationToken.IsCancellationRequested) { return(null); } if (guessGuid && StringConversion.CheckGuid(samples)) { checkResult.FoundValueFormat.DataType = DataType.Guid; return(checkResult); } if (cancellationToken.IsCancellationRequested) { return(null); } // in case we have named dates, this is not feasible if (!checkNamedDates) { // Trying some chars, if they are in, assume its a string var valuesWithChars = 0; foreach (var value in samples) { // Not having AM PM or T as it might be part of a date Not having E in there as might be // part of a number u 1.487% o 6.264% n 2.365% i 6.286% h 7.232% s 6.327% This adds to a // 30% chance for each position in the text to determine if a text a regular text, if (value.IndexOfAny(new[] { 'u', 'U', 'o', 'O', 'i', 'I', 'n', 'N', 's', 'S', 'h', 'H' }) <= -1) { continue; } valuesWithChars++; // Only do so if more then half of the samples are string if (valuesWithChars < count / 2 && valuesWithChars < 10) { continue; } checkResult.FoundValueFormat.DataType = DataType.String; return(checkResult); } } if (count < minRequiredSamples && guessDateTime && othersValueFormatDate != null) { var res = StringConversion.CheckDate(samples, othersValueFormatDate.DateFormat, othersValueFormatDate.DateSeparator, othersValueFormatDate.TimeSeparator, CultureInfo.CurrentCulture); if (res.FoundValueFormat != null) { return(res); } } // if we have less than the required samples values do not try and try to get a type if (count < minRequiredSamples || cancellationToken.IsCancellationRequested) { return(null); } var firstValue = samples.First(); if (cancellationToken.IsCancellationRequested) { return(null); } // Guess a date format that could be interpreted as number before testing numbers if (guessDateTime && firstValue.Length == 8) { var res = StringConversion.CheckDate(samples, "yyyyMMdd", string.Empty, ":", CultureInfo.InvariantCulture); if (res.FoundValueFormat != null) { return(res); } checkResult.KeepBestPossibleMatch(res); } if (cancellationToken.IsCancellationRequested) { return(null); } // We need to have at least 10 sample values here its too dangerous to assume it is a date if (guessDateTime && serialDateTime && count > 10 && count > minRequiredSamples) { var res = StringConversion.CheckSerialDate(samples, true); if (res.FoundValueFormat != null) { return(res); } checkResult.KeepBestPossibleMatch(res); } if (cancellationToken.IsCancellationRequested) { return(null); } // assume dates are of the same format across the files we check if the dates // we have would possibly match no matter how many samples we have if (guessDateTime && othersValueFormatDate != null) { var res = StringConversion.CheckDate(samples, othersValueFormatDate.DateFormat, othersValueFormatDate.DateSeparator, othersValueFormatDate.TimeSeparator, CultureInfo.CurrentCulture); if (res.FoundValueFormat != null) { return(res); } } if (cancellationToken.IsCancellationRequested) { return(null); } if (guessNumeric) { var res = GuessNumeric(samples, guessPercentage, false, cancellationToken); if (res.FoundValueFormat != null) { return(res); } checkResult.KeepBestPossibleMatch(res); } if (cancellationToken.IsCancellationRequested) { return(null); } // Minimum length of a date is 4 characters if (guessDateTime && firstValue.Length > 3) { var res = GuessDateTime(samples, checkNamedDates, cancellationToken); if (res.FoundValueFormat != null) { return(res); } checkResult.KeepBestPossibleMatch(res); } if (cancellationToken.IsCancellationRequested) { return(null); } // if we have dates and allow serial dates, but do not guess numeric (this would be a fit) try // if the dates are all serial if (!guessDateTime || !serialDateTime || guessNumeric) { return(checkResult); } { var res = StringConversion.CheckSerialDate(samples, false); if (res.FoundValueFormat != null) { return(res); } checkResult.KeepBestPossibleMatch(res); } return(checkResult); }
public static CheckResult GuessNumeric(IList <string> samples, bool guessPercentage, bool allowStartingZero, CancellationToken cancellationToken) { var checkResult = new CheckResult(); var possibleGrouping = new List <char>(); // Determine which decimalGrouping could be used foreach (var caracter in StringConversion.DecimalGroupings) { if (caracter == '\0') { continue; } foreach (var smp in samples) { if (smp.IndexOf(caracter) <= -1) { continue; } possibleGrouping.Add(caracter); break; } } possibleGrouping.Add('\0'); var possibleDecimal = new List <char>(); foreach (var caracter in StringConversion.DecimalSeparators) { if (caracter == '\0') { continue; } foreach (var smp in samples) { if (smp.IndexOf(caracter) <= -1) { continue; } possibleDecimal.Add(caracter); break; } } // Need to have at least one decimal separator if (possibleDecimal.Count == 0) { possibleDecimal.Add('.'); } foreach (var thousandSeparator in possibleGrouping) { // Try Numbers: Int and Decimal foreach (var decimalSeparator in possibleDecimal) { if (cancellationToken.IsCancellationRequested) { return(null); } if (decimalSeparator.Equals(thousandSeparator)) { continue; } var res = StringConversion.CheckNumber(samples, decimalSeparator, thousandSeparator, guessPercentage, allowStartingZero); if (res.FoundValueFormat != null) { return(res); } checkResult.KeepBestPossibleMatch(res); } } return(checkResult); }
/// <summary> /// Writes the object definition. /// </summary> private static void WriteDefinition(Type type, JsonTextWriter jtw) { var csa = type.GetCustomAttribute <ClassSchemaAttribute>(); if (csa == null) { throw new InvalidOperationException($"Type {type.Name} does not have required ClassSchemaAttribute defined."); } jtw.WritePropertyName(csa.Name); jtw.WriteStartObject(); jtw.WritePropertyName("type"); jtw.WriteValue("object"); jtw.WritePropertyName("title"); jtw.WriteValue(CleanString(csa.Title) ?? StringConversion.ToSentenceCase(csa.Name) !); if (csa.Description != null) { jtw.WritePropertyName("description"); jtw.WriteValue(CleanString(csa.Description)); } jtw.WritePropertyName("properties"); jtw.WriteStartObject(); var rqd = new List <string>(); foreach (var pi in type.GetProperties()) { var jpa = pi.GetCustomAttribute <JsonPropertyAttribute>(); if (jpa == null) { continue; } var name = jpa.PropertyName ?? StringConversion.ToCamelCase(pi.Name) !; jtw.WritePropertyName(name); jtw.WriteStartObject(); var psa = pi.GetCustomAttribute <PropertySchemaAttribute>(); if (psa != null) { jtw.WritePropertyName("type"); jtw.WriteValue(GetJsonType(pi)); jtw.WritePropertyName("title"); jtw.WriteValue(CleanString(psa.Title) ?? StringConversion.ToSentenceCase(name) !); if (psa.Description != null) { jtw.WritePropertyName("description"); jtw.WriteValue(CleanString(psa.Description)); } if (psa.IsMandatory) { rqd.Add(name); } if (psa.Options != null) { jtw.WritePropertyName("enum"); jtw.WriteStartArray(); foreach (var opt in psa.Options) { jtw.WriteValue(opt); } jtw.WriteEndArray(); } } else { var pcsa = pi.GetCustomAttribute <PropertyCollectionSchemaAttribute>(); if (pcsa == null) { throw new InvalidOperationException($"Type '{type.Name}' Property '{pi.Name}' does not have a required PropertySchemaAttribute or PropertyCollectionSchemaAttribute."); } jtw.WritePropertyName("type"); jtw.WriteValue("array"); jtw.WritePropertyName("title"); jtw.WriteValue(CleanString(pcsa.Title) ?? StringConversion.ToSentenceCase(name) !); if (pcsa.Description != null) { jtw.WritePropertyName("description"); jtw.WriteValue(CleanString(pcsa.Description)); } jtw.WritePropertyName("items"); if (pi.PropertyType == typeof(List <string>)) { jtw.WriteStartObject(); jtw.WritePropertyName("type"); jtw.WriteValue("string"); jtw.WriteEndObject(); } else { var t = ComplexTypeReflector.GetItemType(pi.PropertyType); jtw.WriteStartObject(); jtw.WritePropertyName("$ref"); jtw.WriteValue($"#/definitions/{t.GetCustomAttribute<ClassSchemaAttribute>()!.Name}"); jtw.WriteEndObject(); } } jtw.WriteEndObject(); } jtw.WriteEndObject(); if (rqd.Count > 0) { jtw.WritePropertyName("required"); jtw.WriteStartArray(); foreach (var name in rqd) { jtw.WriteValue(name); } jtw.WriteEndArray(); } jtw.WriteEndObject(); }
/// <summary> /// <inheritdoc/> /// </summary> protected override void Prepare() { CheckKeyHasValue(Name); CheckOptionsProperties(); Schema = DefaultWhereNull(Schema, () => "dbo"); DbTable = Root !.DbTables !.Where(x => x.Name == Name && x.Schema == Schema).SingleOrDefault(); if (DbTable == null) { throw new CodeGenException(this, nameof(Name), $"Specified Schema.Table '{Schema}.{Name}' not found in database."); } Alias = DefaultWhereNull(Alias, () => new string(StringConversion.ToSentenceCase(Name) !.Split(' ').Select(x => x.Substring(0, 1).ToLower(System.Globalization.CultureInfo.InvariantCulture).ToCharArray()[0]).ToArray())); ViewName = DefaultWhereNull(ViewName, () => "vw" + Name); ViewSchema = DefaultWhereNull(ViewSchema, () => Schema); if (!string.IsNullOrEmpty(Permission) && Permission.Split(".", StringSplitOptions.RemoveEmptyEntries).Length == 1) { Permission += ".Read"; } ColumnNameIsDeleted = DefaultWhereNull(ColumnNameIsDeleted, () => Root !.ColumnNameIsDeleted); ColumnNameTenantId = DefaultWhereNull(ColumnNameTenantId, () => Root !.ColumnNameTenantId); ColumnNameOrgUnitId = DefaultWhereNull(ColumnNameOrgUnitId, () => Root !.ColumnNameOrgUnitId); ColumnNameRowVersion = DefaultWhereNull(ColumnNameRowVersion, () => Root !.ColumnNameRowVersion); ColumnNameCreatedBy = DefaultWhereNull(ColumnNameCreatedBy, () => Root !.ColumnNameCreatedBy); ColumnNameCreatedDate = DefaultWhereNull(ColumnNameCreatedDate, () => Root !.ColumnNameCreatedDate); ColumnNameUpdatedBy = DefaultWhereNull(ColumnNameUpdatedBy, () => Root !.ColumnNameUpdatedBy); ColumnNameUpdatedDate = DefaultWhereNull(ColumnNameUpdatedDate, () => Root !.ColumnNameUpdatedDate); ColumnNameDeletedBy = DefaultWhereNull(ColumnNameDeletedBy, () => Root !.ColumnNameDeletedBy); ColumnNameDeletedDate = DefaultWhereNull(ColumnNameDeletedDate, () => Root !.ColumnNameDeletedDate); PrepareJoins(); if (Order != null && Order.Count > 0) { foreach (var order in Order) { order.Prepare(Root !, this); } } foreach (var c in DbTable.Columns) { if (c.IsPrimaryKey) { var cc = new QueryColumnConfig { Name = c.Name, DbColumn = c }; cc.Prepare(Root !, this); PrimaryKeyColumns.Add(cc); } if ((ExcludeColumns == null || !ExcludeColumns.Contains(c.Name !)) && (IncludeColumns == null || IncludeColumns.Contains(c.Name !))) { var cc = new QueryColumnConfig { Name = c.Name, DbColumn = c }; var ca = AliasColumns?.Where(x => x.StartsWith(c.Name + "^", StringComparison.Ordinal)).FirstOrDefault(); if (ca != null) { var parts = ca.Split("^", StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 2) { cc.NameAlias = parts[1]; } } cc.Prepare(Root !, this); Columns.Add(cc); } } if (Where == null) { Where = new List <QueryWhereConfig>(); } if (ColumnTenantId != null) { Where.Add(new QueryWhereConfig { Statement = $"[{Alias}].[{ColumnTenantId.Name}] = dbo.fnGetTenantId(NULL)" }); } if (ColumnIsDeleted != null) { Where.Add(new QueryWhereConfig { Statement = $"([{Alias}].[{ColumnIsDeleted.Name}] IS NULL OR [{Alias}].[{ColumnIsDeleted.Name}] = 0)" }); } if (!string.IsNullOrEmpty(Permission)) { Where.Add(new QueryWhereConfig { Statement = $"{Root!.GetUserPermissionSql}(NULL, NULL, '{Permission.ToUpperInvariant()}', NULL) = 1" });
/// <summary> /// Writes the schema for the object. /// </summary> private static void WriteObject(ConfigType ct, Type type, XNamespace ns, XElement xe, bool isRoot) { var csa = type.GetCustomAttribute <ClassSchemaAttribute>(); if (csa == null) { throw new InvalidOperationException($"Type '{type.Name}' does not have a required ClassSchemaAttribute."); } if (!Enum.TryParse <ConfigurationEntity>(csa.Name, out var ce)) { ce = ConfigurationEntity.CodeGen; } var xml = new XElement(ns + "element"); xml.Add(new XAttribute("name", csa.Name)); if (!isRoot) { xml.Add(new XAttribute("minOccurs", "0")); xml.Add(new XAttribute("maxOccurs", "unbounded")); } xml.Add(new XElement(ns + "annotation", new XElement(ns + "documentation", csa.Title))); var xct = new XElement(ns + "complexType"); // Add sub-collections within xs:choice element. var hasSeq = false; var xs = new XElement(ns + "choice"); xs.Add(new XAttribute("maxOccurs", "unbounded")); foreach (var pi in type.GetProperties()) { var pcsa = pi.GetCustomAttribute <PropertyCollectionSchemaAttribute>(); if (pcsa == null) { continue; } // Properties with List<string> are not compatible with XML and should be picked up as comma separated strings. if (pi.PropertyType == typeof(List <string>)) { continue; } WriteObject(ct, ComplexTypeReflector.GetItemType(pi.PropertyType), ns, xs, false); hasSeq = true; } if (hasSeq) { xct.Add(xs); } // Add properties as xs:attribute's. foreach (var pi in type.GetProperties()) { var jpa = pi.GetCustomAttribute <JsonPropertyAttribute>(); if (jpa == null) { continue; } var name = jpa.PropertyName ?? StringConversion.ToCamelCase(pi.Name) !; var xmlName = XmlYamlTranslate.GetXmlName(ct, ce, name); var xmlOverride = XmlYamlTranslate.GetXmlPropertySchemaAttribute(ct, ce, xmlName); var psa = xmlOverride.Attribute ?? pi.GetCustomAttribute <PropertySchemaAttribute>(); if (psa == null) { // Properties with List<string> are not compatible with XML and should be picked up as comma separated strings. if (pi.PropertyType == typeof(List <string>)) { var pcsa = pi.GetCustomAttribute <PropertyCollectionSchemaAttribute>(); if (pcsa == null) { continue; } var xpx = new XElement(ns + "attribute", new XAttribute("name", xmlName), new XAttribute("use", pcsa.IsMandatory ? "required" : "optional")); xpx.Add(new XElement(ns + "annotation", new XElement(ns + "documentation", GetDocumentation(name, pcsa)))); xct.Add(xpx); } continue; } var xp = new XElement(ns + "attribute", new XAttribute("name", xmlName), new XAttribute("use", psa.IsMandatory ? "required" : "optional")); xp.Add(new XElement(ns + "annotation", new XElement(ns + "documentation", GetDocumentation(name, psa)))); if (psa.Options == null) { xp.Add(new XAttribute("type", GetXmlType(pi, xmlOverride.Type))); } else { var xr = new XElement(ns + "restriction", new XAttribute("base", GetXmlType(pi, xmlOverride.Type))); foreach (var opt in psa.Options) { xr.Add(new XElement(ns + "enumeration", new XAttribute("value", opt))); } xp.Add(new XElement(ns + "simpleType", xr)); } xct.Add(xp); } // Add this type into the overall document. xml.Add(xct); xe.Add(xml); }
public void ConvertsDateTimeToDoubleUsedByExcel() { Assert.Equal(42826, StringConversion.ToDouble(DateTime.Parse("2017-04-01"))); Assert.Equal(new decimal(42826.8807986111), new decimal(StringConversion.ToDouble(DateTime.Parse("2017-04-01 21:08:21")))); }