Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion src/Libraries/Taskist.Service/WorkItems/BacklogItemService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public async Task<IPagedList<Backlog>> GetPagedListAsync(int assigneeId,
{
return await _backlogRepository.GetAllPagedAsync(query =>
{
query = query.Where(x => !x.Deleted); //r
if (projectId > 0)
query = query.Where(x => x.ProjectId == projectId);
else
Expand Down Expand Up @@ -186,7 +187,7 @@ await _backlogCommentRepository.InsertAsync(new BacklogComment
BacklogId = entity.Id,
CreatedById = entity.CreatedById,
CreatedOn = DateTime.UtcNow,
Comment = $"New {entity.TaskType.Name} created.",
Comment = $"New {entity.TaskType?.Name} ?? backlog created.", //r
SystemComment = true
});

Expand Down Expand Up @@ -283,6 +284,18 @@ public async Task DeleteAsync(Backlog entity)
await _backlogRepository.DeleteAsync(entity);
}

public async Task DeleteBacklogAsync(int id) //r
{
var entity = await _backlogRepository.GetByIdAsync(id);
if (entity == null)
throw new ArgumentNullException(nameof(entity));

entity.Deleted = true;

await _backlogRepository.UpdateAsync(entity);
}


#endregion

#region Methods For Documents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@ Task<IList<Backlog>> GetAllForExcelExportAsync(int assigneeId,


Task DeleteAsync(Backlog entity);
Task DeleteBacklogAsync(int id);

#region Documents
#region Documents

Task<IList<BacklogDocument>> GetAllDocumentAsync(int backlogId);
Task<IList<BacklogDocument>> GetAllDocumentAsync(int backlogId);

Task<Document> GetDocumentByIdAsync(int id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ public async Task<IActionResult> AddMember(UserProjectModel model)
CanReport = model.CanReport,
CanEdit = model.CanEdit,
CanReOpen = model.CanReOpen,
CanDelete =model.CanDelete,
CanClose = model.CanClose,
CanComment = model.CanComment,
CanViewOthersTask = model.CanViewOthersTask,
Expand Down Expand Up @@ -231,8 +232,19 @@ public async Task<IActionResult> EditMember(UserProjectModel model)
if (ModelState.IsValid)
{
var entity = await _projectService.GetMemberByIdAsync(model.Id);
entity = _mapper.Map(model, entity);

if (entity == null)
return Json(new JsonResponseModel { Status = HttpStatusCodeEnum.NoData });

entity.CanReport = model.CanReport;
entity.CanEdit = model.CanEdit;
entity.CanReOpen = model.CanReOpen;
entity.CanDelete = model.CanDelete;
entity.CanClose = model.CanClose;
entity.CanComment = model.CanComment;
entity.CanViewOthersTask = model.CanViewOthersTask;
entity.CanEditOthersTask = model.CanEditOthersTask;


await _projectService.UpdateMemberAsync(entity);

await _userActivityService.InsertAsync("ProjectMember", string.Format(await _localizationService.GetResourceAsync("Log.RecordUpdated"), entity.User.Name), entity);
Expand All @@ -241,7 +253,7 @@ public async Task<IActionResult> EditMember(UserProjectModel model)
{
Status = HttpStatusCodeEnum.Success,
Message = await _localizationService.GetResourceAsync("Message.UpdateSuccess")
});
});
}

return Json(new JsonResponseModel
Expand Down Expand Up @@ -419,6 +431,7 @@ public async Task<IActionResult> DataReadMember(int projectId, DataTableRequest
CanReport = x.CanReport,
CanEdit = x.CanEdit,
CanClose = x.CanClose,
CanDelete = x.CanDelete,
CanReOpen = x.CanReOpen,
CanComment = x.CanComment
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public async Task<IActionResult> Create(BacklogModel model, List<CustomFieldValu

if (fieldValues.Any())
{
var customFields = await _customFieldService.GetAllMandatoryAsync(lastAccessedProjectId);
var customFields = (await _customFieldService.GetAllMandatoryAsync(lastAccessedProjectId)).ToList();
if (customFields.Any())
{
var emptyValues = customFields.Where(x => fieldValues.Any(y => y.CustomFieldId == x.Id && string.IsNullOrEmpty(y.Value)));
Expand Down Expand Up @@ -193,7 +193,7 @@ public async Task<IActionResult> Edit(int id)
{
var projectAccess = await GetProjectAccess();
if (projectAccess == null || !projectAccess.CanReport && !projectAccess.CanEdit && !projectAccess.CanClose)
return AccessDenied();
return AccessDenied();

var entity = await _backlogItemService.GetByIdAsync(id);
if (entity == null)
Expand All @@ -202,10 +202,37 @@ public async Task<IActionResult> Edit(int id)
var model = _mapper.Map<BacklogModel>(entity);

await InitModelAsync(model);
model.CanEdit = await _permissionService.AuthorizeAsync(PermissionProvider.WorkItem.MANAGE_BACKLOGLOG);
model.CanDelete = await _permissionService.AuthorizeAsync(PermissionProvider.WorkItem.MANAGE_BACKLOGLOG);

return View(model);
}

[HttpPost("DeleteBacklog")]
[ValidateAntiForgeryToken]
[CheckPermission(PermissionProvider.WorkItem.MANAGE_BACKLOGLOG)]
public async Task<IActionResult> DeleteBacklogAsync(int id)
{

// check permission
if (!await _permissionService.AuthorizeAsync(PermissionProvider.WorkItem.MANAGE_BACKLOGLOG))
return Forbid();

var backlog = await _backlogItemService.GetByIdAsync(id);
if (backlog == null)
return NotFound();

backlog.Deleted = true;
await _backlogItemService.UpdateAsync(backlog);

return Json(new
{
success = true,
message = true ? "Backlog File deleted!" : "Oops, unable to delete the file!"
});

}

public async Task<IActionResult> Filter(int filterMode)
{
var model = new BacklogModel();
Expand Down Expand Up @@ -593,6 +620,7 @@ private async Task<BacklogPageModel> GetProjectAccess()
CanReport = projectMap != null && projectMap.CanReport,
CanEdit = projectMap != null && projectMap.CanEdit,
CanClose = projectMap != null && projectMap.CanClose,
CanDelete = projectMap != null && projectMap.CanDelete,
CanViewOthersTask = projectMap != null && projectMap.CanViewOthersTask,
CanEditOthersTask = projectMap != null && projectMap.CanEditOthersTask
};
Expand All @@ -615,6 +643,7 @@ private async Task InitModelAsync(BacklogModel model)
{
var access = await GetProjectAccess();
model.CanEdit = model.AssigneeId == loggedUser.Id || access.CanEditOthersTask;
model.CanDelete = access.CanDelete;
}
foreach (var item in taskTypes)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ public AutoMapperProfile()

CreateMap<Backlog, BacklogModel>().ReverseMap()
.ForMember(dest => dest.Code, act => act.Ignore())
.ForMember(dest => dest.AssigneeId, opt => opt.MapFrom(src => src.AssigneeId == -1 ? (int?)null : src.AssigneeId));
.ForMember(dest => dest.AssigneeId, opt => opt.MapFrom(src => src.AssigneeId == -1 ? (int?)null : src.AssigneeId))
.ForMember(dest => dest.SprintId, opt => opt.MapFrom(src => src.SprintId == -1 ? (int?)null : src.SprintId))
.ForMember(dest => dest.ReporterId, opt => opt.MapFrom(src => src.ReporterId == -1 ? (int?)null : src.ReporterId));

CreateMap<Sprint, SprintModel>().ReverseMap();
CreateMap<CustomField, CustomFieldRenderModel>();
Expand Down
9 changes: 7 additions & 2 deletions src/Presentation/Taskist.Web/Models/Users/UserProjectModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ public UserProjectModel()
[LocalizedDisplayName("UserProjectModel.CanClose")]
public bool CanClose { get; set; }

[LocalizedDisplayName("UserProjectModel.CanReOpen")]
[LocalizedDisplayName("UserProjectModel.CanDelete")]
public bool CanDelete { get; set; }

[LocalizedDisplayName("UserProjectModel.CanReOpen")]
public bool CanReOpen { get; set; }

[LocalizedDisplayName("UserProjectModel.CanComment")]
Expand All @@ -52,7 +55,9 @@ public class UserProjectGridModel : BaseModel

public bool CanClose { get; set; }

public bool CanReOpen { get; set; }
public bool CanDelete { get; set; }

public bool CanReOpen { get; set; }

public bool CanComment { get; set; }
}
2 changes: 2 additions & 0 deletions src/Presentation/Taskist.Web/Models/WorkItems/BacklogModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ public BacklogModel()

public bool CanEdit { get; set; }

public bool CanDelete { get; set; }

[LocalizedDisplayName("BacklogTask.CreatedBy")]
public int CreatedById { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public class BacklogPageModel

public bool CanClose { get; set; }

public bool CanDelete { get; set; }

public bool CanReOpen { get; set; }

public bool CanComment { get; set; }
Expand Down
45 changes: 44 additions & 1 deletion src/Presentation/Taskist.Web/Views/Backlog/Edit.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
<a asp-action="Index" class="btn btn-secondary">
<i class="fas fa-ban me-1"></i>@Localize("Button.Cancel")
</a>
@Html.AntiForgeryToken()
@if (Model.CanDelete)
{
<button type="button" class="btn btn-danger" onclick="confirmDelete(@Model.Id)">
<i class="fas fa-trash me-1"></i>@Localize("Button.Delete")
</button>
}

</div>
</div>
</div>
Expand All @@ -35,7 +43,40 @@
</div>
</div>
</form>

<script>

function confirmDelete(id) {
if (confirm("Are you sure you want to delete this backlog item?")) {

var token = $('#EditForm input[name="__RequestVerificationToken"]').val();

$.ajax({
url: '@Url.Action("DeleteBacklog", "Backlog")',
type: 'POST',
data: {
id: id,
__RequestVerificationToken: token
},
success: function (result) {
if (result.success) {
window.location.href = '@Url.Action("Index", "Backlog")';
}
},
error: function (xhr, status, error) {
console.error("Status: " + status);
console.error("Error: " + error);
console.error("Response: " + xhr.responseText);

if(xhr.status === 403) alert("You do not have permission to delete this.");
else if(xhr.status === 400) alert("Security validation failed (Anti-Forgery Token).");
else if(xhr.status === 404) alert("Delete action not found (URL mismatch).");
else alert("Delete failed: " + xhr.status);
}
});
}
}

$(function () {
let buttons = '';
JSManager.setPageTitle(`@Localize("BacklogPage.Title") #@Model.Id`);
Expand All @@ -44,4 +85,6 @@
buttons += `<a href="javascript:JSManager.openOffCanvas('@Url.Action("Comments", new { Id = Model.Id })','@Localize("BacklogPage.Button.Comments")')" title="@Localize("BacklogPage.Button.Comments")" class="btn btn-sm btn-success text-white me-2"><i class="fa-solid fa-comments"></i></a>`;
JSManager.setPageButtons(buttons);
});
</script>


</script>
4 changes: 4 additions & 0 deletions src/Presentation/Taskist.Web/Views/Project/Members.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@
new ColumnConditionModel { Value = "true", Operator = OperatorEnum.EQUAL, Icon = "fa fa-check", TextColor = "#2eb85c" },
new ColumnConditionModel { Value = "false", Operator = OperatorEnum.EQUAL, Icon = "fa fa-times", TextColor = "#e55353" }
}},
new ColumnModel { Title = Localize("ProjectMemberGrid.CanDelete").Text, DataColumn = "CanDelete", Conditions = new List<ColumnConditionModel>{
new ColumnConditionModel { Value = "true", Operator = OperatorEnum.EQUAL, Icon = "fa fa-check", TextColor = "#2eb85c" },
new ColumnConditionModel { Value = "false", Operator = OperatorEnum.EQUAL, Icon = "fa fa-times", TextColor = "#e55353" }
}},
new ColumnModel { Title = Localize("ProjectMemberGrid.CanReOpen").Text, DataColumn = "CanReOpen", Conditions = new List<ColumnConditionModel>{
new ColumnConditionModel { Value = "true", Operator = OperatorEnum.EQUAL, Icon = "fa fa-check", TextColor = "#2eb85c" },
new ColumnConditionModel { Value = "false", Operator = OperatorEnum.EQUAL, Icon = "fa fa-times", TextColor = "#e55353" }
Expand Down
8 changes: 8 additions & 0 deletions src/Presentation/Taskist.Web/Views/Project/_FormMember.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@
</label>
</div>
</div>
<div class="col-md-12">
<div class="mb-3">
<label class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" asp-for="CanDelete">
<wc-label asp-for="CanDelete" />
</label>
</div>
</div>
<div class="col-md-12">
<div class="mb-3">
<label class="form-check form-check-inline">
Expand Down