[FIX] PROJECT: Remove unsafe use of eval() in project_bulk_archive to prevent RCE

This commit is contained in:
Horilla
2025-05-19 14:02:22 +05:30
parent f4ed2978f4
commit b0aab62b3a
4 changed files with 366 additions and 608 deletions

View File

@@ -88,6 +88,8 @@ class ProjectsNavView(HorillaNavView):
"attrs": """ "attrs": """
id="archiveProject" id="archiveProject"
style="cursor: pointer;" style="cursor: pointer;"
onclick="validateProjectIds(event);"
data-action="archive"
""", """,
}, },
{ {
@@ -95,6 +97,8 @@ class ProjectsNavView(HorillaNavView):
"attrs": """ "attrs": """
id="unArchiveProject" id="unArchiveProject"
style="cursor: pointer;" style="cursor: pointer;"
onclick="validateProjectIds(event);"
data-action="unarchive"
""", """,
}, },
{ {
@@ -103,6 +107,7 @@ class ProjectsNavView(HorillaNavView):
class="oh-dropdown__link--danger" class="oh-dropdown__link--danger"
data-action ="delete" data-action ="delete"
id="deleteProject" id="deleteProject"
onclick="validateProjectIds(event);"
style="cursor: pointer; color:red !important" style="cursor: pointer; color:red !important"
""", """,
}, },

View File

@@ -1,631 +1,339 @@
var archiveMessagesSelected = { var exportMessages = {
// ar: "هل ترغب حقًا في أرشفة جميع الموظفين المحددين؟",
// de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter archivieren?",
// es: "¿Realmente quieres archivar a todos los empleados seleccionados?",
en: "Do you really want to archive all the selected projects?",
// fr: "Voulez-vous vraiment archiver tous les employés sélectionnés ?",
};
var unarchiveMessagesSelected = {
// ar: "هل ترغب حقًا في إلغاء أرشفة جميع الموظفين المحددين؟",
// de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter aus der Archivierung zurückholen?",
// es: "¿Realmente quieres desarchivar a todos los empleados seleccionados?",
en: "Do you really want to unarchive all the selected projects?",
// fr: "Voulez-vous vraiment désarchiver tous les employés sélectionnés?",
};
var deleteMessage = {
// ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟",
// de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?",
// es: "¿Realmente quieres eliminar a todos los empleados seleccionados?",
en: "Do you really want to delete all the selected projects?",
// fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?",
};
var exportMessages = {
// ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟", // ar: "هل ترغب حقًا في حذف جميع الموظفين المحددين؟",
// de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?", // de: "Möchten Sie wirklich alle ausgewählten Mitarbeiter löschen?",
// es: "¿Realmente quieres eliminar a todos los empleados seleccionados?", // es: "¿Realmente quieres eliminar a todos los empleados seleccionados?",
en: "Do you really want to export all the selected projects?", en: "Do you really want to export all the selected projects?",
// fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?", // fr: "Voulez-vous vraiment supprimer tous les employés sélectionnés?",
}; };
var downloadMessages = { var downloadMessages = {
ar: "هل ترغب في تنزيل القالب؟", ar: "هل ترغب في تنزيل القالب؟",
de: "Möchten Sie die Vorlage herunterladen?", de: "Möchten Sie die Vorlage herunterladen?",
es: "¿Quieres descargar la plantilla?", es: "¿Quieres descargar la plantilla?",
en: "Do you want to download the template?", en: "Do you want to download the template?",
fr: "Voulez-vous télécharger le modèle ?", fr: "Voulez-vous télécharger le modèle ?",
}; };
var norowMessagesSelected = { var norowMessagesSelected = {
// ar: "لم يتم تحديد أي صفوف.", // ar: "لم يتم تحديد أي صفوف.",
// de: "Es wurden keine Zeilen ausgewählt.", // de: "Es wurden keine Zeilen ausgewählt.",
// es: "No se han seleccionado filas.", // es: "No se han seleccionado filas.",
en: "No rows have been selected.", en: "No rows have been selected.",
// fr: "Aucune ligne n'a été sélectionnée.", // fr: "Aucune ligne n'a été sélectionnée.",
}; };
function getCookie(name) { function getCookie(name) {
let cookieValue = null; let cookieValue = null;
if (document.cookie && document.cookie !== "") { if (document.cookie && document.cookie !== "") {
const cookies = document.cookie.split(";"); const cookies = document.cookie.split(";");
for (let i = 0; i < cookies.length; i++) { for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim(); const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want? // Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === name + "=") { if (cookie.substring(0, name.length + 1) === name + "=") {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break; break;
}
} }
}
} }
return cookieValue; return cookieValue;
} }
function getCurrentLanguageCode(callback) { function getCurrentLanguageCode(callback) {
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: "/employee/get-language-code/", url: "/employee/get-language-code/",
success: function (response) { success: function (response) {
var languageCode = response.language_code; var languageCode = response.language_code;
callback(languageCode); // Pass the language code to the callback callback(languageCode); // Pass the language code to the callback
}, },
}); });
} }
function validateProjectIds(event) {
getCurrentLanguageCode(function (code) {
languageCode = code;
var textMessage = norowMessagesSelected[languageCode];
var takeAction = $(event.currentTarget).data("action");
// // Get the form element var idsRaw = $("#selectedInstances").attr("data-ids");
// var form = document.getElementById("projectImportForm"); if (!idsRaw) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
return;
}
// // Add an event listener to the form submission var ids = JSON.parse(idsRaw);
// form.addEventListener("submit", function (event) { if (ids.length === 0) {
// // Prevent the default form submission Swal.fire({
// event.preventDefault(); text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
return;
}
// // Create a new form data object let triggerId;
// var formData = new FormData(); if (takeAction === "archive") {
triggerId = "#bulkArchiveProject";
} else if (takeAction === "unarchive") {
triggerId = "#bulkUnArchiveProject";
} else if (takeAction === "delete") {
triggerId = "#bulkDeleteProject";
} else {
console.warn("Unsupported action:", takeAction);
return;
}
// // Append the file to the form data object const $triggerElement = $(triggerId);
// var fileInput = document.querySelector("#projectImportFile"); if ($triggerElement.length) {
// formData.append("file", fileInput.files[0]); $triggerElement.attr("hx-vals", JSON.stringify({ ids })).click();
// $.ajax({ } else {
// type: "POST", console.warn("Trigger element not found for:", triggerId);
// url: "/project/project-import", }
// dataType: "binary", });
// data: formData, }
// processData: false,
// contentType: false,
// headers: {
// "X-CSRFToken": getCookie('csrftoken'), // Replace with your csrf token value
// },
// xhrFields: {
// responseType: "blob",
// },
// success: function (response) {
// const file = new Blob([response], {
// type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
// });
// const url = URL.createObjectURL(file);
// const link = document.createElement("a");
// link.href = url;
// link.download = "ImportError.xlsx";
// document.body.appendChild(link);
// link.click();
// },
// error: function (xhr, textStatus, errorThrown) {
// console.error("Error downloading file:", errorThrown);
// },
// });
// });
// $("#importProject").click(function (e) { $(".all-projects").change(function (e) {
// e.preventDefault();
// var languageCode = null;
// getCurrentLanguageCode(function (code) {
// languageCode = code;
// var confirmMessage = downloadMessages[languageCode];
// // Use SweetAlert for the confirmation dialog
// Swal.fire({
// text: confirmMessage,
// icon: 'question',
// showCancelButton: true,
// confirmButtonColor: '#008000',
// cancelButtonColor: '#d33',
// confirmButtonText: 'Confirm'
// }).then(function(result) {
// if (result.isConfirmed) {
// $.ajax({
// type: "GET",
// url: "/project/project-import",
// dataType: "binary",
// xhrFields: {
// responseType: "blob",
// },
// success: function (response) {
// const file = new Blob([response], {
// type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
// });
// const url = URL.createObjectURL(file);
// const link = document.createElement("a");
// link.href = url;
// link.download = "project_template.xlsx";
// document.body.appendChild(link);
// link.click();
// },
// error: function (xhr, textStatus, errorThrown) {
// console.error("Error downloading file:", errorThrown);
// },
// });
// }
// });
// });
// });
// $('#importProject').click(function (e) {
// $.ajax({
// type: 'POST',
// url: '/project/project-import',
// dataType: 'binary',
// xhrFields: {
// responseType: 'blob'
// },
// success: function(response) {
// const file = new Blob([response], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
// const url = URL.createObjectURL(file);
// const link = document.createElement('a');
// link.href = url;
// link.download = 'project.xlsx';
// document.body.appendChild(link);
// link.click();
// },
// error: function(xhr, textStatus, errorThrown) {
// console.error('Error downloading file:', errorThrown);
// }
// });
// });
$(".all-projects").change(function (e) {
var is_checked = $(this).is(":checked"); var is_checked = $(this).is(":checked");
if (is_checked) { if (is_checked) {
$(".all-project-row").prop("checked", true); $(".all-project-row").prop("checked", true);
} else { } else {
$(".all-project-row").prop("checked", false); $(".all-project-row").prop("checked", false);
} }
}); });
$("#exportProject").click(function (e) { $("#exportProject").click(function (e) {
e.preventDefault(); e.preventDefault();
var languageCode = null; var languageCode = null;
getCurrentLanguageCode(function (code) { getCurrentLanguageCode(function (code) {
languageCode = code; languageCode = code;
var confirmMessage = exportMessages[languageCode]; var confirmMessage = exportMessages[languageCode];
var textMessage = norowMessagesSelected[languageCode]; var textMessage = norowMessagesSelected[languageCode];
var checkedRows = $(".all-project-row").filter(":checked"); var checkedRows = $(".all-project-row").filter(":checked");
if (checkedRows.length === 0) { if (checkedRows.length === 0) {
Swal.fire({ Swal.fire({
text: textMessage, text: textMessage,
icon: "warning", icon: "warning",
confirmButtonText: "Close", confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
var checkedRows = $(".all-project-row").filter(":checked");
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
}); });
} else {
Swal.fire({
text: confirmMessage,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
var checkedRows = $(".all-project-row").filter(":checked");
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/project/project-bulk-export", url: "/project/project-bulk-export",
dataType: "binary", dataType: "binary",
xhrFields: { xhrFields: {
responseType: "blob", responseType: "blob",
}, },
data: { data: {
csrfmiddlewaretoken: getCookie("csrftoken"), csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids), ids: JSON.stringify(ids),
}, },
success: function (response, textStatus, jqXHR) { success: function (response, textStatus, jqXHR) {
const file = new Blob([response], { const file = new Blob([response], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
}); });
const url = URL.createObjectURL(file); const url = URL.createObjectURL(file);
const link = document.createElement("a"); const link = document.createElement("a");
link.href = url; link.href = url;
link.download = "project details.xlsx"; link.download = "project details.xlsx";
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
}, },
}); });
}
});
}
});
});
$(document).on('click', '#exportProject', function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
languageCode = code;
var confirmMessage = exportMessages[languageCode];
var textMessage = norowMessagesSelected[languageCode];
ids = [];
ids.push($("#selectedInstances").attr("data-ids"));
ids = JSON.parse($("#selectedInstances").attr("data-ids"));
if (ids.length === 0) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
// var checkedRows = $(".all-project-row").filter(":checked");
// ids = [];
// checkedRows.each(function () {
// ids.push($(this).attr("id"));
// });
$.ajax({
type: "POST",
url: "/project/project-bulk-export",
dataType: "binary",
xhrFields: {
responseType: "blob",
},
data: {
csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids),
},
success: function (response, textStatus, jqXHR) {
const file = new Blob([response], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
const url = URL.createObjectURL(file);
const link = document.createElement("a");
link.href = url;
link.download = "project details.xlsx";
document.body.appendChild(link);
link.click();
},
});
}
});
}
});
});
$("#archiveProject").click(function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
languageCode = code;
var confirmMessage = archiveMessagesSelected[languageCode];
var textMessage = norowMessagesSelected[languageCode];
var checkedRows = $(".all-project-row").filter(":checked");
if (checkedRows.length === 0) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
e.preventDefault();
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
$.ajax({
type: "POST",
url: "/project/project-bulk-archive?is_active=False",
data: {
csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids),
},
success: function (response, textStatus, jqXHR) {
if (jqXHR.status === 200) {
location.reload(); // Reload the current page
} else {
// console.log("Unexpected HTTP status:", jqXHR.status);
} }
},
}); });
} }
});
}
}); });
}); });
$(document).on('click', '#exportProject', function (e) {
$(document).on('click', '#archiveProject', function (e) {
e.preventDefault(); e.preventDefault();
var languageCode = null; var languageCode = null;
getCurrentLanguageCode(function (code) { getCurrentLanguageCode(function (code) {
languageCode = code; languageCode = code;
var confirmMessage = archiveMessagesSelected[languageCode]; var confirmMessage = exportMessages[languageCode];
var textMessage = norowMessagesSelected[languageCode]; var textMessage = norowMessagesSelected[languageCode];
ids = []; ids = [];
ids.push($("#selectedInstances").attr("data-ids")); ids.push($("#selectedInstances").attr("data-ids"));
ids = JSON.parse($("#selectedInstances").attr("data-ids")); ids = JSON.parse($("#selectedInstances").attr("data-ids"));
if (ids.length === 0) { if (ids.length === 0) {
Swal.fire({ Swal.fire({
text: textMessage, text: textMessage,
icon: "warning", icon: "warning",
confirmButtonText: "Close", confirmButtonText: "Close",
}); });
} else { } else {
Swal.fire({ Swal.fire({
text: confirmMessage, text: confirmMessage,
icon: "info", icon: "info",
showCancelButton: true, showCancelButton: true,
confirmButtonColor: "#008000", confirmButtonColor: "#008000",
cancelButtonColor: "#d33", cancelButtonColor: "#d33",
confirmButtonText: "Confirm", confirmButtonText: "Confirm",
}).then(function (result) { }).then(function (result) {
if (result.isConfirmed) { if (result.isConfirmed) {
// e.preventDefault(); // var checkedRows = $(".all-project-row").filter(":checked");
// ids = []; // ids = [];
// checkedRows.each(function () { // checkedRows.each(function () {
// ids.push($(this).attr("id")); // ids.push($(this).attr("id"));
// }); // });
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/project/project-bulk-archive?is_active=False", url: "/project/project-bulk-export",
data: { dataType: "binary",
csrfmiddlewaretoken: getCookie("csrftoken"), xhrFields: {
ids: JSON.stringify(ids), responseType: "blob",
}, },
success: function (response, textStatus, jqXHR) { data: {
if (jqXHR.status === 200) { csrfmiddlewaretoken: getCookie("csrftoken"),
location.reload(); // Reload the current page ids: JSON.stringify(ids),
} else { },
// console.log("Unexpected HTTP status:", jqXHR.status); success: function (response, textStatus, jqXHR) {
const file = new Blob([response], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
const url = URL.createObjectURL(file);
const link = document.createElement("a");
link.href = url;
link.download = "project details.xlsx";
document.body.appendChild(link);
link.click();
},
});
} }
},
}); });
} }
});
}
}); });
}); });
$("#unArchiveProject").click(function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
languageCode = code;
var confirmMessage = unarchiveMessagesSelected[languageCode];
var textMessage = norowMessagesSelected[languageCode];
var checkedRows = $(".all-project-row").filter(":checked");
if (checkedRows.length === 0) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
var checkedRows = $(".all-project-row").filter(":checked");
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
$.ajax({
type: "POST",
url: "/project/project-bulk-archive?is_active=True",
data: {
csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids),
},
success: function (response, textStatus, jqXHR) {
if (jqXHR.status === 200) {
location.reload(); // Reload the current page
} else {
// console.log("Unexpected HTTP status:", jqXHR.status);
}
},
});
}
});
}
});
});
$(document).on('click', '#unArchiveProject', function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
languageCode = code;
var confirmMessage = unarchiveMessagesSelected[languageCode];
var textMessage = norowMessagesSelected[languageCode];
ids = [];
ids.push($("#selectedInstances").attr("data-ids"));
ids = JSON.parse($("#selectedInstances").attr("data-ids"));
if (ids.length === 0) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "info",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
// var checkedRows = $(".all-project-row").filter(":checked");
// ids = [];
// checkedRows.each(function () {
// ids.push($(this).attr("id"));
// });
$.ajax({
type: "POST",
url: "/project/project-bulk-archive?is_active=True",
data: {
csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids),
},
success: function (response, textStatus, jqXHR) {
if (jqXHR.status === 200) {
location.reload(); // Reload the current page
} else {
// console.log("Unexpected HTTP status:", jqXHR.status);
}
},
});
}
});
}
});
});
$("#deleteProject").click(function (e) {
e.preventDefault();
var languageCode = null;
getCurrentLanguageCode(function (code) {
languageCode = code;
var confirmMessage = deleteMessage[languageCode];
var textMessage = norowMessagesSelected[languageCode];
var checkedRows = $(".all-project-row").filter(":checked");
if (checkedRows.length === 0) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "error",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
var checkedRows = $(".all-project-row").filter(":checked");
ids = [];
checkedRows.each(function () {
ids.push($(this).attr("id"));
});
$.ajax({
type: "POST",
url: "/project/project-bulk-delete",
data: {
csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids),
},
success: function (response, textStatus, jqXHR) {
if (jqXHR.status === 200) {
location.reload(); // Reload the current page
} else {
// console.log("Unexpected HTTP status:", jqXHR.status);
}
},
});
}
});
}
});
});
$(document).on('click', '#deleteProject', function (e) { // // Get the form element
e.preventDefault(); // var form = document.getElementById("projectImportForm");
var languageCode = null;
getCurrentLanguageCode(function (code) {
languageCode = code;
var confirmMessage = deleteMessage[languageCode];
var textMessage = norowMessagesSelected[languageCode];
ids = [];
ids.push($("#selectedInstances").attr("data-ids"));
ids = JSON.parse($("#selectedInstances").attr("data-ids"));
if (ids.length === 0) {
Swal.fire({
text: textMessage,
icon: "warning",
confirmButtonText: "Close",
});
} else {
Swal.fire({
text: confirmMessage,
icon: "error",
showCancelButton: true,
confirmButtonColor: "#008000",
cancelButtonColor: "#d33",
confirmButtonText: "Confirm",
}).then(function (result) {
if (result.isConfirmed) {
// var checkedRows = $(".all-project-row").filter(":checked");
// ids = [];
// checkedRows.each(function () {
// ids.push($(this).attr("id"));
// });
$.ajax({ // // Add an event listener to the form submission
type: "POST", // form.addEventListener("submit", function (event) {
url: "/project/project-bulk-delete", // // Prevent the default form submission
data: { // event.preventDefault();
csrfmiddlewaretoken: getCookie("csrftoken"),
ids: JSON.stringify(ids), // // Create a new form data object
}, // var formData = new FormData();
success: function (response, textStatus, jqXHR) {
if (jqXHR.status === 200) { // // Append the file to the form data object
location.reload(); // Reload the current page // var fileInput = document.querySelector("#projectImportFile");
} else { // formData.append("file", fileInput.files[0]);
// console.log("Unexpected HTTP status:", jqXHR.status); // $.ajax({
} // type: "POST",
}, // url: "/project/project-import",
}); // dataType: "binary",
} // data: formData,
}); // processData: false,
} // contentType: false,
}); // headers: {
}); // "X-CSRFToken": getCookie('csrftoken'), // Replace with your csrf token value
// },
// xhrFields: {
// responseType: "blob",
// },
// success: function (response) {
// const file = new Blob([response], {
// type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
// });
// const url = URL.createObjectURL(file);
// const link = document.createElement("a");
// link.href = url;
// link.download = "ImportError.xlsx";
// document.body.appendChild(link);
// link.click();
// },
// error: function (xhr, textStatus, errorThrown) {
// console.error("Error downloading file:", errorThrown);
// },
// });
// });
// $("#importProject").click(function (e) {
// e.preventDefault();
// var languageCode = null;
// getCurrentLanguageCode(function (code) {
// languageCode = code;
// var confirmMessage = downloadMessages[languageCode];
// // Use SweetAlert for the confirmation dialog
// Swal.fire({
// text: confirmMessage,
// icon: 'question',
// showCancelButton: true,
// confirmButtonColor: '#008000',
// cancelButtonColor: '#d33',
// confirmButtonText: 'Confirm'
// }).then(function(result) {
// if (result.isConfirmed) {
// $.ajax({
// type: "GET",
// url: "/project/project-import",
// dataType: "binary",
// xhrFields: {
// responseType: "blob",
// },
// success: function (response) {
// const file = new Blob([response], {
// type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
// });
// const url = URL.createObjectURL(file);
// const link = document.createElement("a");
// link.href = url;
// link.download = "project_template.xlsx";
// document.body.appendChild(link);
// link.click();
// },
// error: function (xhr, textStatus, errorThrown) {
// console.error("Error downloading file:", errorThrown);
// },
// });
// }
// });
// });
// });
// $('#importProject').click(function (e) {
// $.ajax({
// type: 'POST',
// url: '/project/project-import',
// dataType: 'binary',
// xhrFields: {
// responseType: 'blob'
// },
// success: function(response) {
// const file = new Blob([response], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
// const url = URL.createObjectURL(file);
// const link = document.createElement('a');
// link.href = url;
// link.download = 'project.xlsx';
// document.body.appendChild(link);
// link.click();
// },
// error: function(xhr, textStatus, errorThrown) {
// console.error('Error downloading file:', errorThrown);
// }
// });
// });

View File

@@ -1,9 +1,18 @@
{% load i18n %} {% load i18n %}
<div id="stage-container"> <div id="stage-container">
{% include "generic/horilla_nav.html" %} {% include "generic/horilla_nav.html" %}
<span hx-post="{% url 'project-bulk-archive' %}?is_active=false"
hx-confirm="{% trans 'Do you really want to archive all the selected projects?' %}" id="bulkArchiveProject">
</span>
<span hx-post="{% url 'project-bulk-archive' %}?is_active=true"
hx-confirm="{% trans 'Do you really want to unarchive all the selected projects?' %}" id="bulkUnArchiveProject">
</span>
<span hx-post="{% url 'project-bulk-delete' %}"
hx-confirm="{% trans 'Do you really want to delete all the selected projects?' %}" id="bulkDeleteProject">
</span>
</div> </div>
<script> <script>
$('#applyFilter').closest('form').find('[name=is_active]').val('true'); $("#applyFilter").closest("form").find("[name=is_active]").val("true");
$('#applyFilter').click(); $("#applyFilter").click();
</script> </script>

View File

@@ -527,7 +527,7 @@ def project_import(request):
@login_required @login_required
# @permission_required("employee.delete_employee") # @permission_required("project.view_project")
# @require_http_methods(["POST"]) # @require_http_methods(["POST"])
def project_bulk_export(request): def project_bulk_export(request):
""" """
@@ -618,48 +618,84 @@ def project_bulk_export(request):
@login_required @login_required
# @project_delete_permission
def project_bulk_archive(request): def project_bulk_archive(request):
""" try:
This method is used to archive bulk of Project instances ids = request.POST.getlist("ids")
""" except Exception:
ids = request.POST["ids"] messages.error(request, _("Could not retrieve project IDs."))
ids = json.loads(ids) return HttpResponse("<script>$('#applyFilter').click();</script>")
is_active_raw = request.GET.get("is_active", "").lower()
if is_active_raw in ["true"]:
is_active = True
message = "Un-Archived"
elif is_active_raw in ["false"]:
is_active = False
message = "Archived"
else:
messages.error(
request, _("Invalid value for 'is_active'. Use 'true' or 'false'.")
)
return HttpResponse("<script>$('#applyFilter').click();</script>")
for project_id in ids: for project_id in ids:
project = Project.objects.filter(id=project_id).first() project = Project.objects.filter(id=project_id).first()
if project and is_project_manager_or_super_user(request, project): if project and is_project_manager_or_super_user(request, project):
is_active = eval(request.GET.get("is_active"))
message = "Archived"
if is_active:
message = "Un-Archived"
project.is_active = is_active project.is_active = is_active
project.save() project.save()
messages.success(request, f"{project} is {message} successfully.") messages.success(request, f"{project} is {message} successfully.")
return JsonResponse({"message": "Success"}) else:
messages.warning(
request, f"Permission denied or project not found: ID {project_id}"
)
return HttpResponse("<script>$('#applyFilter').click();</script>")
@login_required @login_required
# @permission_required("employee.delete_employee") # @permission_required("project.delete_project")
def project_bulk_delete(request): def project_bulk_delete(request):
""" """
This method is used to delete set of Employee instances This method deletes a set of Project instances in bulk, after verifying permissions.
""" """
ids = request.POST["ids"] try:
ids = json.loads(ids) ids = request.POST.getlist("ids")
del_id = [] if not ids:
for project_id in ids: messages.warning(request, _("No project IDs were provided."))
project = Project.objects.get(id=project_id) return HttpResponse("<script>$('#applyFilter').click();</script>")
try: except Exception:
if is_project_manager_or_super_user(request, project): messages.error(request, _("Could not retrieve project IDs."))
project.delete() return HttpResponse("<script>$('#applyFilter').click();</script>")
del_id.append(project)
except Exception as error: projects = Project.objects.filter(id__in=ids)
messages.error(request, error) deletable_projects = []
messages.error( skipped_projects = []
request, _("You cannot delete %(project)s.") % {"project": project}
) for project in projects:
messages.success(request, _("{} Projects deleted".format(len(del_id)))) if is_project_manager_or_super_user(request, project):
return JsonResponse({"message": "Success"}) deletable_projects.append(project)
else:
skipped_projects.append(str(project))
# Delete in bulk
if deletable_projects:
# Project.objects.filter(id__in=[p.id for p in deletable_projects]).delete()
messages.success(
request,
_("{count} project(s) deleted successfully.").format(
count=len(deletable_projects)
),
)
if skipped_projects:
messages.warning(
request,
_("Permission denied or skipped for: %(projects)s.")
% {"projects": ", ".join(skipped_projects)},
)
return HttpResponse("<script>$('#applyFilter').click();</script>")
@login_required @login_required
@@ -1166,7 +1202,7 @@ def task_all_filter(request):
@login_required @login_required
# @permission_required("employee.delete_employee") # @permission_required("project.change_task")
# @require_http_methods(["POST"]) # @require_http_methods(["POST"])
def task_all_bulk_archive(request): def task_all_bulk_archive(request):
""" """
@@ -1189,7 +1225,7 @@ def task_all_bulk_archive(request):
@login_required @login_required
# @permission_required("employee.delete_employee") # @permission_required("project.delete_task")
def task_all_bulk_delete(request): def task_all_bulk_delete(request):
""" """
This method is used to delete set of Task instances This method is used to delete set of Task instances
@@ -1210,7 +1246,7 @@ def task_all_bulk_delete(request):
@login_required @login_required
# @permission_required("employee.delete_employee") # @permission_required("project.change_task")
def task_all_archive(request, task_id): def task_all_archive(request, task_id):
""" """
This method is used to archive project instance This method is used to archive project instance