public static bool HasUserPermission(User user, int? CountryID, PermissionLevel requiredLevel, UserPermissionsContainer userPermissions = null) { if (user != null) { if (!String.IsNullOrEmpty(user.Permissions)) { if (userPermissions == null) { userPermissions = JsonConvert.DeserializeObject<UserPermissionsContainer>(user.Permissions); } if (userPermissions.Permissions != null) { if (userPermissions.Permissions.Any(p => p.Level == PermissionLevel.Admin && (p.CountryID == null || p.CountryID == CountryID))) { //user is admin (for given country or all countries) return true; } if (userPermissions.Permissions.Any(p => p.Level == requiredLevel && (p.CountryID == null || p.CountryID == CountryID))) { //user has required level of access (for given country or all countries) return true; } } } } return false; }
public static void Log(User user, AuditEventType eventType, string eventDescription, string comment) { try { OCM.Core.Data.OCMEntities dataModel = new OCM.Core.Data.OCMEntities(); var auditEntry = new Core.Data.AuditLog(); if (user == null) { auditEntry.User = dataModel.Users.First(u => u.ID == (int)StandardUsers.System); } else { auditEntry.UserID = user.ID; } auditEntry.EventDescription = "[" + eventType.ToString() + "]:" + (eventDescription != null ? eventDescription : ""); auditEntry.Comment = comment; auditEntry.EventDate = DateTime.UtcNow; dataModel.AuditLogs.Add(auditEntry); dataModel.SaveChanges(); System.Diagnostics.Debug.WriteLine("Log:"+auditEntry.EventDescription); } catch (Exception) { //TODO: fallback to alternative logging } }
public static bool IsUserAdministrator(User user) { if (HasUserPermission(user, null, PermissionLevel.Admin)) { return true; } //fallback legacy check return HasUserPermission(user, StandardPermissionAttributes.Administrator, "true"); }
public static bool HasUserPermission(User user, StandardPermissionAttributes permissionAttribute, string attributeValue) { if (user != null && attributeValue != null) { if (user.Permissions != null) { if (user.Permissions.Contains("[" + permissionAttribute.ToString() + "=" + attributeValue + "]")) { return true; } } } return false; }
public ActionResult EditUser(OCM.API.Common.Model.User userDetails) { if (ModelState.IsValid) { var userManager = new UserManager(); //save if (userManager.UpdateUserProfile(userDetails, true)) { return(RedirectToAction("Users")); } } return(View(userDetails)); }
/// <summary> /// For a list of ChargePoint objects, attempt to populate the AddressInfo (at least country) based on lat/lon if not already populated /// </summary> /// <param name="itemList"></param> /// <param name="coreRefData"></param> public void UpdateImportedPOIList(ImportReport poiResults, User user) { var submissionManager = new SubmissionManager(); int itemCount = 1; foreach (var newPOI in poiResults.Added) { Log("Importing New POI " + itemCount + ": " + newPOI.AddressInfo.ToString()); submissionManager.PerformPOISubmission(newPOI, user, false); } foreach (var updatedPOI in poiResults.Updated) { Log("Importing Updated POI " + itemCount + ": " + updatedPOI.AddressInfo.ToString()); submissionManager.PerformPOISubmission(updatedPOI, user, performCacheRefresh: false, disablePOISuperseding: true); } foreach (var delisted in poiResults.Delisted) { Log("Delisting Removed POI " + itemCount + ": " + delisted.AddressInfo.ToString()); delisted.SubmissionStatus = null; delisted.SubmissionStatusTypeID = (int)StandardSubmissionStatusTypes.Delisted_RemovedByDataProvider; submissionManager.PerformPOISubmission(delisted, user, false); } //refresh POI cache var cacheTask = Task.Run(async () => { return await OCM.Core.Data.CacheManager.RefreshCachedData(); }); cacheTask.Wait(); //temp get all providers references for recognised duplicates /*var dupeRefs = from dupes in poiResults.Duplicates where !String.IsNullOrEmpty(dupes.DataProvidersReference) select dupes.DataProvidersReference; string dupeOutput = ""; foreach(var d in dupeRefs) { dupeOutput += ",'"+d+"'"; } System.Diagnostics.Debug.WriteLine(dupeOutput);*/ if (poiResults.ProviderDetails.DefaultDataProvider != null) { //update date last updated for this provider new DataProviderManager().UpdateDateLastImport(poiResults.ProviderDetails.DefaultDataProvider.ID); } }
/// <summary> /// Consumers should prepare a new/updated ChargePoint with as much info populated as possible /// </summary> /// <param name="submission">ChargePoint info for submission, if ID and UUID set will be treated as an update</param> /// <returns>false on error or not enough data supplied</returns> public async Task <ValidationResult> PerformPOISubmission(Model.ChargePoint updatedPOI, Model.User user, bool performCacheRefresh = true, bool disablePOISuperseding = false) { try { var poiManager = new POIManager(); bool enableEditQueueLogging = bool.Parse(ConfigurationManager.AppSettings["EnableEditQueue"]); bool isUpdate = false; bool userCanEditWithoutApproval = false; bool isSystemUser = false; int? supersedesID = null;//POI from another data provider which has been superseded by an edit //if user signed in, check if they have required permission to perform an edit/approve (if required) if (user != null) { if (user.ID == (int)StandardUsers.System) { isSystemUser = true; } //if user is system user, edits/updates are not recorded in edit queue if (isSystemUser) { enableEditQueueLogging = false; } userCanEditWithoutApproval = POIManager.CanUserEditPOI(updatedPOI, user); } var dataModel = new Core.Data.OCMEntities(); //if poi is an update, validate if update can be performed if (updatedPOI.ID > 0 && !String.IsNullOrEmpty(updatedPOI.UUID)) { if (dataModel.ChargePoints.Any(c => c.Id == updatedPOI.ID && c.Uuid == updatedPOI.UUID)) { //update is valid poi, check if user has permission to perform an update isUpdate = true; if (userCanEditWithoutApproval) { AllowUpdates = true; } if (!AllowUpdates && !enableEditQueueLogging) { //valid update requested but updates not allowed return(new ValidationResult { IsValid = false, Message = "Updates are disabled" }); } } else { //update does not correctly identify an existing poi return(new ValidationResult { IsValid = false, Message = "Update does not correctly match an existing POI" }); } } //validate if minimal required data is present if (updatedPOI.AddressInfo.Title == null || (updatedPOI.AddressInfo.Country == null && updatedPOI.AddressInfo.CountryID == null)) { return(new ValidationResult { IsValid = false, Message = "Update failed basic validation" }); } //convert to DB version of POI and back so that properties are fully populated using (var refDataManager = new ReferenceDataManager()) { var refData = await refDataManager.GetCoreReferenceDataAsync(); updatedPOI = PopulateFullPOI(updatedPOI, refData); } Model.ChargePoint oldPOI = null; if (updatedPOI.ID > 0) { //get json snapshot of current cp data to store as 'previous' oldPOI = await poiManager.Get(updatedPOI.ID); } //if user cannot edit directly, add to edit queue for approval var editQueueItem = new Core.Data.EditQueueItem { DateSubmitted = DateTime.UtcNow }; if (enableEditQueueLogging) { editQueueItem.EntityId = updatedPOI.ID; editQueueItem.EntityType = dataModel.EntityTypes.FirstOrDefault(t => t.Id == 1); //charging point location entity type id //serialize cp as json //null extra data we don't want to serialize/compare updatedPOI.UserComments = null; updatedPOI.MediaItems = null; string editData = PerformSerialisationToString(updatedPOI, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); editQueueItem.EditData = editData; if (updatedPOI.ID > 0) { //check if poi will change with this edit, if not we discard it completely if (!poiManager.HasDifferences(oldPOI, updatedPOI)) { System.Diagnostics.Debug.WriteLine("POI Update has no changes, discarding change."); return(new ValidationResult { IsValid = true, ItemId = updatedPOI.ID, Message = "No POI changes detected" }); } else { editQueueItem.PreviousData = PerformSerialisationToString(oldPOI, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); } } if (user != null) { editQueueItem.User = dataModel.Users.FirstOrDefault(u => u.Id == user.ID); } var processedByUser = editQueueItem.User ?? dataModel.Users.FirstOrDefault(u => u.Id == (int)StandardUsers.System); editQueueItem.IsProcessed = false; dataModel.EditQueueItems.Add(editQueueItem); //TODO: send notification of new item for approval //save edit queue item dataModel.SaveChanges(); //if previous edit queue item exists by same user for same POI, mark as processed var previousEdits = dataModel.EditQueueItems.Where(e => e.UserId == editQueueItem.UserId && e.EntityId == editQueueItem.EntityId && e.EntityTypeId == editQueueItem.EntityTypeId && e.Id != editQueueItem.Id && e.IsProcessed != true); foreach (var previousEdit in previousEdits) { previousEdit.IsProcessed = true; previousEdit.ProcessedByUser = processedByUser; previousEdit.DateProcessed = DateTime.UtcNow; } //save updated edit queue items dataModel.SaveChanges(); } //prepare and save changes POI changes/addition if (isUpdate && !AllowUpdates) { //user has submitted an edit but is not an approved editor //SendEditSubmissionNotification(updatedPOI, user); //user is not an editor, item is now pending in edit queue for approval. return(new ValidationResult { IsValid = true, ItemId = updatedPOI.ID, Message = "Update submitted for review" }); } if (isUpdate && updatedPOI.SubmissionStatusTypeID >= 1000) { //update is a delisting, skip superseding poi System.Diagnostics.Debug.WriteLine("skipping superseding of imported POI due to delisting"); } else { //if poi being updated exists from an imported source we supersede the old POI with the new version, unless we're doing a fresh import from same data provider if (!disablePOISuperseding) { //if update by non-system user will change an imported/externally provided data, supersede old POI with new one (retain ID against new POI) if (isUpdate && !isSystemUser && oldPOI.DataProviderID != (int)StandardDataProviders.OpenChargeMapContrib) { //move old poi to new id, set status of new item to superseded supersedesID = poiManager.SupersedePOI(dataModel, oldPOI, updatedPOI); } } } //user is an editor, go ahead and store the addition/update //set/update cp properties var cpData = poiManager.PopulateChargePoint_SimpleToData(updatedPOI, dataModel); //if item has no submission status and user permitted to edit, set to published if (userCanEditWithoutApproval && cpData.SubmissionStatusTypeId == null) { cpData.SubmissionStatusTypeId = (int)StandardSubmissionStatusTypes.Submitted_Published; //hack due to conflicting state change for SubmissionStatusType } else { //no submission status, set to 'under review' if (cpData.SubmissionStatusTypeId == null) { cpData.SubmissionStatusTypeId = (int)StandardSubmissionStatusTypes.Submitted_UnderReview; } } cpData.DateLastStatusUpdate = DateTime.UtcNow; if (!isUpdate) { //new data objects need added to data model before save if (cpData.AddressInfo != null) { dataModel.AddressInfos.Add(cpData.AddressInfo); } dataModel.ChargePoints.Add(cpData); } //finally - save poi update dataModel.SaveChanges(); //get id of update/new poi int newPoiID = cpData.Id; //this is an authorised update, reflect change in edit queue item if (enableEditQueueLogging && user != null && user.ID > 0) { var editUser = dataModel.Users.FirstOrDefault(u => u.Id == user.ID); editQueueItem.User = editUser; if (newPoiID > 0) { editQueueItem.EntityId = newPoiID; } //if user is authorised to edit, process item automatically without review if (userCanEditWithoutApproval) { editQueueItem.ProcessedByUser = editUser; editQueueItem.DateProcessed = DateTime.UtcNow; editQueueItem.IsProcessed = true; } //save edit queue item changes dataModel.SaveChanges(); } else { //anonymous submission, update edit queue item if (enableEditQueueLogging && user == null) { if (newPoiID > 0) { editQueueItem.EntityId = newPoiID; } dataModel.SaveChanges(); } } System.Diagnostics.Debug.WriteLine("Added/Updated CP:" + cpData.Id); //if user is not anonymous, log their submission and update their reputation points if (user != null) { AuditLogManager.Log(user, isUpdate ? AuditEventType.UpdatedItem : AuditEventType.CreatedItem, "Modified OCM-" + cpData.Id, null); //add reputation points new UserManager().AddReputationPoints(user, 1); } //preserve new POI Id for caller updatedPOI.ID = cpData.Id; if (performCacheRefresh) { if (supersedesID != null) { await CacheManager.RefreshCachedPOI((int)supersedesID); } await CacheManager.RefreshCachedPOI(updatedPOI.ID); } return(new ValidationResult { IsValid = true, ItemId = updatedPOI.ID, Message = "Update submitted." }); } catch (Exception exp) { System.Diagnostics.Debug.WriteLine(exp.ToString()); AuditLogManager.ReportWebException(true, null, AuditEventType.SystemErrorWeb, "POI Submission Failed", exp); //error performing submission return(new ValidationResult { IsValid = false, Message = "Submission Failed with an Exception: " + exp.Message }); } }
public int PerformSubmission(Common.Model.MediaItem mediaItem, Model.User user) { return(-1); }
private static void SendPOICommentSubmissionNotifications(Common.Model.UserComment comment, Model.User user, Core.Data.UserComment dataComment) { try { //prepare notification NotificationManager notification = new NotificationManager(); Hashtable msgParams = new Hashtable(); msgParams.Add("Description", ""); msgParams.Add("ChargePointID", comment.ChargePointID); msgParams.Add("ItemURL", "https://openchargemap.org/site/poi/details/" + comment.ChargePointID); msgParams.Add("UserName", user != null ? user.Username : comment.UserName); msgParams.Add("MessageBody", "Comment (" + dataComment.UserCommentType.Title + ") added to OCM-" + comment.ChargePointID + ": " + dataComment.Comment); //if fault report, attempt to notify operator if (dataComment.UserCommentType.Id == (int)StandardCommentTypes.FaultReport) { //decide if we can send a fault notification to the operator notification.PrepareNotification(NotificationType.FaultReport, msgParams); //notify default system recipients bool operatorNotified = false; if (dataComment.ChargePoint.Operator != null) { if (!String.IsNullOrEmpty(dataComment.ChargePoint.Operator.FaultReportEmail)) { try { notification.SendNotification(dataComment.ChargePoint.Operator.FaultReportEmail, ConfigurationManager.AppSettings["DefaultRecipientEmailAddresses"].ToString()); operatorNotified = true; } catch (Exception) { System.Diagnostics.Debug.WriteLine("Fault report: failed to notify operator"); } } } if (!operatorNotified) { notification.Subject += " (OCM: Could not notify Operator)"; notification.SendNotification(NotificationType.LocationCommentReceived); } } else { //normal comment, notification to OCM only notification.PrepareNotification(NotificationType.LocationCommentReceived, msgParams); //notify default system recipients notification.SendNotification(NotificationType.LocationCommentReceived); } } catch (Exception) { ;; // failed to send notification } }
/// <summary> /// Submit a new comment against a given charge equipment id /// </summary> /// <param name="comment"></param> /// <returns>ID of new comment, -1 for invalid cp, -2 for general error saving comment</returns> public async Task <int> PerformSubmission(Common.Model.UserComment comment, Model.User user) { //TODO: move all to UserCommentManager //populate data model comment from simple comment object var dataModel = new Core.Data.OCMEntities(); int cpID = comment.ChargePointID; var dataComment = new Core.Data.UserComment(); var dataChargePoint = dataModel.ChargePoints.FirstOrDefault(c => c.Id == cpID); if (dataChargePoint == null) { return(-1); //invalid charge point specified } dataComment.ChargePointId = dataChargePoint.Id; dataComment.Comment = comment.Comment; int commentTypeID = comment.CommentTypeID ?? 10; //default to General Comment // some clients may post a CommentType object instead of just an ID if (comment.CommentType != null) { commentTypeID = comment.CommentType.ID; } dataComment.UserCommentTypeId = commentTypeID; int?checkinStatusType = comment.CheckinStatusTypeID; dataComment.CheckinStatusTypeId = (byte?)comment.CheckinStatusTypeID; // some clients may post a CheckinStatusType object instead of just an ID if (dataComment.CheckinStatusTypeId == null && comment.CheckinStatusType != null) { dataComment.CheckinStatusTypeId = (byte?)comment.CheckinStatusType.ID; } dataComment.UserName = comment.UserName; dataComment.Rating = comment.Rating; dataComment.RelatedUrl = comment.RelatedURL; dataComment.DateCreated = DateTime.UtcNow; if (user != null && user.ID > 0) { var ocmUser = dataModel.Users.FirstOrDefault(u => u.Id == user.ID); if (ocmUser != null) { dataComment.UserId = ocmUser.Id; dataComment.UserName = ocmUser.Username; } } try { dataChargePoint.DateLastStatusUpdate = DateTime.UtcNow; dataModel.UserComments.Add(dataComment); dataModel.SaveChanges(); if (user != null) { AuditLogManager.Log(user, AuditEventType.CreatedItem, "Added Comment " + dataComment.Id + " to OCM-" + cpID, null); //add reputation points new UserManager().AddReputationPoints(user, 1); } //SendPOICommentSubmissionNotifications(comment, user, dataComment); //TODO: only refresh cache for specific POI await CacheManager.RefreshCachedPOI(dataComment.ChargePoint.Id); return(dataComment.Id); } catch (Exception exp) { return(-2); //error saving } }
public ActionResult Edit(User updateProfile) { if (ModelState.IsValid) { try { if (Session["UserID"] != null) { // TODO: Add update logic here var userManager = new UserManager(); var user = userManager.GetUser((int)Session["UserID"]); bool updatedOK = false; if (user.ID == updateProfile.ID) { updatedOK = userManager.UpdateUserProfile(updateProfile, false); } if (updatedOK) { return RedirectToAction("Index"); } else { TempData["UpdateFailed"] = true; } } return View(); } catch { return View(); } } return View(updateProfile); }
/// <summary> /// Submit a new comment against a given charge equipment id /// </summary> /// <param name="comment"></param> /// <returns>ID of new comment, -1 for invalid cp, -2 for general error saving comment</returns> public int PerformSubmission(Common.Model.UserComment comment, Model.User user) { //TODO: move all to UserCommentManager //populate data model comment from simple comment object var dataModel = new Core.Data.OCMEntities(); int cpID = comment.ChargePointID; var dataComment = new Core.Data.UserComment(); dataComment.ChargePoint = dataModel.ChargePoints.FirstOrDefault(c => c.ID == cpID); if (dataComment.ChargePoint == null) { return(-1); //invalid charge point specified } dataComment.Comment = comment.Comment; int commentTypeID = 10; //default to General Comment if (comment.CommentType != null) { commentTypeID = comment.CommentType.ID; } dataComment.UserCommentType = dataModel.UserCommentTypes.FirstOrDefault(t => t.ID == commentTypeID); if (comment.CheckinStatusType != null) { dataComment.CheckinStatusType = dataModel.CheckinStatusTypes.FirstOrDefault(t => t.ID == comment.CheckinStatusType.ID); } dataComment.UserName = comment.UserName; dataComment.Rating = comment.Rating; dataComment.RelatedURL = comment.RelatedURL; dataComment.DateCreated = DateTime.UtcNow; if (user != null && user.ID > 0) { var ocmUser = dataModel.Users.FirstOrDefault(u => u.ID == user.ID); if (ocmUser != null) { dataComment.User = ocmUser; dataComment.UserName = ocmUser.Username; } } /*if (dataComment.User==null) * { * return -3; //rejected, not authenticated * }*/ try { dataComment.ChargePoint.DateLastStatusUpdate = DateTime.UtcNow; dataModel.UserComments.Add(dataComment); dataModel.SaveChanges(); if (user != null) { AuditLogManager.Log(user, AuditEventType.CreatedItem, "Added Comment " + dataComment.ID + " to OCM-" + cpID, null); //add reputation points new UserManager().AddReputationPoints(user, 1); } //SendPOICommentSubmissionNotifications(comment, user, dataComment); //TODO: only refresh cache for specific POI CacheManager.RefreshCachedPOI(dataComment.ChargePoint.ID); return(dataComment.ID); } catch (Exception) { return(-2); //error saving } }
/// <summary> /// Add reputation points to a user /// </summary> /// <param name="user"></param> /// <param name="amount"></param> public void AddReputationPoints(User user, int amount) { try { if (user != null) { if (user.ID > 0) { var userData = dataModel.Users.First(u => u.ID == user.ID); if (userData != null) { if (userData.ReputationPoints == null) userData.ReputationPoints = 0; userData.ReputationPoints += amount; dataModel.SaveChanges(); } } } } catch (Exception) { //could not add points to given user } }
/// <summary> /// Apply updates to a user profile /// </summary> /// <param name="user"></param> /// <returns></returns> public bool UpdateUserProfile(User updatedProfile, bool allowAdminChanges) { try { if (updatedProfile != null) { if (updatedProfile.ID > 0) { var userData = dataModel.Users.First(u => u.ID == updatedProfile.ID); if (userData != null) { if (userData.IdentityProvider == "OCM" && String.IsNullOrWhiteSpace(updatedProfile.EmailAddress)) { //cannot proceed with update, email required as user name for login return false; } if (userData.EmailAddress != updatedProfile.EmailAddress && !string.IsNullOrWhiteSpace(updatedProfile.EmailAddress)) { //ensure email address is not in use by another account before changing if (dataModel.Users.Any(e => e.ID != userData.ID && e.EmailAddress != null && e.EmailAddress.Trim().ToLower() == updatedProfile.EmailAddress.ToLower().Trim())) { //cannot proceed, user is trying to change email address to match another user return false; } } userData.Location = updatedProfile.Location; userData.Profile = updatedProfile.Profile; userData.Username = updatedProfile.Username; userData.WebsiteURL = updatedProfile.WebsiteURL; userData.IsProfilePublic = (updatedProfile.IsProfilePublic != null ? (bool)updatedProfile.IsProfilePublic : false); userData.IsPublicChargingProvider = (updatedProfile.IsPublicChargingProvider != null ? (bool)updatedProfile.IsPublicChargingProvider : false); userData.IsEmergencyChargingProvider = (updatedProfile.IsEmergencyChargingProvider != null ? (bool)updatedProfile.IsEmergencyChargingProvider : false); userData.EmailAddress = updatedProfile.EmailAddress; userData.Latitude = updatedProfile.Latitude; userData.Longitude = updatedProfile.Longitude; //TODO: SyncedSettings if (allowAdminChanges) { userData.ReputationPoints = updatedProfile.ReputationPoints; userData.Identifier = updatedProfile.Identifier; userData.Permissions = updatedProfile.Permissions; userData.IdentityProvider = updatedProfile.IdentityProvider; } if (userData.IdentityProvider == "OCM" && !String.IsNullOrWhiteSpace(userData.EmailAddress)) userData.Identifier = userData.EmailAddress; dataModel.SaveChanges(); return true; } } } } catch (Exception) { //could not update user return false; } return false; }
public bool GrantPermission(User user, StandardPermissionAttributes permissionAttribute, string attributeValue, bool removeOnly, User administrator) { //to apply permissions we add or remove from the permissions list attached to the user details, we also maintain a string in the legacy semicolon seperated format for apps/code which still requires the older format. var userDetails = dataModel.Users.FirstOrDefault(u => u.ID == user.ID); if (userDetails != null) { UserPermissionsContainer userPermissions = new UserPermissionsContainer(); if (!String.IsNullOrEmpty(user.Permissions)) { userPermissions = JsonConvert.DeserializeObject<UserPermissionsContainer>(user.Permissions); } //apply permission to legacypermission tag of user details string attributeTag = "[" + permissionAttribute.ToString() + "=" + attributeValue + "];"; if (userPermissions.LegacyPermissions == null) userPermissions.LegacyPermissions = ""; if (userPermissions.Permissions == null) userPermissions.Permissions = new List<UserPermission>(); if (!removeOnly) { //add permission //append permission attribute for user //legacy format is [AttributeName1=Value];[AttributeName2=Value]; -legacy format is maintained as LegacyPermissions field in JSON format, for older apps (mainly older versions of OCM app) if (!userPermissions.LegacyPermissions.Contains(attributeTag)) { if (!userPermissions.LegacyPermissions.EndsWith(";") && userPermissions.LegacyPermissions != "") userPermissions.LegacyPermissions += ";"; userPermissions.LegacyPermissions += attributeTag; //add permission to main permission list if (permissionAttribute == StandardPermissionAttributes.CountryLevel_Editor) { var permission = new UserPermission(); if (attributeValue != "All") { permission.CountryID = int.Parse(attributeValue); } permission.Level = PermissionLevel.Editor; userPermissions.Permissions.Add(permission); } //TODO: administrator permissions AuditLogManager.Log(administrator, AuditEventType.PermissionGranted, "User: "******"; Permission:" + permissionAttribute.ToString(), null); } } else { //remove permission userPermissions.LegacyPermissions = userPermissions.LegacyPermissions.Replace(attributeTag, ""); if (permissionAttribute == StandardPermissionAttributes.CountryLevel_Editor) { if (attributeValue != "All") { int countryID = int.Parse(attributeValue); userPermissions.Permissions.RemoveAll(p => p.Level == PermissionLevel.Editor && p.CountryID == countryID); } else { userPermissions.Permissions.RemoveAll(p => p.Level == PermissionLevel.Editor); } } AuditLogManager.Log(administrator, AuditEventType.PermissionRemoved, "User: "******"; Permission:" + permissionAttribute.ToString(), null); } //remove requested permission attribute if it exists if (userDetails.PermissionsRequested != null) { userDetails.PermissionsRequested = userDetails.PermissionsRequested.Replace(attributeTag, ""); } userDetails.Permissions = JsonConvert.SerializeObject(userPermissions, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); dataModel.SaveChanges(); return true; } else { return false; } }