public IActionResult Login([FromBody]JObject submitObj) { string email = (string)submitObj["email"]; string password = (string)submitObj["password"]; bool rememberMe = (bool)submitObj["rememberMe"]; SecurityManager secMan = new SecurityManager(service); var user = secMan.GetUser(email, password); var responseObj = new ResponseModel(); if (user != null) { if (user.Enabled == false) { responseObj.Success = false; responseObj.Message = "Error while user authentication."; var errorMsg = new ErrorModel(); errorMsg.Key = "Email"; errorMsg.Value = email; errorMsg.Message = "User account is disabled."; responseObj.Errors.Add(errorMsg); responseObj.Object = new { token = "" }; } else { responseObj.Object = null; responseObj.Success = true; responseObj.Timestamp = DateTime.UtcNow; responseObj.Object = new { token = WebSecurityUtil.Login(HttpContext, user.Id, user.ModifiedOn, rememberMe, service) }; } } else { responseObj.Success = false; responseObj.Message = "Login failed"; var errorMsg = new ErrorModel(); errorMsg.Key = "Email"; errorMsg.Value = email; errorMsg.Message = "Invalid email or password"; responseObj.Errors.Add(errorMsg); responseObj.Object = new { token = "" }; } return DoResponse(responseObj); }
public IActionResult MyMilestones() { var response = new ResponseModel(); var resultProjectIdList = new List<Guid>(); try { #region << Get Project Ids >> #region << Can user read projects >> //Get current user ErpUser user = SecurityContext.CurrentUser; //Get entity meta var entity = entMan.ReadEntity("wv_project").Object; //check if user role has permissions var canRead = user.Roles.Any(x => entity.RecordPermissions.CanRead.Any(z => z == x.Id)); var canCreate = user.Roles.Any(x => entity.RecordPermissions.CanCreate.Any(z => z == x.Id)); var canUpdate = user.Roles.Any(x => entity.RecordPermissions.CanUpdate.Any(z => z == x.Id)); var canDelete = user.Roles.Any(x => entity.RecordPermissions.CanDelete.Any(z => z == x.Id)); if (!canRead) { response.Success = false; response.Message = "You do not have permission to read the projects in this system"; response.Timestamp = DateTime.UtcNow; return Json(response); //return empty object } var milestone = entMan.ReadEntity("wv_milestone").Object; //check if user role has permissions var canReadMilestone = user.Roles.Any(x => milestone.RecordPermissions.CanRead.Any(z => z == x.Id)); var canCreateMilestone = user.Roles.Any(x => milestone.RecordPermissions.CanCreate.Any(z => z == x.Id)); var canUpdateMilestone = user.Roles.Any(x => milestone.RecordPermissions.CanUpdate.Any(z => z == x.Id)); var canDeleteMilestone = user.Roles.Any(x => milestone.RecordPermissions.CanDelete.Any(z => z == x.Id)); if (!canReadMilestone) { response.Success = false; response.Message = "You do not have permission to read the milestones in this system"; response.Timestamp = DateTime.UtcNow; return Json(response); //return empty object } #endregion var requestedFields = "id," + "$user_1_n_project_owner.id," + "$role_n_n_project_team.id,$role_n_n_project_customer.id"; #region << Query builder >> //QueryObject filterObj = EntityQuery.QueryEQ("id", recordId); QueryObject filterObj = null; EntityQuery resultQuery = new EntityQuery("wv_project", requestedFields, filterObj, null, null, null, null); #endregion #region << Execute >> QueryResponse result = recMan.Find(resultQuery); if (!result.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = result.Message; response.Object = null; return Json(response); } foreach (var record in result.Object.Data) { //Check if user can view the object var userIsPM = false; var userIsStaff = false; var userIsCustomer = false; #region << Check user roles >> foreach (var userRole in user.Roles) { if (!userIsPM) { userIsPM = ((List<EntityRecord>)record["$user_1_n_project_owner"]).Any(z => (Guid)z["id"] == user.Id); } if (!userIsStaff) { userIsStaff = ((List<EntityRecord>)record["$role_n_n_project_team"]).Any(z => (Guid)z["id"] == userRole.Id); } if (!userIsCustomer) { userIsCustomer = ((List<EntityRecord>)record["$role_n_n_project_customer"]).Any(z => (Guid)z["id"] == userRole.Id); } } #endregion if (userIsPM || userIsStaff || userIsCustomer) { resultProjectIdList.Add((Guid)record["id"]); } } #endregion #endregion if (resultProjectIdList.Count == 0) { response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "You do not have access to any project or there are no projects yet"; response.Object = null; return Json(response); } #region << Get Milestones >> var milestoneFields = "*"; QueryObject projectIdFilterSection = null; #region << project id filters >> var projectIdRulesList = new List<QueryObject>(); foreach (var projectId in resultProjectIdList) { var projectIdRule = EntityQuery.QueryEQ("project_id", projectId); projectIdRulesList.Add(projectIdRule); } projectIdFilterSection = EntityQuery.QueryOR(projectIdRulesList.ToArray()); #endregion var sortRulesList = new List<QuerySortObject>(); var defaultSortRule = new QuerySortObject("name", QuerySortType.Ascending); sortRulesList.Add(defaultSortRule); var milestoneQuery = new EntityQuery("wv_milestone", milestoneFields, projectIdFilterSection, sortRulesList.ToArray(), null, null, null); var milestoneQueryResponse = recMan.Find(milestoneQuery); if (!milestoneQueryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = milestoneQueryResponse.Message; response.Object = null; return Json(response); } response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "My milestones successfully read"; response.Object = milestoneQueryResponse.Object.Data; return Json(response); #endregion } catch (Exception ex) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + ex.Message; response.Object = null; return Json(response); } }
public IActionResult LastUpdatedTasksUserOwns(int page = 1) { var response = new ResponseModel(); try { //var queryString = HttpContext.Request.QueryString; #region << Can user read activities >> //Get current user ErpUser user = SecurityContext.CurrentUser; //Get entity meta var entity = entMan.ReadEntity("wv_task").Object; //check if user role has permissions var canRead = user.Roles.Any(x => entity.RecordPermissions.CanRead.Any(z => z == x.Id)); var canCreate = user.Roles.Any(x => entity.RecordPermissions.CanCreate.Any(z => z == x.Id)); var canUpdate = user.Roles.Any(x => entity.RecordPermissions.CanUpdate.Any(z => z == x.Id)); var canDelete = user.Roles.Any(x => entity.RecordPermissions.CanDelete.Any(z => z == x.Id)); if (!canRead) { response.Success = false; response.Message = "You do not have permission to read the tasks in this system"; response.Timestamp = DateTime.UtcNow; return Json(response); //return empty object } #endregion var taskQueryResponse = new QueryResponse(); #region << Get tasks >> { var fields = "id,number,subject,priority,last_modified_on,$user_wv_task_modified_by.username"; //Add default sort by created_on var sortRulesList = new List<QuerySortObject>(); var defaultSortRule = new QuerySortObject("last_modified_on", QuerySortType.Descending); sortRulesList.Add(defaultSortRule); #endregion var ownerFilter = EntityQuery.QueryEQ("owner_id", SecurityContext.CurrentUser.Id); var notClosedFilter = EntityQuery.QueryNOT("status", "completed"); var rootFilterSection = EntityQuery.QueryAND(ownerFilter, notClosedFilter); //Calculate page var pageSize = 5; var skipRecords = (page - 1) * pageSize; var activityQuery = new EntityQuery("wv_task", fields, rootFilterSection, sortRulesList.ToArray(), skipRecords, pageSize, null); taskQueryResponse = recMan.Find(activityQuery); if (!taskQueryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = taskQueryResponse.Message; response.Object = null; return Json(response); } } response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "Successful read"; response.Object = taskQueryResponse.Object.Data; return Json(response); } catch (Exception ex) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = ex.Message; response.Object = null; return Json(response); } }
public IActionResult GetSprintTasksList(Guid sprintId, string status = "not started", string scope = "user", int page = 1, int pageSize = 1) { var response = new ResponseModel(); var taskList = new List<EntityRecord>(); var processedTaskList = new List<EntityRecord>(); var userDictionary = new Dictionary<Guid, EntityRecord>(); var skipPages = (page - 1) * pageSize; try { #region << Get all users >> { var query = new EntityQuery("user"); var queryResponse = recMan.Find(query); if (!queryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + queryResponse.Message; response.Object = null; return Json(response); } foreach (var user in queryResponse.Object.Data) { userDictionary[(Guid)user["id"]] = user; } } #endregion #region << Get tasks >> { QueryObject queryFilter = null; var queryRulesList = new List<QueryObject>(); //Only not completed tasks queryRulesList.Add(EntityQuery.QueryNOT("status", "completed")); if (scope == "user") { queryRulesList.Add(EntityQuery.QueryEQ("owner_id", SecurityContext.CurrentUser.Id)); } queryRulesList.Add(EntityQuery.QueryEQ("status", status)); queryFilter = EntityQuery.QueryAND(queryRulesList.ToArray()); var sortRulesList = new List<QuerySortObject>(); var sortRule = new QuerySortObject("created_on", QuerySortType.Descending); sortRulesList.Add(sortRule); var queryFields = "id,code,owner_id, priority,status,subject," + "x_billable_hours,x_nonbillable_hours,estimation"; var query = new EntityQuery("wv_task", queryFields, queryFilter, sortRulesList.ToArray(), skipPages, pageSize); var queryResponse = recMan.Find(query); if (!queryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + queryResponse.Message; response.Object = null; return Json(response); } if (queryResponse.Object.Data.Any()) { taskList = queryResponse.Object.Data; } else { response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "No tasks found!"; response.Object = new List<EntityRecord>(); return Json(response); } } #endregion #region << process Tasks >> foreach (var task in taskList) { var proccessedTask = new EntityRecord(); proccessedTask["id"] = (Guid)task["id"]; proccessedTask["code"] = (string)task["code"]; proccessedTask["priority"] = (string)task["priority"]; proccessedTask["status"] = (string)task["status"]; proccessedTask["subject"] = (string)task["subject"]; proccessedTask["estimation"] = (decimal)task["estimation"]; proccessedTask["logged"] = (decimal)task["x_nonbillable_hours"] + (decimal)task["x_billable_hours"]; proccessedTask["owner_username"] = (string)userDictionary[(Guid)task["owner_id"]]["username"]; proccessedTask["owner_image"] = (string)userDictionary[(Guid)task["owner_id"]]["image"]; processedTaskList.Add(proccessedTask); } #endregion response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "Tasks successfully read"; response.Object = processedTaskList; return Json(response); } catch (Exception ex) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + ex.Message; response.Object = null; return Json(response); } }
public IActionResult GetSprintList(int page = 1, int pageSize = 1) { var response = new ResponseModel(); var sprintList = new List<EntityRecord>(); var skipPages = (page - 1) * pageSize; try { QueryObject queryFilter = null; var sortRulesList = new List<QuerySortObject>(); var sortRule = new QuerySortObject("start_date", QuerySortType.Descending); sortRulesList.Add(sortRule); var query = new EntityQuery("wv_sprint", "*", queryFilter, sortRulesList.ToArray(), skipPages, pageSize); var queryResponse = recMan.Find(query); if (!queryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + queryResponse.Message; response.Object = null; return Json(response); } if (queryResponse.Object.Data.Any()) { sprintList = queryResponse.Object.Data; } else { response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "No sprints found!"; response.Object = null; return Json(response); } response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "Sprints successfully read"; response.Object = sprintList; return Json(response); } catch (Exception ex) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + ex.Message; response.Object = null; return Json(response); } }
public ResponseModel ImportEntityRecordsFromCsv(string entityName, string fileTempPath) { //The import CSV should have column names matching the names of the imported fields. The first column should be "id" matching the id of the record to be updated. //If the 'id' of a record equals 'null', a new record will be created with the provided columns and default values for the missing ones. ResponseModel response = new ResponseModel(); response.Message = "Records successfully imported"; response.Timestamp = DateTime.UtcNow; response.Success = true; response.Object = null; //string fileTempPath = @"D:\csv\test.csv"; //FileInfo fileInfo = new FileInfo(fileTempPath); //if (!fileInfo.Exists) // throw new Exception("FILE_NOT_EXIST"); //FileStream fileStream = fileInfo.OpenRead(); //TextReader reader = new StreamReader(fileStream); if (string.IsNullOrWhiteSpace(fileTempPath)) { response.Timestamp = DateTime.UtcNow; response.Success = false; response.Message = "Import failed! fileTempPath parameter cannot be empty or null!"; response.Errors.Add(new ErrorModel("fileTempPath", fileTempPath, "Import failed! File does not exist!")); return response; } if (fileTempPath.StartsWith("/fs")) fileTempPath = fileTempPath.Remove(0, 3); if (!fileTempPath.StartsWith("/")) fileTempPath = "/" + fileTempPath; fileTempPath = fileTempPath.ToLowerInvariant(); using (DbConnection connection = DbContext.Current.CreateConnection()) { List<EntityRelation> relations = relMan.Read().Object; EntityListResponse entitiesResponse = entMan.ReadEntities(); List<Entity> entities = entitiesResponse.Object; Entity entity = entities.FirstOrDefault(e => e.Name == entityName); if (entity == null) { response.Timestamp = DateTime.UtcNow; response.Success = false; response.Message = "Import failed! Entity with such name does not exist!"; response.Errors.Add(new ErrorModel("entityName", entityName, "Entity with such name does not exist!")); return response; } DbFileRepository fs = new DbFileRepository(); DbFile file = fs.Find(fileTempPath); if (file == null) { response.Timestamp = DateTime.UtcNow; response.Success = false; response.Message = "Import failed! File does not exist!"; response.Errors.Add(new ErrorModel("fileTempPath", fileTempPath, "Import failed! File does not exist!")); return response; } byte[] fileBytes = file.GetBytes(); MemoryStream fileStream = new MemoryStream(fileBytes); //fileStream.Write(fileBytes, 0, fileBytes.Length); //fileStream.Flush(); TextReader reader = new StreamReader(fileStream); CsvReader csvReader = new CsvReader(reader); csvReader.Configuration.HasHeaderRecord = true; csvReader.Configuration.IsHeaderCaseSensitive = false; csvReader.Read(); List<string> columns = csvReader.FieldHeaders.ToList(); List<dynamic> fieldMetaList = new List<dynamic>(); foreach (var column in columns) { Field field; if (column.Contains(RELATION_SEPARATOR)) { var relationData = column.Split(RELATION_SEPARATOR).Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); if (relationData.Count > 2) throw new Exception(string.Format("The specified field name '{0}' is incorrect. Only first level relation can be specified.", column)); string relationName = relationData[0]; string relationFieldName = relationData[1]; if (string.IsNullOrWhiteSpace(relationName) || relationName == "$" || relationName == "$$") throw new Exception(string.Format("Invalid relation '{0}'. The relation name is not specified.", column)); else if (!relationName.StartsWith("$")) throw new Exception(string.Format("Invalid relation '{0}'. The relation name is not correct.", column)); else relationName = relationName.Substring(1); //check for target priority mark $$ if (relationName.StartsWith("$")) { relationName = relationName.Substring(1); } if (string.IsNullOrWhiteSpace(relationFieldName)) throw new Exception(string.Format("Invalid relation '{0}'. The relation field name is not specified.", column)); var relation = relations.SingleOrDefault(x => x.Name == relationName); if (relation == null) throw new Exception(string.Format("Invalid relation '{0}'. The relation does not exist.", column)); if (relation.TargetEntityId != entity.Id && relation.OriginEntityId != entity.Id) throw new Exception(string.Format("Invalid relation '{0}'. The relation field belongs to entity that does not relate to current entity.", column)); Entity relationEntity = null; if (relation.OriginEntityId == entity.Id) { relationEntity = entities.FirstOrDefault(e => e.Id == relation.TargetEntityId); field = relationEntity.Fields.FirstOrDefault(f => f.Name == relationFieldName); } else { relationEntity = entities.FirstOrDefault(e => e.Id == relation.OriginEntityId); field = relationEntity.Fields.FirstOrDefault(f => f.Name == relationFieldName); } } else { field = entity.Fields.FirstOrDefault(f => f.Name == column); } dynamic fieldMeta = new ExpandoObject(); fieldMeta.ColumnName = column; fieldMeta.FieldType = field.GetFieldType(); fieldMetaList.Add(fieldMeta); } connection.BeginTransaction(); try { do { EntityRecord newRecord = new EntityRecord(); foreach (var fieldMeta in fieldMetaList) { string columnName = fieldMeta.ColumnName.ToString(); string value = csvReader.GetField<string>(columnName); if (value.StartsWith("[") && value.EndsWith("]")) { newRecord[columnName] = JsonConvert.DeserializeObject<List<string>>(value); } else { switch ((FieldType)fieldMeta.FieldType) { case FieldType.AutoNumberField: case FieldType.CurrencyField: case FieldType.NumberField: case FieldType.PercentField: { decimal decValue; if (decimal.TryParse(value, out decValue)) newRecord[columnName] = decValue; else newRecord[columnName] = null; } break; case FieldType.CheckboxField: { bool bValue; if (bool.TryParse(value, out bValue)) newRecord[columnName] = bValue; else newRecord[columnName] = null; } break; case FieldType.DateField: case FieldType.DateTimeField: { DateTime dtValue; if (DateTime.TryParse(value, out dtValue)) newRecord[columnName] = dtValue; else newRecord[columnName] = null; } break; case FieldType.MultiSelectField: { if (!string.IsNullOrWhiteSpace(value)) newRecord[columnName] = new List<string>(new string[] { value }); else newRecord[columnName] = null; } break; case FieldType.TreeSelectField: { if (!string.IsNullOrWhiteSpace(value)) newRecord[columnName] = new List<string>(new string[] { value }); else newRecord[columnName] = null; } break; case FieldType.GuidField: { Guid gValue; if (Guid.TryParse(value, out gValue)) newRecord[columnName] = gValue; else newRecord[columnName] = null; } break; default: { newRecord[columnName] = value; } break; } } } QueryResponse result; if (!newRecord.GetProperties().Any(x => x.Key == "id") || newRecord["id"] == null || string.IsNullOrEmpty(newRecord["id"].ToString())) { newRecord["id"] = Guid.NewGuid(); result = recMan.CreateRecord(entityName, newRecord); } else { result = recMan.UpdateRecord(entityName, newRecord); } if (!result.Success) { string message = result.Message; if (result.Errors.Count > 0) { foreach (ErrorModel error in result.Errors) message += " " + error.Message; } throw new Exception(message); } } while (csvReader.Read()); connection.CommitTransaction(); } catch (Exception e) { connection.RollbackTransaction(); response.Success = false; response.Object = null; response.Timestamp = DateTime.UtcNow; #if DEBUG response.Message = e.Message + e.StackTrace; #else response.Message = "Import failed! An internal error occurred!"; #endif } finally { reader.Close(); fileStream.Close(); } return response; } }
public IActionResult CreateEntityRecord(string entityName, [FromBody]EntityRecord postObj) { ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << create_record_input_filter >> ////////////////////////////////////////////////////////////////////////////////////// try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.record = postObj; hookFilterObj.controller = this; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.CreateRecordInput, entityName, hookFilterObj); postObj = hookFilterObj.record; } catch (Exception ex) { return Json(CreateErrorResponse("Plugin error in web hook create_record_input_filter: " + ex.Message)); }// <<< var validationErrors = new List<ErrorModel>(); //TODO implement validation if (postObj == null) postObj = new EntityRecord(); ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << create_record_validation_errors_filter >> ////////////////////////////////////////////////////////////////////////////////////// try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.errors = validationErrors; hookFilterObj.record = postObj; hookFilterObj.controller = this; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.CreateRecordValidationErrors, entityName, hookFilterObj); validationErrors = hookFilterObj.errors; } catch (Exception ex) { return Json(CreateErrorResponse("Plugin error in web hook create_record_validation_errors_filter: " + ex.Message)); }// <<< if (validationErrors.Count > 0) { var response = new ResponseModel(); response.Success = false; response.Timestamp = DateTime.UtcNow; response.Errors = validationErrors; response.Message = "Validation error occurred!"; response.Object = null; return Json(response); } if (!postObj.GetProperties().Any(x => x.Key == "id")) postObj["id"] = Guid.NewGuid(); else if (string.IsNullOrEmpty(postObj["id"] as string)) postObj["id"] = Guid.NewGuid(); //Create transaction var result = new QueryResponse(); using (var connection = DbContext.Current.CreateConnection()) { try { connection.BeginTransaction(); ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << create_record_pre_save_filter >> ////////////////////////////////////////////////////////////////////////////////////// try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.record = postObj; hookFilterObj.recordId = (Guid)postObj["id"]; hookFilterObj.controller = this; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.CreateRecordPreSave, entityName, hookFilterObj); postObj = hookFilterObj.record; } catch (Exception ex) { connection.RollbackTransaction(); return Json(CreateErrorResponse("Plugin error in web hook create_record_pre_save_filter: " + ex.Message)); }// <<< result = recMan.CreateRecord(entityName, postObj); connection.CommitTransaction(); } catch (Exception ex) { connection.RollbackTransaction(); var response = new ResponseModel(); response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error while saving the record: " + ex.Message; response.Object = null; return Json(response); } } ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK ACTION << create_record >> ////////////////////////////////////////////////////////////////////////////////////// try { dynamic hookActionObj = new ExpandoObject(); hookActionObj.record = postObj; hookActionObj.result = result; hookActionObj.controller = this; hooksService.ProcessActions(SystemWebHookNames.CreateRecordAction, entityName, hookActionObj); } catch (Exception ex) { return Json(CreateErrorResponse("Plugin error in web hook create_record_success_action: " + ex.Message)); }// <<< return DoResponse(result); }
public IActionResult CurrentUserPermissions() { var responseObj = new ResponseModel(); responseObj.Object = WebSecurityUtil.GetCurrentUserPermissions(HttpContext); responseObj.Success = true; responseObj.Timestamp = DateTime.UtcNow; return DoResponse(responseObj); }
public IActionResult ProjectTimelogReport(int year = 0, int month = 0) { var response = new ResponseModel(); if (year == 0 || month == 0) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Month or year parameter is missing"; response.Object = null; return Json(response); } try { var timelogs = new List<EntityRecord>(); var projects = new List<EntityRecord>(); var projectsWithTimelogs = new List<EntityRecord>(); var projectTaskBugsDict = new Dictionary<Guid, List<EntityRecord>>(); var workedTaskIds = new List<Guid>(); var workedBugIds = new List<Guid>(); var workedTasks = new List<EntityRecord>(); var workedBugs = new List<EntityRecord>(); var taskTimelogs = new Dictionary<Guid, List<EntityRecord>>(); var bugTimelogs = new Dictionary<Guid, List<EntityRecord>>(); #region << Get timelogs from the period >> var startDate = new DateTime(year, month, 1); var endDate = startDate.AddMonths(1); { var requestedFields = "billable,hours," + "$$bug_1_n_time_log.id,$$task_1_n_time_log.id"; var filterObj = EntityQuery.QueryAND(EntityQuery.QueryGTE("log_date", startDate), EntityQuery.QueryLT("log_date", endDate)); EntityQuery resultQuery = new EntityQuery("wv_timelog", requestedFields, filterObj); QueryResponse result = recMan.Find(resultQuery); if (!result.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = result.Message; response.Object = null; return Json(response); } timelogs = result.Object.Data; var addedTasks = new Dictionary<Guid, bool>(); var addedBugs = new Dictionary<Guid, bool>(); foreach (var timelog in timelogs) { if (((List<EntityRecord>)timelog["$task_1_n_time_log"]).Any()) { var task = ((List<EntityRecord>)timelog["$task_1_n_time_log"])[0]; var taskId = (Guid)task["id"]; if (!addedTasks.ContainsKey(taskId)) { addedTasks[taskId] = true; workedTaskIds.Add(taskId); } var timelogList = new List<EntityRecord>(); if (taskTimelogs.ContainsKey(taskId)) { timelogList = taskTimelogs[taskId]; timelogList.Add(timelog); } else { timelogList.Add(timelog); } taskTimelogs[taskId] = timelogList; } if (((List<EntityRecord>)timelog["$bug_1_n_time_log"]).Any()) { var bug = ((List<EntityRecord>)timelog["$bug_1_n_time_log"])[0]; var bugId = (Guid)bug["id"]; if (!addedBugs.ContainsKey(bugId)) { addedBugs[bugId] = true; workedBugIds.Add(bugId); } var timelogList = new List<EntityRecord>(); if (bugTimelogs.ContainsKey(bugId)) { timelogList = bugTimelogs[bugId]; timelogList.Add(timelog); } else { timelogList.Add(timelog); } bugTimelogs[bugId] = timelogList; } } } #endregion #region << Get tasks >> { if (workedTaskIds.Count() > 0) { var requestedFields = "id,subject,project_id"; var queryList = new List<QueryObject>(); foreach (var taskId in workedTaskIds) { var query = EntityQuery.QueryEQ("id", taskId); queryList.Add(query); } var filterObj = EntityQuery.QueryOR(queryList.ToArray()); var sortRulesList = new List<QuerySortObject>(); var sortRule = new QuerySortObject("created_on", QuerySortType.Ascending); sortRulesList.Add(sortRule); EntityQuery resultQuery = new EntityQuery("wv_task", requestedFields, filterObj, sortRulesList.ToArray()); QueryResponse result = recMan.Find(resultQuery); if (!result.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = result.Message; response.Object = null; return Json(response); } workedTasks = result.Object.Data; } } #endregion #region << Get bugs >> { if (workedBugIds.Count() > 0) { var requestedFields = "id,subject,project_id"; var queryList = new List<QueryObject>(); foreach (var bugId in workedBugIds) { var query = EntityQuery.QueryEQ("id", bugId); queryList.Add(query); } var filterObj = EntityQuery.QueryOR(queryList.ToArray()); var sortRulesList = new List<QuerySortObject>(); var sortRule = new QuerySortObject("created_on", QuerySortType.Ascending); sortRulesList.Add(sortRule); EntityQuery resultQuery = new EntityQuery("wv_bug", requestedFields, filterObj, sortRulesList.ToArray()); QueryResponse result = recMan.Find(resultQuery); if (!result.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = result.Message; response.Object = null; return Json(response); } workedBugs = result.Object.Data; } } #endregion #region << Generate project task & bugs dict >> foreach (var task in workedTasks) { var taskId = (Guid)task["id"]; var taskProjectId = (Guid)task["project_id"]; var taskBillable = (decimal)0; var taskNotBillable = (decimal)0; var taskTimeLogList = taskTimelogs[taskId]; foreach (var timelog in taskTimeLogList) { if ((bool)timelog["billable"]) { taskBillable += (decimal)timelog["hours"]; } else { taskNotBillable += (decimal)timelog["hours"]; } } task["billable"] = taskBillable; task["not_billable"] = taskNotBillable; task["type"] = "task"; var projectBugAndTasks = new List<EntityRecord>(); if (projectTaskBugsDict.ContainsKey(taskProjectId)) { projectBugAndTasks = projectTaskBugsDict[taskProjectId]; } projectBugAndTasks.Add(task); projectTaskBugsDict[taskProjectId] = projectBugAndTasks; } foreach (var bug in workedBugs) { var bugId = (Guid)bug["id"]; var bugProjectId = (Guid)bug["project_id"]; var bugBillable = (decimal)0; var bugNotBillable = (decimal)0; var bugTimeLogList = bugTimelogs[bugId]; foreach (var timelog in bugTimeLogList) { if ((bool)timelog["billable"]) { bugBillable += (decimal)timelog["hours"]; } else { bugNotBillable += (decimal)timelog["hours"]; } } bug["billable"] = bugBillable; bug["not_billable"] = bugNotBillable; bug["type"] = "bug"; var projectBugAndTasks = new List<EntityRecord>(); if (projectTaskBugsDict.ContainsKey(bugProjectId)) { projectBugAndTasks = projectTaskBugsDict[bugProjectId]; } projectBugAndTasks.Add(bug); projectTaskBugsDict[bugProjectId] = projectBugAndTasks; } #endregion #region << Get all projects >> { var requestedFields = "id,name"; var queryList = new List<QueryObject>(); foreach (var taskId in workedTaskIds) { var query = EntityQuery.QueryEQ("id", taskId); queryList.Add(query); } QueryObject filterObj = null; var sortRulesList = new List<QuerySortObject>(); var sortRule = new QuerySortObject("created_on", QuerySortType.Ascending); sortRulesList.Add(sortRule); EntityQuery resultQuery = new EntityQuery("wv_project", requestedFields, filterObj, sortRulesList.ToArray()); QueryResponse result = recMan.Find(resultQuery); if (!result.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = result.Message; response.Object = null; return Json(response); } projects = result.Object.Data; } #endregion #region << Generate project with logs >> var totalBillable = (decimal)0; var totalNotBillable = (decimal)0; foreach (var project in projects) { if (projectTaskBugsDict.ContainsKey((Guid)project["id"])) { var projectEntries = (List<EntityRecord>)projectTaskBugsDict[(Guid)project["id"]]; project["entries"] = projectEntries; project["billable"] = (decimal)0; project["not_billable"] = (decimal)0; foreach (var entry in projectEntries) { project["billable"] = (decimal)project["billable"] + (decimal)entry["billable"]; project["not_billable"] = (decimal)project["not_billable"] + (decimal)entry["not_billable"]; } totalBillable += (decimal)project["billable"]; totalNotBillable += (decimal)project["not_billable"]; projectsWithTimelogs.Add(project); } } #endregion #region var responseObject = new EntityRecord(); responseObject["projects"] = projectsWithTimelogs; responseObject["billable"] = totalBillable; responseObject["not_billable"] = totalNotBillable; response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "Report successfully generated"; response.Object = responseObject; return Json(response); #endregion } catch (Exception ex) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + ex.Message; response.Object = null; return Json(response); } }
public IActionResult ProjectMilestones(int page = 0) { var response = new ResponseModel(); #region << Can user read projects >> //Get current user ErpUser user = SecurityContext.CurrentUser; //Get entity meta var entity = entMan.ReadEntity("wv_milestone").Object; //check if user role has permissions var canRead = user.Roles.Any(x => entity.RecordPermissions.CanRead.Any(z => z == x.Id)); var canCreate = user.Roles.Any(x => entity.RecordPermissions.CanCreate.Any(z => z == x.Id)); var canUpdate = user.Roles.Any(x => entity.RecordPermissions.CanUpdate.Any(z => z == x.Id)); var canDelete = user.Roles.Any(x => entity.RecordPermissions.CanDelete.Any(z => z == x.Id)); if (!canRead) { response.Success = false; response.Message = "You do not have permission to read the projects in this system"; response.Timestamp = DateTime.UtcNow; return Json(response); //return empty object } #endregion #region << Get the project id >> var queryString = HttpContext.Request.QueryString.ToString(); var queryKeyValue = QueryHelpers.ParseQuery(queryString); var projectId = new Guid(); if (queryKeyValue.ContainsKey("recordId") && Guid.TryParse(queryKeyValue["recordId"], out projectId)) { } else { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Project Id either not found or not a GUID"; response.Object = null; } #endregion #region << Get milestone data >> var requestedFields = "id,name,start_date,end_date,x_tasks_not_started,x_tasks_in_progress,x_tasks_completed,x_bugs_opened,x_bugs_reopened,x_bugs_closed"; QueryObject filterObj = EntityQuery.QueryEQ("project_id", projectId); var sortList = new List<QuerySortObject>(); sortList.Add(new QuerySortObject("end_date", QuerySortType.Descending)); EntityQuery resultQuery = new EntityQuery("wv_milestone", requestedFields, filterObj, sortList.ToArray(), null, null, null); QueryResponse result = recMan.Find(resultQuery); if (!result.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = result.Message; response.Object = null; return Json(response); } #endregion var resultRecordsList = new List<EntityRecord>(); foreach (var record in result.Object.Data) { var recordObj = new EntityRecord(); recordObj["id"] = record["id"]; recordObj["name"] = record["name"]; recordObj["start_date"] = record["start_date"]; recordObj["end_date"] = record["end_date"]; #region << tasks Count "not started" vs "in progress" vs "completed" >> var tasksNotStarted = (decimal)record["x_tasks_not_started"]; var tasksInProgress = (decimal)record["x_tasks_in_progress"]; var tasksCompleted = (decimal)record["x_tasks_completed"]; recordObj["tasks_not_started_count"] = tasksNotStarted; recordObj["tasks_in_progress_count"] = tasksInProgress; recordObj["tasks_completed_count"] = tasksCompleted; if (tasksNotStarted + tasksInProgress + tasksCompleted > 0) { recordObj["tasks_not_started_percentage"] = Math.Round((decimal)(tasksNotStarted * 100) / (tasksNotStarted + tasksInProgress + tasksCompleted)); recordObj["tasks_in_progress_percentage"] = Math.Round((decimal)(tasksInProgress * 100) / (tasksNotStarted + tasksInProgress + tasksCompleted)); recordObj["tasks_completed_percentage"] = 100 - Math.Round((decimal)(tasksNotStarted * 100) / (tasksNotStarted + tasksInProgress + tasksCompleted)) - Math.Round((decimal)(tasksInProgress * 100) / (tasksNotStarted + tasksInProgress + tasksCompleted)); } else { recordObj["tasks_not_started_percentage"] = 0; recordObj["tasks_in_progress_percentage"] = 0; recordObj["tasks_completed_percentage"] = 0; } #endregion #region << bugs Count "opened" & "reopened" vs "closed" >> var bugsOpened = (decimal)record["x_bugs_opened"]; var bugsReOpened = (decimal)record["x_bugs_reopened"]; var bugsClosed = (decimal)record["x_bugs_closed"]; recordObj["bugs_opened_count"] = bugsOpened; recordObj["bugs_reopened_count"] = bugsReOpened; recordObj["bugs_closed_count"] = bugsClosed; if (bugsOpened + bugsReOpened + bugsClosed > 0) { recordObj["bugs_opened_percentage"] = Math.Round((decimal)(bugsOpened * 100) / (bugsOpened + bugsReOpened + bugsClosed)); recordObj["bugs_reopened_percentage"] = Math.Round((decimal)(bugsReOpened * 100) / (bugsOpened + bugsReOpened + bugsClosed)); recordObj["bugs_closed_percentage"] = 100 - Math.Round((decimal)(bugsOpened * 100) / (bugsOpened + bugsReOpened + bugsClosed)) - Math.Round((decimal)(bugsReOpened * 100) / (bugsOpened + bugsReOpened + bugsClosed)); } else { recordObj["bugs_opened_percentage"] = 0; recordObj["bugs_reopened_percentage"] = 0; recordObj["bugs_closed_percentage"] = 0; } #endregion resultRecordsList.Add(recordObj); } response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "My projects successfully read"; response.Object = resultRecordsList; return Json(response); }
public IActionResult MyProjects(int page = 0) { var response = new ResponseModel(); try { //var queryString = HttpContext.Request.QueryString; #region << Can user read projects >> //Get current user ErpUser user = SecurityContext.CurrentUser; //Get entity meta var entity = entMan.ReadEntity("wv_project").Object; //check if user role has permissions var canRead = user.Roles.Any(x => entity.RecordPermissions.CanRead.Any(z => z == x.Id)); var canCreate = user.Roles.Any(x => entity.RecordPermissions.CanCreate.Any(z => z == x.Id)); var canUpdate = user.Roles.Any(x => entity.RecordPermissions.CanUpdate.Any(z => z == x.Id)); var canDelete = user.Roles.Any(x => entity.RecordPermissions.CanDelete.Any(z => z == x.Id)); if (!canRead) { response.Success = false; response.Message = "You do not have permission to read the projects in this system"; response.Timestamp = DateTime.UtcNow; return Json(response); //return empty object } #endregion #region << Init fields >> var requestedFields = "id,name,code,start_date,end_date," + "x_milestones_opened,x_milestones_completed,x_tasks_not_started,x_tasks_in_progress,x_tasks_completed,x_bugs_opened,x_bugs_reopened,x_bugs_closed," + "$user_1_n_project_owner.id,$user_1_n_project_owner.image,$user_1_n_project_owner.username," + "$role_n_n_project_team.id,$role_n_n_project_customer.id"; #endregion #region << Query builder >> //This list support filters by name var queryString = HttpContext.Request.QueryString.ToString(); var queryKeyValue = QueryHelpers.ParseQuery(queryString); //Get the project name from query if exists QueryObject rootFilterSection = null; var auxFiltersRuleList = new List<QueryObject>(); if (queryKeyValue.ContainsKey("name")) { var projectIdRule = EntityQuery.QueryContains("name", (string)queryKeyValue["name"]); auxFiltersRuleList.Add(projectIdRule); } if (auxFiltersRuleList.Count > 0) { rootFilterSection = EntityQuery.QueryAND(auxFiltersRuleList.ToArray()); } EntityQuery resultQuery = new EntityQuery("wv_project", requestedFields, rootFilterSection, null, null, null, null); #endregion #region << Execute >> QueryResponse result = recMan.Find(resultQuery); var resultRecordsList = new List<EntityRecord>(); if (!result.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = result.Message; response.Object = null; return Json(response); } foreach (var record in result.Object.Data) { //Check if user can view the object var userIsPM = false; var userIsStaff = false; var userIsCustomer = false; #region << Check user roles >> foreach (var userRole in user.Roles) { if (!userIsPM) { userIsPM = ((List<EntityRecord>)record["$user_1_n_project_owner"]).Any(z => (Guid)z["id"] == user.Id); } if (!userIsStaff) { userIsStaff = ((List<EntityRecord>)record["$role_n_n_project_team"]).Any(z => (Guid)z["id"] == userRole.Id); } if (!userIsCustomer) { userIsCustomer = ((List<EntityRecord>)record["$role_n_n_project_customer"]).Any(z => (Guid)z["id"] == userRole.Id); } } #endregion if (userIsPM || userIsStaff || userIsCustomer) { var recordObj = new EntityRecord(); recordObj["id"] = record["id"]; recordObj["name"] = record["name"]; recordObj["code"] = record["code"]; recordObj["start_date"] = record["start_date"]; recordObj["end_date"] = record["end_date"]; recordObj["owner_image"] = ((List<EntityRecord>)record["$user_1_n_project_owner"])[0]["image"]; recordObj["owner_username"] = ((List<EntityRecord>)record["$user_1_n_project_owner"])[0]["username"]; #region << milestones Count "opened" vs "completed" >> var milestonesOpened = (decimal)record["x_milestones_opened"]; var milestonesCompleted = (decimal)record["x_milestones_completed"]; recordObj["milestones_opened_count"] = milestonesOpened; recordObj["milestones_completed_count"] = milestonesCompleted; if (milestonesOpened + milestonesCompleted > 0) { recordObj["milestones_opened_percentage"] = Math.Round((decimal)(milestonesOpened * 100) / (milestonesOpened + milestonesCompleted)); recordObj["milestones_completed_percentage"] = 100 - Math.Round((decimal)(milestonesOpened * 100) / (milestonesOpened + milestonesCompleted)); } else { recordObj["milestones_opened_percentage"] = 0; recordObj["milestones_completed_percentage"] = 0; } #endregion #region << tasks Count "not started" vs "in progress" vs "completed" >> var tasksNotStarted = (decimal)record["x_tasks_not_started"]; var tasksInProgress = (decimal)record["x_tasks_in_progress"]; var tasksCompleted = (decimal)record["x_tasks_completed"]; recordObj["tasks_not_started_count"] = tasksNotStarted; recordObj["tasks_in_progress_count"] = tasksInProgress; recordObj["tasks_completed_count"] = tasksCompleted; if (tasksNotStarted + tasksInProgress + tasksCompleted > 0) { recordObj["tasks_not_started_percentage"] = Math.Round((decimal)(tasksNotStarted * 100) / (tasksNotStarted + tasksInProgress + tasksCompleted)); recordObj["tasks_in_progress_percentage"] = Math.Round((decimal)(tasksInProgress * 100) / (tasksNotStarted + tasksInProgress + tasksCompleted)); recordObj["tasks_completed_percentage"] = 100 - Math.Round((decimal)(tasksNotStarted * 100) / (tasksNotStarted + tasksInProgress + tasksCompleted)) - Math.Round((decimal)(tasksInProgress * 100) / (tasksNotStarted + tasksInProgress + tasksCompleted)); } else { recordObj["tasks_not_started_percentage"] = 0; recordObj["tasks_in_progress_percentage"] = 0; recordObj["tasks_completed_percentage"] = 0; } #endregion #region << bugs Count "opened" & "reopened" vs "closed" >> var bugsOpened = (decimal)record["x_bugs_opened"]; var bugsReOpened = (decimal)record["x_bugs_reopened"]; var bugsClosed = (decimal)record["x_bugs_closed"]; recordObj["bugs_opened_count"] = bugsOpened; recordObj["bugs_reopened_count"] = bugsReOpened; recordObj["bugs_closed_count"] = bugsClosed; if (bugsOpened + bugsReOpened + bugsClosed > 0) { recordObj["bugs_opened_percentage"] = Math.Round((decimal)(bugsOpened * 100) / (bugsOpened + bugsReOpened + bugsClosed)); recordObj["bugs_reopened_percentage"] = Math.Round((decimal)(bugsReOpened * 100) / (bugsOpened + bugsReOpened + bugsClosed)); recordObj["bugs_closed_percentage"] = 100 - Math.Round((decimal)(bugsOpened * 100) / (bugsOpened + bugsReOpened + bugsClosed)) - Math.Round((decimal)(bugsReOpened * 100) / (bugsOpened + bugsReOpened + bugsClosed)); } else { recordObj["bugs_opened_percentage"] = 0; recordObj["bugs_reopened_percentage"] = 0; recordObj["bugs_closed_percentage"] = 0; } #endregion resultRecordsList.Add(recordObj); } } #endregion //var skipRecords = list.PageSize * (page - 1); //if (page != 0) //{ // resultRecordsList = resultRecordsList.Skip(skipRecords).Take(page).ToList(); //} response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "My projects successfully read"; response.Object = resultRecordsList; return Json(response); } catch (Exception ex) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + ex.Message; response.Object = null; return Json(response); } }
public IActionResult ExportListRecordsToCsv(string entityName, string listName, int count = 10) { if(count == -1) { //return all records } else if(count > 0) { //returh the defined count of records } else { //return empty list } //Just for test var theExportFilePathInTempGridFs = "/fs/entityGuid/listGuid/timestamp/boz-export-path.csv"; var response = new ResponseModel(); response.Success = true; response.Message = "Records successfully exported"; response.Object = theExportFilePathInTempGridFs; return DoResponse(response); }
public IActionResult ImportEntityRecordsFromCsv(string entityName, [FromBody]string fileTempPath) { //The import CSV should have column names matching the names of the imported fields. The first column should be "id" matching the id of the record to be updated. //If the 'id' of a record equals 'null', a new record will be created with the provided columns and default values for the missing ones. var response = new ResponseModel(); response.Success = true; response.Message = "Records successfully imported"; response.Object = null; return DoResponse(response); }
public ResponseModel EvaluateImportEntityRecordsFromCsv(string entityName, JObject postObject, bool enableWebHooks = true, object controller = null) { ResponseModel response = new ResponseModel(); response.Message = "Records successfully evaluated"; response.Timestamp = DateTime.UtcNow; response.Success = true; response.Object = null; List<EntityRelation> relations = relMan.Read().Object; EntityListResponse entitiesResponse = entMan.ReadEntities(); List<Entity> entities = entitiesResponse.Object; Entity entity = entities.FirstOrDefault(e => e.Name == entityName); if (entity == null) { response.Success = false; response.Message = "Entity not found"; return response; } var entityFields = entity.Fields; string fileTempPath = ""; string clipboard = ""; string generalCommand = "evaluate"; EntityRecord commands = new EntityRecord(); if (!postObject.IsNullOrEmpty() && postObject.Properties().Any(p => p.Name == "fileTempPath")) { fileTempPath = postObject["fileTempPath"].ToString(); } if (!postObject.IsNullOrEmpty() && postObject.Properties().Any(p => p.Name == "clipboard")) { clipboard = postObject["clipboard"].ToString(); } if (!postObject.IsNullOrEmpty() && postObject.Properties().Any(p => p.Name == "general_command")) { generalCommand = postObject["general_command"].ToString(); //could be "evaluate" & "evaluate-import" the first will just evaluate, the second one will evaluate and import if all is fine } if (!postObject.IsNullOrEmpty() && generalCommand == "evaluate-import" && postObject.Properties().Any(p => p.Name == "commands") && !((JToken)postObject["commands"]).IsNullOrEmpty()) { var commandsObject = postObject["commands"].Value<JObject>(); if (!commandsObject.IsNullOrEmpty() && commandsObject.Properties().Any()) { foreach (var property in commandsObject.Properties()) { commands[property.Name] = ((JObject)property.Value).ToObject<EntityRecord>(); } } } //VALIDATE: if (fileTempPath == "" && clipboard == "") { response.Success = false; response.Message = "Both clipboard and file CSV sources are empty!"; return response; } CsvReader csvReader = null; string csvContent = ""; bool usingClipboard = false; //CASE: 1 If fileTempPath != "" -> get the csv from the file if (fileTempPath != "") { if (fileTempPath.StartsWith("/fs")) fileTempPath = fileTempPath.Remove(0, 3); if (!fileTempPath.StartsWith("/")) fileTempPath = "/" + fileTempPath; fileTempPath = fileTempPath.ToLowerInvariant(); DbFileRepository fs = new DbFileRepository(); DbFile file = fs.Find(fileTempPath); if (file == null) { response.Timestamp = DateTime.UtcNow; response.Success = false; response.Message = "Import failed! File does not exist!"; response.Errors.Add(new ErrorModel("fileTempPath", fileTempPath, "Import failed! File does not exist!")); return response; } byte[] fileBytes = file.GetBytes(); MemoryStream fileStream = new MemoryStream(fileBytes); TextReader reader = new StreamReader(fileStream); csvReader = new CsvReader(reader); } //CASE: 2 If fileTempPath == "" -> get the csv from the clipboard else { csvContent = clipboard; usingClipboard = true; csvReader = new CsvReader(new StringReader(csvContent)); } csvReader.Configuration.HasHeaderRecord = true; csvReader.Configuration.IsHeaderCaseSensitive = false; if (usingClipboard) { csvReader.Configuration.Delimiter = "\t"; } //The evaluation object has two properties - errors and warnings. Both are objects //The error validation object should return arrays by field name ex. {field_name:[null,null,"error message"]} //The warning validation object should return arrays by field name ex. {field_name:[null,null,"warning message"]} var evaluationObj = new EntityRecord(); evaluationObj["errors"] = new EntityRecord(); evaluationObj["warnings"] = new EntityRecord(); evaluationObj["records"] = new List<EntityRecord>(); evaluationObj["commands"] = new EntityRecord(); // the commands is object with properties the fieldNames and the following object as value {command: "to_create" | "no_import" | "to_update", fieldType: 14, fieldName: "name", fieldLabel: "label"} var statsObject = new EntityRecord(); statsObject["to_create"] = 0; statsObject["no_import"] = 0; statsObject["to_update"] = 0; statsObject["errors"] = 0; statsObject["warnings"] = 0; evaluationObj["stats"] = statsObject; evaluationObj["general_command"] = generalCommand; csvReader.Read(); List<string> columnNames = csvReader.FieldHeaders.ToList(); foreach (var columnName in columnNames) { //Init the error list for this field if (!((EntityRecord)evaluationObj["errors"]).GetProperties().Any(p => p.Key == columnName)) { ((EntityRecord)evaluationObj["errors"])[columnName] = new List<string>(); } //Init the warning list for this field var warningList = new List<string>(); if (!((EntityRecord)evaluationObj["warnings"]).GetProperties().Any(p => p.Key == columnName)) { ((EntityRecord)evaluationObj["warnings"])[columnName] = new List<string>(); } bool existingField = false; Field currentFieldMeta = null; Field relationEntityFieldMeta = null; Field relationFieldMeta = null; Entity relationEntity = null; string direction = "origin-target"; EntityRelationType relationType = EntityRelationType.OneToMany; string fieldEnityName = entity.Name; string fieldRelationName = string.Empty; if (!commands.GetProperties().Any(p => p.Key == columnName)) { commands[columnName] = new EntityRecord(); ((EntityRecord)commands[columnName])["command"] = "no_import"; ((EntityRecord)commands[columnName])["entityName"] = fieldEnityName; ((EntityRecord)commands[columnName])["fieldType"] = FieldType.TextField; ((EntityRecord)commands[columnName])["fieldName"] = columnName; ((EntityRecord)commands[columnName])["fieldLabel"] = columnName; } if (columnName.Contains(RELATION_SEPARATOR)) { var relationData = columnName.Split(RELATION_SEPARATOR).Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); if (relationData.Count > 2) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("The specified field name '{0}' is incorrect. Only first level relation can be specified.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } string relationName = relationData[0]; string relationFieldName = relationData[1]; if (string.IsNullOrWhiteSpace(relationName) || relationName == "$" || relationName == "$$") { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. The relation name is not specified.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } else if (!relationName.StartsWith("$")) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. The relation name is not correct.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } else relationName = relationName.Substring(1); //check for target priority mark $$ if (relationName.StartsWith("$")) { relationName = relationName.Substring(1); direction = "target-origin"; } if (string.IsNullOrWhiteSpace(relationFieldName)) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. The relation field name is not specified.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } var relation = relations.SingleOrDefault(x => x.Name == relationName); if (relation == null) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. The relation does not exist.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } if (relation.TargetEntityId != entity.Id && relation.OriginEntityId != entity.Id) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. The relation field belongs to entity that does not relate to current entity.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } if (relation.OriginEntityId == relation.TargetEntityId) { if (direction == "origin-target") { relationEntity = entity; relationEntityFieldMeta = relationEntity.Fields.FirstOrDefault(f => f.Id == relation.TargetFieldId); currentFieldMeta = relationEntity.Fields.FirstOrDefault(f => f.Name == relationFieldName); relationFieldMeta = entity.Fields.FirstOrDefault(f => f.Id == relation.OriginFieldId); } else { relationEntity = entity; relationEntityFieldMeta = relationEntity.Fields.FirstOrDefault(f => f.Id == relation.OriginFieldId); currentFieldMeta = relationEntity.Fields.FirstOrDefault(f => f.Name == relationFieldName); relationFieldMeta = entity.Fields.FirstOrDefault(f => f.Id == relation.TargetFieldId); } } else if (relation.OriginEntityId == entity.Id) { //direction doesn't matter relationEntity = entities.FirstOrDefault(e => e.Id == relation.TargetEntityId); relationEntityFieldMeta = relationEntity.Fields.FirstOrDefault(f => f.Id == relation.TargetFieldId); currentFieldMeta = relationEntity.Fields.FirstOrDefault(f => f.Name == relationFieldName); relationFieldMeta = entity.Fields.FirstOrDefault(f => f.Id == relation.OriginFieldId); } else { //direction doesn't matter relationEntity = entities.FirstOrDefault(e => e.Id == relation.OriginEntityId); relationEntityFieldMeta = relationEntity.Fields.FirstOrDefault(f => f.Id == relation.OriginFieldId); currentFieldMeta = relationEntity.Fields.FirstOrDefault(f => f.Name == relationFieldName); relationFieldMeta = entity.Fields.FirstOrDefault(f => f.Id == relation.TargetFieldId); } if (currentFieldMeta == null) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. Fields with such name does not exist.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } if (currentFieldMeta.GetFieldType() == FieldType.MultiSelectField || currentFieldMeta.GetFieldType() == FieldType.TreeSelectField) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. Fields from Multiselect and Treeselect types can't be used as relation fields.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } if (relation.RelationType == EntityRelationType.OneToOne && ((relation.TargetEntityId == entity.Id && relationFieldMeta.Name == "id") || (relation.OriginEntityId == entity.Id && relationEntityFieldMeta.Name == "id"))) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. Can't use relations when relation field is id field.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } fieldEnityName = relationEntity.Name; fieldRelationName = relationName; relationType = relation.RelationType; } else { currentFieldMeta = entity.Fields.FirstOrDefault(f => f.Name == columnName); } if (currentFieldMeta != null) { existingField = true; } if (!existingField && !string.IsNullOrWhiteSpace(fieldRelationName)) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Creation of a new relation field is not allowed.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } #region << Commands >> //we need to init the command for this column - if it is new field the default is do nothing, if it is existing the default is update if (existingField) { if (generalCommand == "evaluate") { ((EntityRecord)commands[columnName])["command"] = "to_update"; ((EntityRecord)commands[columnName])["relationName"] = fieldRelationName; ((EntityRecord)commands[columnName])["relationDirection"] = direction; ((EntityRecord)commands[columnName])["relationType"] = relationType; ((EntityRecord)commands[columnName])["entityName"] = fieldEnityName; ((EntityRecord)commands[columnName])["fieldType"] = currentFieldMeta.GetFieldType(); ((EntityRecord)commands[columnName])["fieldName"] = currentFieldMeta.Name; ((EntityRecord)commands[columnName])["fieldLabel"] = currentFieldMeta.Label; bool hasPermisstion = SecurityContext.HasEntityPermission(EntityPermission.Update, entity); if (!hasPermisstion) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add($"Access denied. Trying to update record in entity '{entity.Name}' with no update access."); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } ((EntityRecord)commands[columnName])["currentFieldMeta"] = currentFieldMeta; ((EntityRecord)commands[columnName])["relationEntityFieldMeta"] = relationEntityFieldMeta; ((EntityRecord)commands[columnName])["relationFieldMeta"] = relationFieldMeta; } else { if (generalCommand == "evaluate") { //we need to check wheather the property of the command match the fieldName ((EntityRecord)commands[columnName])["command"] = "to_create"; ((EntityRecord)commands[columnName])["entityName"] = fieldEnityName; ((EntityRecord)commands[columnName])["fieldType"] = FieldType.TextField; ((EntityRecord)commands[columnName])["fieldName"] = columnName; ((EntityRecord)commands[columnName])["fieldLabel"] = columnName; bool hasPermisstion = SecurityContext.HasEntityPermission(EntityPermission.Create, entity); if (!hasPermisstion) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add($"Access denied. Trying to create record in entity '{entity.Name}' with no create access."); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } } #endregion } evaluationObj["commands"] = commands; do { Dictionary<string, EntityRecord> fieldsFromRelationList = new Dictionary<string, EntityRecord>(); Dictionary<string, string> rowRecordData = new Dictionary<string, string>(); foreach (var columnName in columnNames) { string fieldValue = csvReader.GetField<string>(columnName); rowRecordData[columnName] = fieldValue; EntityRecord commandRecords = ((EntityRecord)commands[columnName]); Field currentFieldMeta = new TextField(); if (commandRecords.GetProperties().Any(p => p.Key == "currentFieldMeta")) currentFieldMeta = (Field)commandRecords["currentFieldMeta"]; if (columnName.Contains(RELATION_SEPARATOR)) { string relationName = (string)((EntityRecord)commands[columnName])["relationName"]; string relationDirection = (string)((EntityRecord)commands[columnName])["relationDirection"]; string relationEntityName = (string)((EntityRecord)commands[columnName])["entityName"]; EntityRelationType relationType = (EntityRelationType)Enum.Parse(typeof(EntityRelationType), (((EntityRecord)commands[columnName])["relationType"]).ToString()); Field relationEntityFieldMeta = (Field)((EntityRecord)commands[columnName])["relationEntityFieldMeta"]; Field relationFieldMeta = (Field)((EntityRecord)commands[columnName])["relationFieldMeta"]; var relation = relations.SingleOrDefault(x => x.Name == relationName); string relationFieldValue = ""; if (columnNames.Any(c => c == relationFieldMeta.Name)) relationFieldValue = csvReader.GetField<string>(relationFieldMeta.Name); QueryObject filter = null; if ((relationType == EntityRelationType.OneToMany && relation.OriginEntityId == relation.TargetEntityId && relationDirection == "origin-target") || (relationType == EntityRelationType.OneToMany && relation.OriginEntityId != relation.TargetEntityId && relation.OriginEntityId == entity.Id) || relationType == EntityRelationType.ManyToMany) { //expect array of values if (!columnNames.Any(c => c == relationFieldMeta.Name) || string.IsNullOrEmpty(relationFieldValue)) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. Relation field does not exist into input record data or its value is null.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } List<string> values = new List<string>(); if (relationFieldValue.StartsWith("[") && relationFieldValue.EndsWith("]")) { values = JsonConvert.DeserializeObject<List<string>>(relationFieldValue); } if (values.Count < 1) continue; List<QueryObject> queries = new List<QueryObject>(); foreach (var val in values) { queries.Add(EntityQuery.QueryEQ(currentFieldMeta.Name, val)); } filter = EntityQuery.QueryOR(queries.ToArray()); } else { filter = EntityQuery.QueryEQ(currentFieldMeta.Name, DbRecordRepository.ExtractFieldValue(fieldValue, currentFieldMeta, true)); } EntityRecord fieldsFromRelation = new EntityRecord(); if (fieldsFromRelationList.Any(r => r.Key == relation.Name)) { fieldsFromRelation = fieldsFromRelationList[relationName]; } else { fieldsFromRelation["columns"] = new List<string>(); fieldsFromRelation["queries"] = new List<QueryObject>(); fieldsFromRelation["direction"] = relationDirection; fieldsFromRelation["relationEntityName"] = relationEntityName; } ((List<string>)fieldsFromRelation["columns"]).Add(columnName); ((List<QueryObject>)fieldsFromRelation["queries"]).Add(filter); fieldsFromRelationList[relationName] = fieldsFromRelation; } } foreach (var fieldsFromRelation in fieldsFromRelationList) { EntityRecord fieldsFromRelationValue = fieldsFromRelation.Value; List<string> columnList = (List<string>)fieldsFromRelationValue["columns"]; List<QueryObject> queries = (List<QueryObject>)fieldsFromRelationValue["queries"]; string relationDirection = (string)fieldsFromRelationValue["direction"]; string relationEntityName = (string)fieldsFromRelationValue["relationEntityName"]; QueryObject filter = EntityQuery.QueryAND(queries.ToArray()); var relation = relations.SingleOrDefault(r => r.Name == fieldsFromRelation.Key); //get related records QueryResponse relatedRecordResponse = recMan.Find(new EntityQuery(relationEntityName, "*", filter, null, null, null)); if (!relatedRecordResponse.Success || relatedRecordResponse.Object.Data.Count < 1) { foreach (var columnName in columnList) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. The relation record does not exist.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } else if (relatedRecordResponse.Object.Data.Count > 1 && ((relation.RelationType == EntityRelationType.OneToMany && relation.OriginEntityId == relation.TargetEntityId && relationDirection == "target-origin") || (relation.RelationType == EntityRelationType.OneToMany && relation.OriginEntityId != relation.TargetEntityId && relation.TargetEntityId == entity.Id) || relation.RelationType == EntityRelationType.OneToOne)) { //there can be no more than 1 records foreach (var columnName in columnList) { ((List<string>)((EntityRecord)evaluationObj["errors"])[columnName]).Add(string.Format("Invalid relation '{0}'. There are multiple relation records matching this value.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } fieldsFromRelationList[fieldsFromRelation.Key]["relatedRecordResponse"] = relatedRecordResponse; } var rowRecord = new EntityRecord(); if ((int)statsObject["errors"] == 0) { foreach (var columnName in columnNames) { string fieldValue = rowRecordData[columnName]; EntityRecord commandRecords = ((EntityRecord)commands[columnName]); Field currentFieldMeta = new TextField(); if (commandRecords.GetProperties().Any(p => p.Key == "currentFieldMeta")) currentFieldMeta = (Field)commandRecords["currentFieldMeta"]; string fieldEnityName = (string)commandRecords["entityName"]; string command = (string)commandRecords["command"]; bool existingField = false; if (command == "to_update") existingField = true; if (existingField) { #region << Validation >> var errorsList = (List<string>)((EntityRecord)evaluationObj["errors"])[columnName]; var warningList = (List<string>)((EntityRecord)evaluationObj["warnings"])[columnName]; if (columnName.Contains(RELATION_SEPARATOR)) { string relationName = (string)((EntityRecord)commands[columnName])["relationName"]; string relationDirection = (string)((EntityRecord)commands[columnName])["relationDirection"]; string relationEntityName = (string)((EntityRecord)commands[columnName])["entityName"]; EntityRelationType relationType = (EntityRelationType)Enum.Parse(typeof(EntityRelationType), (((EntityRecord)commands[columnName])["relationType"]).ToString()); Field relationEntityFieldMeta = (Field)((EntityRecord)commands[columnName])["relationEntityFieldMeta"]; Field relationFieldMeta = (Field)((EntityRecord)commands[columnName])["relationFieldMeta"]; var relation = relations.SingleOrDefault(x => x.Name == relationName); QueryResponse relatedRecordResponse = (QueryResponse)fieldsFromRelationList[relationName]["relatedRecordResponse"]; var relatedRecords = relatedRecordResponse.Object.Data; List<Guid> relatedRecordValues = new List<Guid>(); foreach (var relatedRecord in relatedRecords) { relatedRecordValues.Add((Guid)relatedRecord[relationEntityFieldMeta.Name]); } string relationFieldValue = ""; if (columnNames.Any(c => c == relationFieldMeta.Name)) relationFieldValue = rowRecordData[relationFieldMeta.Name]; if (relation.RelationType == EntityRelationType.OneToOne && ((relation.OriginEntityId == relation.TargetEntityId && relationDirection == "origin-target") || relation.OriginEntityId == entity.Id)) { if (!columnNames.Any(c => c == relationFieldMeta.Name) || string.IsNullOrWhiteSpace(relationFieldValue)) { errorsList.Add(string.Format("Invalid relation '{0}'. Relation field does not exist into input record data or its value is null.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } else if (relation.RelationType == EntityRelationType.OneToMany && ((relation.OriginEntityId == relation.TargetEntityId && relationDirection == "origin-target") || relation.OriginEntityId == entity.Id)) { if (!columnNames.Any(c => c == relationFieldMeta.Name) || string.IsNullOrWhiteSpace(relationFieldValue)) { errorsList.Add(string.Format("Invalid relation '{0}'. Relation field does not exist into input record data or its value is null.", columnName)); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } else if (relation.RelationType == EntityRelationType.ManyToMany) { foreach (Guid relatedRecordIdValue in relatedRecordValues) { Guid relRecordId = Guid.Empty; if (!Guid.TryParse(relationFieldValue, out relRecordId)) { errorsList.Add("Invalid record value for field: '" + columnName + "'. Invalid value: '" + fieldValue + "'"); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } } } if (string.IsNullOrWhiteSpace(fieldValue)) { if (currentFieldMeta.Required && currentFieldMeta.Name != "id") { errorsList.Add("Field is required. Value can not be empty!"); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } else if (!(fieldValue.StartsWith("[") && fieldValue.EndsWith("]"))) { FieldType fType = (FieldType)currentFieldMeta.GetFieldType(); switch (fType) { case FieldType.AutoNumberField: case FieldType.CurrencyField: case FieldType.NumberField: case FieldType.PercentField: { decimal decValue; if (!decimal.TryParse(fieldValue, out decValue)) { errorsList.Add("Value have to be of decimal type!"); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } break; case FieldType.CheckboxField: { bool bValue; if (!bool.TryParse(fieldValue, out bValue)) { errorsList.Add("Value have to be of boolean type!"); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } break; case FieldType.DateField: case FieldType.DateTimeField: { DateTime dtValue; if (!DateTime.TryParse(fieldValue, out dtValue)) { errorsList.Add("Value have to be of datetime type!"); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } break; case FieldType.MultiSelectField: { } break; case FieldType.SelectField: { if (!((SelectField)currentFieldMeta).Options.Any(o => o.Key == fieldValue)) { errorsList.Add("Value does not exist in select field options!"); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } break; case FieldType.TreeSelectField: { } break; case FieldType.GuidField: { Guid gValue; if (!Guid.TryParse(fieldValue, out gValue)) { errorsList.Add("Value have to be of guid type!"); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; } } break; } } ((EntityRecord)evaluationObj["errors"])[columnName] = errorsList; //validate the value for warnings ((EntityRecord)evaluationObj["warnings"])[columnName] = warningList; #endregion } #region << Data >> //Submit row data if (!(command == "no_import" && generalCommand == "evaluate-import")) rowRecord[columnName] = fieldValue; #endregion } if (enableWebHooks && generalCommand == "evaluate-import") { #region << WebHook Filters >> Guid? recordId = null; if (rowRecord.GetProperties().Any(p => p.Key == "id") && !string.IsNullOrWhiteSpace((string)rowRecord["id"])) { Guid id; if (Guid.TryParse((string)rowRecord["id"], out id)) recordId = id; } ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTERS << create_record_input_filter >> AND << update_record_input_filter >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.record = rowRecord; hookFilterObj.recordId = recordId; hookFilterObj.controller = controller; string webHookName = (!recordId.HasValue || recordId.Value == Guid.Empty) ? SystemWebHookNames.CreateRecordInput : SystemWebHookNames.UpdateRecordInput; hookFilterObj = hooksService.ProcessFilters(webHookName, entityName, hookFilterObj); rowRecord = hookFilterObj.record; } catch (Exception ex) { response.Success = false; response.Object = evaluationObj; response.Timestamp = DateTime.UtcNow; response.Message = (!recordId.HasValue || recordId.Value == Guid.Empty) ? "Plugin error in web hook create_record_input_filter: " + ex.Message : "Plugin error in web hook update_record_input_filter: " + ex.Message; return response; //throw new Exception("Plugin error in web hook update_record_input_filter: " + ex.Message); }// <<< #endregion var validationErrors = new List<ErrorModel>(); ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << update_record_validation_errors_filter >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.errors = validationErrors; hookFilterObj.record = rowRecord; hookFilterObj.recordId = recordId; hookFilterObj.controller = controller; string webHookName = (!recordId.HasValue || recordId.Value == Guid.Empty) ? SystemWebHookNames.CreateRecordValidationErrors : SystemWebHookNames.UpdateRecordValidationErrors; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.UpdateRecordValidationErrors, entityName, hookFilterObj); validationErrors = hookFilterObj.errors; } catch (Exception ex) { response.Success = false; response.Object = evaluationObj; response.Timestamp = DateTime.UtcNow; response.Message = (!recordId.HasValue || recordId.Value == Guid.Empty) ? "Plugin error in web hook create_record_validation_errors_filter: " + ex.Message : "Plugin error in web hook update_record_validation_errors_filter: " + ex.Message; return response; //throw new Exception ("Plugin error in web hook update_record_validation_errors_filter: " + ex.Message)); }// <<< #endregion if (validationErrors.Count > 0) { List<string> errorsList = (List<string>)((EntityRecord)evaluationObj["errors"])["id"]; foreach (var validationError in validationErrors) { errorsList.Add(validationError.Message); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; continue; } } #endregion } } else { foreach (var columnName in columnNames) { EntityRecord commandRecords = ((EntityRecord)commands[columnName]); string command = (string)commandRecords["command"]; string fieldValue = csvReader.GetField<string>(columnName); if (!(command == "no_import" && generalCommand == "evaluate-import")) rowRecord[columnName] = fieldValue; } } ((List<EntityRecord>)evaluationObj["records"]).Add(rowRecord); } while (csvReader.Read()); foreach (var columnName in columnNames) { if (commands.GetProperties().Any(p => p.Key == columnName)) { ((EntityRecord)commands[columnName]).Properties.Remove("currentFieldMeta"); ((EntityRecord)commands[columnName]).Properties.Remove("relationEntityFieldMeta"); ((EntityRecord)commands[columnName]).Properties.Remove("relationFieldMeta"); } } if ((int)statsObject["errors"] > 0) { if (generalCommand == "evaluate-import") { response.Success = false; //evaluationObj["general_command"] = "evaluate"; } response.Object = evaluationObj; return response; } if (generalCommand == "evaluate-import") { using (DbConnection connection = DbContext.Current.CreateConnection()) { connection.BeginTransaction(); try { int fieldCreated = 0; foreach (var columnName in columnNames) { string command = (string)((EntityRecord)commands[columnName])["command"]; if (command == "to_create") { FieldType fieldType = (FieldType)Enum.Parse(typeof(FieldType), (((EntityRecord)commands[columnName])["fieldType"]).ToString()); string fieldName = (string)((EntityRecord)commands[columnName])["fieldName"]; string fieldLabel = (string)((EntityRecord)commands[columnName])["fieldLabel"]; var result = entMan.CreateField(entity.Id, fieldType, null, fieldName, fieldLabel); if (!result.Success) { string message = result.Message; if (result.Errors.Count > 0) { foreach (ErrorModel error in result.Errors) message += " " + error.Message; } throw new Exception(message); } fieldCreated++; } } int successfullyCreatedRecordsCount = 0; int successfullyUpdatedRecordsCount = 0; List<EntityRecord> records = (List<EntityRecord>)evaluationObj["records"]; foreach (EntityRecord record in records) { EntityRecord newRecord = record; QueryResponse result; if (!newRecord.GetProperties().Any(x => x.Key == "id") || newRecord["id"] == null || string.IsNullOrEmpty(newRecord["id"].ToString())) { newRecord["id"] = Guid.NewGuid(); if (enableWebHooks) { ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << create_record_pre_save_filter >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.record = newRecord; hookFilterObj.recordId = (Guid)newRecord["id"]; hookFilterObj.controller = controller; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.CreateRecordPreSave, entityName, hookFilterObj); newRecord = hookFilterObj.record; } catch (Exception ex) { throw new Exception("Plugin error in web hook create_record_pre_save_filter: " + ex.Message); }// <<< #endregion } result = recMan.CreateRecord(entityName, newRecord); if (result.Success) successfullyCreatedRecordsCount++; if (result.Success && enableWebHooks) { ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK ACTION << create_record >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookActionObj = new ExpandoObject(); hookActionObj.record = result.Object.Data[0]; hookActionObj.result = result; hookActionObj.controller = controller; hooksService.ProcessActions(SystemWebHookNames.CreateRecordAction, entityName, hookActionObj); } catch (Exception ex) { throw new Exception("Plugin error in web hook create_record_success_action: " + ex.Message); }// <<< #endregion } } else { if (enableWebHooks) { Guid id; if (Guid.TryParse((string)newRecord["id"], out id)) newRecord["id"] = id; ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << update_record_pre_save_filter >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.record = newRecord; hookFilterObj.recordId = new Guid(newRecord["id"].ToString()); hookFilterObj.controller = controller; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.UpdateRecordPreSave, entityName, hookFilterObj); newRecord = hookFilterObj.record; } catch (Exception ex) { throw new Exception("Plugin error in web hook update_record_pre_save_filter: " + ex.Message); }// <<< #endregion } result = recMan.UpdateRecord(entityName, newRecord); if (result.Success) successfullyUpdatedRecordsCount++; if (result.Success && enableWebHooks) { ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK ACTION << update_record_success_action >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookActionObj = new ExpandoObject(); hookActionObj.record = result.Object.Data[0]; hookActionObj.oldRecord = newRecord; hookActionObj.result = result; hookActionObj.recordId = result.Object.Data[0]["id"]; hookActionObj.controller = controller; hooksService.ProcessActions(SystemWebHookNames.UpdateRecordAction, entityName, hookActionObj); } catch (Exception ex) { throw new Exception("Plugin error in web hook update_record_success_action: " + ex.Message); }// <<< #endregion } } if (!result.Success) { string message = result.Message; if (result.Errors.Count > 0) { foreach (ErrorModel error in result.Errors) message += " " + error.Message; } throw new Exception(message); } } ((EntityRecord)evaluationObj["stats"])["to_create"] = successfullyCreatedRecordsCount; ((EntityRecord)evaluationObj["stats"])["to_update"] = successfullyUpdatedRecordsCount; ((EntityRecord)evaluationObj["stats"])["total_records"] = records.Count; ((EntityRecord)evaluationObj["stats"])["fields_created"] = fieldCreated; connection.CommitTransaction(); } catch (Exception e) { //WebVella.ERP.Api.Cache.ClearEntities(); connection.RollbackTransaction(); ((EntityRecord)evaluationObj["stats"])["errors"] = (int)((EntityRecord)evaluationObj["stats"])["errors"] + 1; response.Success = false; response.Object = evaluationObj; response.Timestamp = DateTime.UtcNow; #if DEBUG response.Message = e.Message + e.StackTrace; #else response.Message = "Import failed! An internal error occurred!"; #endif } } Cache.ClearEntities(); response.Object = evaluationObj; return response; } response.Object = evaluationObj; return response; }
public IActionResult Logout() { WebSecurityUtil.Logout(HttpContext); var responseObj = new ResponseModel(); responseObj.Object = null; responseObj.Success = true; responseObj.Timestamp = DateTime.UtcNow; return DoResponse(responseObj); }
public IActionResult SprintDetails(Guid? sprintId = null, string scope = "user") { var response = new ResponseModel(); var runningSprints = new List<EntityRecord>(); var currentSprint = new EntityRecord(); var userDictionary = new Dictionary<Guid, EntityRecord>(); try { Guid? currentSprintId = null; #region << Get all users >> { var query = new EntityQuery("user"); var queryResponse = recMan.Find(query); if (!queryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + queryResponse.Message; response.Object = null; return Json(response); } foreach (var user in queryResponse.Object.Data) { userDictionary[(Guid)user["id"]] = user; } } #endregion #region << Init the current sprint id >> if (sprintId == null) { //Get all current sprints { var sprintFields = "id"; var queryFilter = EntityQuery.QueryAND(EntityQuery.QueryLTE("start_date", DateTime.UtcNow), EntityQuery.QueryGTE("end_date", DateTime.UtcNow.AddDays(-1))); var sortRulesList = new List<QuerySortObject>(); var sortRule = new QuerySortObject("start_date", QuerySortType.Ascending); sortRulesList.Add(sortRule); var query = new EntityQuery("wv_sprint", sprintFields, queryFilter, sortRulesList.ToArray()); var queryResponse = recMan.Find(query); if (!queryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + queryResponse.Message; response.Object = null; return Json(response); } if (queryResponse.Object.Data.Any()) { runningSprints = queryResponse.Object.Data; } else { response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "Sprints successfully read, but no current sprints found!"; response.Object = null; return Json(response); } } //Find the first sprint that is current to the current data currentSprintId = (Guid)runningSprints[0]["id"]; } else { currentSprintId = sprintId; } #endregion #region << Get current sprint details >> { var fields = "id,start_date,end_date,name," + "$wv_sprint_n_n_wv_task.id,$wv_sprint_n_n_wv_task.code,$wv_sprint_n_n_wv_task.owner_id, $wv_sprint_n_n_wv_task.priority,$wv_sprint_n_n_wv_task.status,$wv_sprint_n_n_wv_task.subject," + "$wv_sprint_n_n_wv_task.x_billable_hours,$wv_sprint_n_n_wv_task.x_nonbillable_hours,$wv_sprint_n_n_wv_task.estimation," + "$$role_n_n_wv_sprint.id"; var queryFilter = EntityQuery.QueryEQ("id", currentSprintId); var query = new EntityQuery("wv_sprint", fields, queryFilter); var queryResponse = recMan.Find(query); if (!queryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + queryResponse.Message; response.Object = null; return Json(response); } if (!queryResponse.Object.Data.Any()) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "There is no sprint with this Id"; response.Object = null; return Json(response); } currentSprint = queryResponse.Object.Data[0]; var sprintRoleRecords = (List<EntityRecord>)currentSprint["$role_n_n_wv_sprint"]; //Check if the current user can see the sprint var userRoles = SecurityContext.CurrentUser.Roles; var userCanAccessSprint = false; foreach(var role in sprintRoleRecords) { if(userRoles.Any(x => x.Id == (Guid)role["id"])) { userCanAccessSprint = true; break; } } if(!userCanAccessSprint) { response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "no access"; response.Object = null; return Json(response); } } #endregion var processedSprintObject = new EntityRecord(); processedSprintObject["id"] = (Guid)currentSprint["id"]; processedSprintObject["start_date"] = (DateTime)currentSprint["start_date"]; processedSprintObject["end_date"] = (DateTime)currentSprint["end_date"]; processedSprintObject["name"] = (string)currentSprint["name"]; processedSprintObject["estimation"] = (decimal)0; processedSprintObject["logged"] = (decimal)0; processedSprintObject["tasks_not_started"] = new List<EntityRecord>(); processedSprintObject["tasks_in_progress"] = new List<EntityRecord>(); processedSprintObject["tasks_completed"] = new List<EntityRecord>(); foreach (var task in (List<EntityRecord>)currentSprint["$wv_sprint_n_n_wv_task"]) { if ((scope == "user" && (Guid)task["owner_id"] == SecurityContext.CurrentUser.Id) || scope != "user") { var proccessedTask = new EntityRecord(); proccessedTask["id"] = (Guid)task["id"]; proccessedTask["code"] = (string)task["code"]; proccessedTask["priority"] = (string)task["priority"]; proccessedTask["status"] = (string)task["status"]; proccessedTask["subject"] = (string)task["subject"]; proccessedTask["estimation"] = (decimal)task["estimation"]; proccessedTask["logged"] = (decimal)task["x_nonbillable_hours"] + (decimal)task["x_billable_hours"]; proccessedTask["owner_username"] = (string)userDictionary[(Guid)task["owner_id"]]["username"]; proccessedTask["owner_image"] = (string)userDictionary[(Guid)task["owner_id"]]["image"]; switch ((string)task["status"]) { case "not started": ((List<EntityRecord>)processedSprintObject["tasks_not_started"]).Add(proccessedTask); break; case "in progress": ((List<EntityRecord>)processedSprintObject["tasks_in_progress"]).Add(proccessedTask); break; case "completed": ((List<EntityRecord>)processedSprintObject["tasks_completed"]).Add(proccessedTask); break; } processedSprintObject["estimation"] = (decimal)processedSprintObject["estimation"] + (decimal)task["estimation"]; processedSprintObject["logged"] = (decimal)processedSprintObject["logged"] + (decimal)proccessedTask["logged"]; } } processedSprintObject["estimation"] = Math.Round((decimal)processedSprintObject["estimation"],2); processedSprintObject["logged"] = Math.Round((decimal)processedSprintObject["logged"],2); response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "My projects successfully read"; response.Object = processedSprintObject; return Json(response); } catch (Exception ex) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error: " + ex.Message; response.Object = null; return Json(response); } }
public IActionResult UpdateEntityRecord(string entityName, Guid recordId, [FromBody]EntityRecord postObj) { if (!postObj.Properties.ContainsKey("id")) { postObj["id"] = recordId; } ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << update_record_input_filter >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.record = postObj; hookFilterObj.recordId = recordId; hookFilterObj.controller = this; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.UpdateRecordInput, entityName, hookFilterObj); postObj = hookFilterObj.record; } catch (Exception ex) { return Json(CreateErrorResponse("Plugin error in web hook update_record_input_filter: " + ex.Message)); }// <<< #endregion var validationErrors = new List<ErrorModel>(); //TODO implement validation ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << update_record_validation_errors_filter >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.errors = validationErrors; hookFilterObj.record = postObj; hookFilterObj.recordId = recordId; hookFilterObj.controller = this; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.UpdateRecordValidationErrors, entityName, hookFilterObj); validationErrors = hookFilterObj.errors; } catch (Exception ex) { return Json(CreateErrorResponse("Plugin error in web hook update_record_validation_errors_filter: " + ex.Message)); }// <<< #endregion if (validationErrors.Count > 0) { var response = new ResponseModel(); response.Success = false; response.Timestamp = DateTime.UtcNow; response.Errors = validationErrors; response.Message = "Validation error occurred!"; response.Object = null; return Json(response); } //clear authentication cache if (entityName == "user") WebSecurityUtil.RemoveIdentityFromCache(recordId); //Create transaction var result = new QueryResponse(); using (var connection = DbContext.Current.CreateConnection()) { try { connection.BeginTransaction(); ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << update_record_pre_save_filter >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.record = postObj; hookFilterObj.recordId = new Guid(postObj["id"].ToString()); hookFilterObj.controller = this; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.UpdateRecordPreSave, entityName, hookFilterObj); postObj = hookFilterObj.record; } catch (Exception ex) { connection.RollbackTransaction(); return Json(CreateErrorResponse("Plugin error in web hook update_record_pre_save_filter: " + ex.Message)); }// <<< #endregion result = recMan.UpdateRecord(entityName, postObj); connection.CommitTransaction(); } catch (Exception ex) { connection.RollbackTransaction(); var response = new ResponseModel(); response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error while saving the record: " + ex.Message; response.Object = null; return Json(response); } } ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK ACTION << update_record_success_action >> ////////////////////////////////////////////////////////////////////////////////////// #region try { dynamic hookActionObj = new ExpandoObject(); hookActionObj.record = postObj; hookActionObj.oldRecord = postObj; hookActionObj.result = result; hookActionObj.recordId = recordId; hookActionObj.controller = this; hooksService.ProcessActions(SystemWebHookNames.UpdateRecordAction, entityName, hookActionObj); } catch (Exception ex) { return Json(CreateErrorResponse("Plugin error in web hook update_record_success_action: " + ex.Message)); }// <<< #endregion return DoResponse(result); }
public IActionResult AllTaskUserCanSee(string listName, int page = 0) { var response = new ResponseModel(); try { //var queryString = HttpContext.Request.QueryString; #region << Can user read tasks >> //Get current user ErpUser user = SecurityContext.CurrentUser; //Get entity meta var entity = entMan.ReadEntity("wv_task").Object; //check if user role has permissions var canRead = user.Roles.Any(x => entity.RecordPermissions.CanRead.Any(z => z == x.Id)); var canCreate = user.Roles.Any(x => entity.RecordPermissions.CanCreate.Any(z => z == x.Id)); var canUpdate = user.Roles.Any(x => entity.RecordPermissions.CanUpdate.Any(z => z == x.Id)); var canDelete = user.Roles.Any(x => entity.RecordPermissions.CanDelete.Any(z => z == x.Id)); if (!canRead) { response.Success = false; response.Message = "You do not have permission to read the projects in this system"; response.Timestamp = DateTime.UtcNow; return Json(response); //return empty object } #endregion var taskQueryResponse = new QueryResponse(); var userCanSeeProjectIds = new List<Guid>(); #region << Generate list of projects user can see >> { var requestedFields = "id,$user_1_n_project_owner.id,$role_n_n_project_team.id,$role_n_n_project_customer.id"; //QueryObject filterObj = EntityQuery.QueryEQ("id", recordId); QueryObject filterObj = null; EntityQuery resultQuery = new EntityQuery("wv_project", requestedFields, filterObj, null, null, null, null); QueryResponse result = recMan.Find(resultQuery); var resultRecordsList = new List<EntityRecord>(); if (!result.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = result.Message; response.Object = null; return Json(response); } foreach (var record in result.Object.Data) { //Check if user can view the object var userIsPM = false; var userIsStaff = false; var userIsCustomer = false; #region << Check user roles >> foreach (var userRole in user.Roles) { if (!userIsPM) { userIsPM = ((List<EntityRecord>)record["$user_1_n_project_owner"]).Any(z => (Guid)z["id"] == user.Id); } if (!userIsStaff) { userIsStaff = ((List<EntityRecord>)record["$role_n_n_project_team"]).Any(z => (Guid)z["id"] == userRole.Id); } if (!userIsCustomer) { userIsCustomer = ((List<EntityRecord>)record["$role_n_n_project_customer"]).Any(z => (Guid)z["id"] == userRole.Id); } } #endregion if (userIsPM || userIsStaff || userIsCustomer) { userCanSeeProjectIds.Add((Guid)record["id"]); } } } #endregion #region << Get tasks >> { var fields = "id,code,number,subject,start_date,end_date,status,priority,$user_1_n_task_owner.id,$user_1_n_task_owner.image"; QueryObject rootFilterSection = null; QueryObject auxFilterSection = null; QueryObject projectIdFilterSection = null; #region << project id filters >> var projectIdRulesList = new List<QueryObject>(); foreach (var projectId in userCanSeeProjectIds) { var projectIdRule = EntityQuery.QueryEQ("project_id", projectId); projectIdRulesList.Add(projectIdRule); } projectIdFilterSection = EntityQuery.QueryOR(projectIdRulesList.ToArray()); #endregion #region << Aux filters & Sort>> var sortRulesList = new List<QuerySortObject>(); var queryString = HttpContext.Request.QueryString.ToString(); var queryKeyValueList = QueryHelpers.ParseQuery(queryString); var auxRulesList = new List<QueryObject>(); var getListObject = entMan.ReadRecordList(entity.Name, listName).Object; //Currently we will hardcode the query generation //auxFilterSection = RecordListQuery.ConvertQuery(getListObject.Query); QueryObject auxRule = new QueryObject(); foreach (var query in queryKeyValueList) { switch (query.Key.ToLowerInvariant()) { case "code": auxRule = new QueryObject(); auxRule = EntityQuery.QueryContains("code", (string)query.Value); auxRulesList.Add(auxRule); break; case "subject": auxRule = new QueryObject(); auxRule = EntityQuery.QueryContains("subject", (string)query.Value); auxRulesList.Add(auxRule); break; case "status": auxRule = new QueryObject(); auxRule = EntityQuery.QueryEQ("status", (string)query.Value); auxRulesList.Add(auxRule); break; case "priority": auxRule = new QueryObject(); auxRule = EntityQuery.QueryEQ("priority", (string)query.Value); auxRulesList.Add(auxRule); break; case "sortby": var sortRule = new QuerySortObject((string)query.Value, QuerySortType.Descending); if (!queryKeyValueList.ContainsKey("sortOrder") || (string)queryKeyValueList["sortOrder"] == "ascending") { sortRule = new QuerySortObject((string)query.Value, QuerySortType.Ascending); } sortRulesList.Add(sortRule); break; } } auxFilterSection = EntityQuery.QueryAND(auxRulesList.ToArray()); //Add default sort by created_on var defaultSortRule = new QuerySortObject("created_on", QuerySortType.Ascending); sortRulesList.Add(defaultSortRule); #endregion rootFilterSection = EntityQuery.QueryAND(projectIdFilterSection, auxFilterSection); //Calculate page var pageSize = getListObject.PageSize; var skipRecords = (page - 1) * pageSize; var taskQuery = new EntityQuery("wv_task", fields, rootFilterSection, sortRulesList.ToArray(), skipRecords, pageSize, null); taskQueryResponse = recMan.Find(taskQuery); if (!taskQueryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = taskQueryResponse.Message; response.Object = null; return Json(response); } } #endregion var taskList = new List<EntityRecord>(); #region << Post-process >> foreach (var task in taskQueryResponse.Object.Data) { var record = new EntityRecord(); record["id"] = (Guid)task["id"]; record["code"] = (string)task["code"]; record["subject"] = (string)task["subject"]; record["start_date"] = (DateTime)task["start_date"]; record["end_date"] = (DateTime)task["end_date"]; record["status"] = (string)task["status"]; record["priority"] = (string)task["priority"]; var taskOwnerIdList = new List<Guid>(); var taskOwnerImageList = new List<string>(); var taskOwnerId = (Guid)((List<EntityRecord>)task["$user_1_n_task_owner"])[0]["id"]; var taskOwnerImage = (string)((List<EntityRecord>)task["$user_1_n_task_owner"])[0]["image"]; taskOwnerIdList.Add(taskOwnerId); taskOwnerImageList.Add(taskOwnerImage); record["$field$user_1_n_task_owner$id"] = taskOwnerIdList; record["$field$user_1_n_task_owner$image"] = taskOwnerImageList; taskList.Add(record); } #endregion response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "Successful read"; response.Object = taskList; return Json(response); } catch (Exception ex) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = ex.Message; response.Object = null; return Json(response); } }
public IActionResult DeleteRecord(Guid recordId, string entityName) { ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << delete_record_input_filter >> ////////////////////////////////////////////////////////////////////////////////////// try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.recordId = recordId; hookFilterObj.controller = this; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.DeleteRecordInput, entityName, hookFilterObj); recordId = hookFilterObj.recordId; } catch (Exception ex) { return Json(CreateErrorResponse("Plugin error in web hook delete_record_input_filter: " + ex.Message)); }// <<< var validationErrors = new List<ErrorModel>(); ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << delete_record_validation_errors_filter >> ////////////////////////////////////////////////////////////////////////////////////// try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.errors = validationErrors; hookFilterObj.recordId = recordId; hookFilterObj.controller = this; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.DeleteRecordValidationErrors, entityName, hookFilterObj); validationErrors = hookFilterObj.errors; } catch (Exception ex) { return Json(CreateErrorResponse("Plugin error in web hook delete_record_validation_errors_filter: " + ex.Message)); }// <<< if (validationErrors.Count > 0) { var response = new ResponseModel(); response.Success = false; response.Timestamp = DateTime.UtcNow; response.Errors = validationErrors; response.Message = "Validation error occurred!"; response.Object = null; return Json(response); } //Create transaction var result = new QueryResponse(); using (var connection = DbContext.Current.CreateConnection()) { try { connection.BeginTransaction(); ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK FILTER << delete_record_pre_save_filter >> ////////////////////////////////////////////////////////////////////////////////////// try { dynamic hookFilterObj = new ExpandoObject(); hookFilterObj.recordId = recordId; hookFilterObj.controller = this; hookFilterObj = hooksService.ProcessFilters(SystemWebHookNames.DeleteRecordPreSave, entityName, hookFilterObj); recordId = hookFilterObj.recordId; } catch (Exception ex) { connection.RollbackTransaction(); return Json(CreateErrorResponse("Plugin error in web hook delete_record_pre_save_filter: " + ex.Message)); }// <<< result = recMan.DeleteRecord(entityName, recordId); connection.CommitTransaction(); } catch (Exception ex) { connection.RollbackTransaction(); var response = new ResponseModel(); response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = "Error while delete the record: " + ex.Message; response.Object = null; return Json(response); } } ////////////////////////////////////////////////////////////////////////////////////// //WEBHOOK ACTION << delete_record_success_action >> ////////////////////////////////////////////////////////////////////////////////////// try { dynamic hookActionObj = new ExpandoObject(); hookActionObj.recordId = recordId; hookActionObj.result = result; hookActionObj.controller = this; hooksService.ProcessActions(SystemWebHookNames.DeleteRecordAction, entityName, hookActionObj); } catch (Exception ex) { return Json(CreateErrorResponse("Plugin error in web hook delete_record_success_action: " + ex.Message)); }// <<< return DoResponse(result); }
public IActionResult AllActivitiesUserCanSee(string label = "all", int page = 1) { var response = new ResponseModel(); try { //var queryString = HttpContext.Request.QueryString; #region << Can user read activities >> //Get current user ErpUser user = SecurityContext.CurrentUser; //Get entity meta var entity = entMan.ReadEntity("wv_project_activity").Object; //check if user role has permissions var canRead = user.Roles.Any(x => entity.RecordPermissions.CanRead.Any(z => z == x.Id)); var canCreate = user.Roles.Any(x => entity.RecordPermissions.CanCreate.Any(z => z == x.Id)); var canUpdate = user.Roles.Any(x => entity.RecordPermissions.CanUpdate.Any(z => z == x.Id)); var canDelete = user.Roles.Any(x => entity.RecordPermissions.CanDelete.Any(z => z == x.Id)); if (!canRead) { response.Success = false; response.Message = "You do not have permission to read the activities in this system"; response.Timestamp = DateTime.UtcNow; return Json(response); //return empty object } #endregion var activityQueryResponse = new QueryResponse(); var userCanSeeProjectIds = new List<Guid>(); #region << Generate list of projects user can see >> { var requestedFields = "id,$user_1_n_project_owner.id,$role_n_n_project_team.id,$role_n_n_project_customer.id"; //QueryObject filterObj = EntityQuery.QueryEQ("id", recordId); QueryObject filterObj = null; EntityQuery resultQuery = new EntityQuery("wv_project", requestedFields, filterObj, null, null, null, null); QueryResponse result = recMan.Find(resultQuery); var resultRecordsList = new List<EntityRecord>(); if (!result.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = result.Message; response.Object = null; return Json(response); } foreach (var record in result.Object.Data) { //Check if user can view the object var userIsPM = false; var userIsStaff = false; var userIsCustomer = false; #region << Check user roles >> foreach (var userRole in user.Roles) { if (!userIsPM) { userIsPM = ((List<EntityRecord>)record["$user_1_n_project_owner"]).Any(z => (Guid)z["id"] == user.Id); } if (!userIsStaff) { userIsStaff = ((List<EntityRecord>)record["$role_n_n_project_team"]).Any(z => (Guid)z["id"] == userRole.Id); } if (!userIsCustomer) { userIsCustomer = ((List<EntityRecord>)record["$role_n_n_project_customer"]).Any(z => (Guid)z["id"] == userRole.Id); } } #endregion if (userIsPM || userIsStaff || userIsCustomer) { userCanSeeProjectIds.Add((Guid)record["id"]); } } } #endregion #region << Get activities >> { var fields = "id,label,created_on,description,subject," + "$user_wv_project_activity_created_by.username,$user_wv_project_activity_created_by.image," + "$project_1_n_activity.name"; QueryObject rootFilterSection = null; QueryObject auxFilterSection = null; QueryObject projectIdFilterSection = null; #region << project id filters >> var projectIdRulesList = new List<QueryObject>(); foreach (var projectId in userCanSeeProjectIds) { var projectIdRule = EntityQuery.QueryEQ("project_id", projectId); projectIdRulesList.Add(projectIdRule); } projectIdFilterSection = EntityQuery.QueryOR(projectIdRulesList.ToArray()); #endregion #region << Aux filters & Sort>> var auxRulesList = new List<QueryObject>(); QueryObject auxRule = new QueryObject(); if (label != "all") { auxRule = EntityQuery.QueryEQ("label", label); auxRulesList.Add(auxRule); } auxFilterSection = EntityQuery.QueryAND(auxRulesList.ToArray()); //Add default sort by created_on var sortRulesList = new List<QuerySortObject>(); var defaultSortRule = new QuerySortObject("created_on", QuerySortType.Descending); sortRulesList.Add(defaultSortRule); #endregion rootFilterSection = EntityQuery.QueryAND(projectIdFilterSection, auxFilterSection); //Calculate page var pageSize = 10; var skipRecords = (page - 1) * pageSize; var activityQuery = new EntityQuery("wv_project_activity", fields, rootFilterSection, sortRulesList.ToArray(), skipRecords, pageSize, null); activityQueryResponse = recMan.Find(activityQuery); if (!activityQueryResponse.Success) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = activityQueryResponse.Message; response.Object = null; return Json(response); } } #endregion response.Success = true; response.Timestamp = DateTime.UtcNow; response.Message = "Successful read"; response.Object = activityQueryResponse.Object.Data; return Json(response); } catch (Exception ex) { response.Success = false; response.Timestamp = DateTime.UtcNow; response.Message = ex.Message; response.Object = null; return Json(response); } }
public IActionResult GetPlugins() { var responseObj = new ResponseModel(); responseObj.Object = new PluginService().Plugins; responseObj.Success = true; responseObj.Timestamp = DateTime.UtcNow; return DoResponse(responseObj); }
public ResponseModel ExportListRecordsToCsv(string entityName, string listName, Stream exportStream, Dictionary<string, string> queries, int count = 10) { ResponseModel response = new ResponseModel(); response.Message = "Records successfully exported"; response.Timestamp = DateTime.UtcNow; response.Success = true; response.Object = null; EntityListResponse entitiesResponse = entMan.ReadEntities(); List<Entity> entities = entitiesResponse.Object; Entity entity = entities.FirstOrDefault(e => e.Name == entityName); if (entity == null) { response.Timestamp = DateTime.UtcNow; response.Success = false; response.Message = "Export failed! Entity with such name does not exist!"; response.Errors.Add(new ErrorModel("entityName", entityName, "Entity with such name does not exist!")); return response; } bool hasPermisstion = SecurityContext.HasEntityPermission(EntityPermission.Read, entity); if (!hasPermisstion) { response.Success = false; response.Message = "Export failed! Trying to read records from entity '" + entity.Name + "' with no read access."; response.Errors.Add(new ErrorModel { Message = "Access denied." }); return response; } List<EntityRelation> relations = new List<EntityRelation>(); var relationResponse = relMan.Read(); if (relationResponse.Success) relations = relationResponse.Object; try { RecordList listMeta = entity.RecordLists.FirstOrDefault(l => l.Name == listName); QueryObject queryObj = null; if (queries.Count > 0) { List<QueryObject> queryObjList = new List<QueryObject>(); if (listMeta != null) { foreach (var query in queries) { if (listMeta.Columns.Any(c => c.DataName == query.Key)) { queryObjList.Add(EntityQuery.QueryContains(query.Key, query.Value)); } } } if (queryObjList.Count == 1) queryObj = queryObjList[0]; else if (queryObjList.Count > 1) queryObj = EntityQuery.QueryAND(queryObjList.ToArray()); } int page = 1; int pageSize = 100; int offset = 0; while (true) { var stream = new MemoryStream(); if (count > 0 && count < (pageSize * page)) { pageSize = count < pageSize ? count : (count - (pageSize * (page - 1))); } List<EntityRecord> records = null; if (count == -1) { records = recMan.GetListRecords(entities, entity, listName, null, queryObj, null, true, returnAllRecords: true); int recordsCount = records.Count(); pageSize = recordsCount > 0 ? recordsCount : 0; } else records = recMan.GetListRecords(entities, entity, listName, page, queryObj, pageSize, true); if (records.Count > 0) { var textWriter = new StreamWriter(stream); var csv = new CsvWriter(textWriter); csv.Configuration.QuoteAllFields = true; if (page == 1) { foreach (var prop in records[0].Properties) { var listItem = listMeta.Columns.FirstOrDefault(c => c.DataName == prop.Key); if (prop.Key.StartsWith("$field") && listItem == null) continue;// remove id field from relation that are not inserted as columns string name = prop.Key; if (prop.Key.StartsWith("$field$")) { name = prop.Key.Remove(0, 7); name = "$" + name.Replace('$', '.'); } csv.WriteField(name); } csv.NextRecord(); } foreach (var record in records) { foreach (var prop in record.Properties) { if (prop.Value != null) { if (prop.Value is List<object>) { var listItem = (RecordListRelationFieldItem)listMeta.Columns.FirstOrDefault(c => c.DataName == prop.Key); if (prop.Key.StartsWith("$field") && listItem == null) { continue;// remove id field from relation that are not inserted as columns } var type = listItem != null ? listItem.Meta.GetFieldType() : FieldType.GuidField; if (prop.Key.StartsWith("$field")) { var relationData = prop.Key.Split('$').Select(x => x.Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); var relation = relations.FirstOrDefault(r => r.Name == relationData[1]); if (relation.RelationType == EntityRelationType.ManyToMany || (relation.RelationType == EntityRelationType.OneToMany && relation.OriginEntityId == entity.Id)) csv.WriteField(JsonConvert.SerializeObject(prop.Value).ToString()); else if (((List<object>)prop.Value).Count > 0) csv.WriteField(((List<object>)prop.Value)[0] ?? ""); else csv.WriteField(""); } else if (type != FieldType.MultiSelectField && type != FieldType.TreeSelectField) { if (((List<object>)prop.Value).Count > 0) csv.WriteField(((List<object>)prop.Value)[0]); else csv.WriteField(""); } else { csv.WriteField(JsonConvert.SerializeObject(prop.Value).ToString()); } } else { csv.WriteField(prop.Value); } } else csv.WriteField(""); } csv.NextRecord(); textWriter.Flush(); } textWriter.Close(); } byte[] buffer = stream.ToArray(); exportStream.Write(buffer, offset, buffer.Length); offset += buffer.Length; exportStream.Flush(); if (records.Count <= pageSize) break; page++; } } catch (Exception ex) { response.Timestamp = DateTime.UtcNow; response.Success = false; response.Message = ex.Message; return response; } //exportStream.Close(); return response; }