@@ -160,4 +178,4 @@
-{% endblock javascripts %}
\ No newline at end of file
+{% endblock javascripts %}
diff --git a/source/app/business/search.py b/source/app/business/search.py
index 36b294f30..1bc2e452a 100644
--- a/source/app/business/search.py
+++ b/source/app/business/search.py
@@ -20,12 +20,15 @@
from app.datamgmt.comments import search_comments
from app.datamgmt.case.case_notes_db import search_notes
from app.datamgmt.case.case_iocs_db import search_iocs
-
+from app.datamgmt.case.case_db import search_case_summary
def search(search_type, search_value):
track_activity(f'started a global search for {search_value} on {search_type}')
files = []
+ if search_type == 'case_summary':
+ files = search_case_summary(search_value)
+
if search_type == 'ioc':
files = search_iocs(search_value)
diff --git a/source/app/datamgmt/case/case_db.py b/source/app/datamgmt/case/case_db.py
index b830c1dd6..1ed152939 100644
--- a/source/app/datamgmt/case/case_db.py
+++ b/source/app/datamgmt/case/case_db.py
@@ -20,6 +20,7 @@
import binascii
from sqlalchemy import and_
+from sqlalchemy import or_
from sqlalchemy import exists
from sqlalchemy import select
@@ -53,6 +54,31 @@ def get_first_case_with_customer(customer_identifier: int) -> Optional[Cases]:
).first()
return case
+def search_case_summary(search_value):
+ results = Cases.query.with_entities(
+ Cases.case_id.label("case_id"),
+ Cases.name.label("case_name"),
+ Cases.description.label("case_description"),
+ Client.name.label("customer_name")
+ ).join(
+ Cases.client
+ ).filter(
+ or_(
+ Cases.name.ilike(f"%{search_value}%"),
+ Cases.description.ilike(f"%{search_value}%"),
+ Client.name.ilike(f"%{search_value}%")
+ )
+ ).all()
+
+ return [
+ {
+ "case_id": r.case_id,
+ "case_name": r.case_name,
+ "case_description": r.case_description,
+ "customer_name": r.customer_name
+ }
+ for r in results
+ ]
def get_case_summary(caseid):
case_summary = Cases.query.filter(
diff --git a/ui/src/pages/search.js b/ui/src/pages/search.js
index 40a797bc0..e8f209bda 100644
--- a/ui/src/pages/search.js
+++ b/ui/src/pages/search.js
@@ -8,6 +8,52 @@ $('#search_value').keypress(function(event){
}
});
+Table_case_summary = $("#case_summary_table").DataTable({
+ dom: 'Bfrtip',
+ aaData: [],
+ aoColumns: [
+ {
+ "data": "case_name",
+ "render": function (data, type, row, meta) {
+ if (type === 'display') {
+ let a_anchor = $('
');
+ a_anchor.attr('href', 'case?cid=' + row["case_id"]);
+ a_anchor.attr('target', '_blank');
+ a_anchor.text(data);
+ return a_anchor[0].outerHTML;
+ }
+ return data;
+ }
+ },
+ {
+ "data": "case_description",
+ "render": function (data, type, row, meta) {
+ if (type === 'display') {
+ return data ? ret_obj_dt_description(data) : "No summary available";
+ }
+ return data;
+ }
+ },
+ {
+ "data": "customer_name",
+ "render": function (data, type, row, meta) {
+ if (type === 'display') { data = sanitizeHTML(data || ""); }
+ return data;
+ }
+ }
+ ],
+ filter: true,
+ info: true,
+ ordering: true,
+ processing: true,
+ retrieve: true,
+ buttons: [
+ { "extend": 'csvHtml5', "text": 'Export', "className": 'btn btn-primary btn-border btn-round btn-sm float-left mr-4 mt-2' },
+ { "extend": 'copyHtml5', "text": 'Copy', "className": 'btn btn-primary btn-border btn-round btn-sm float-left mr-4 mt-2' },
+ ]
+});
+$("#case_summary_table").css("font-size", 12);
+
Table_1 = $("#file_search_table_1").DataTable({
dom: 'Bfrtip',
@@ -159,6 +205,11 @@ function search() {
$('.popover').popover('hide');
$(e.target).popover('toggle');
});
+ } else if (val == "case_summary") {
+ Table_case_summary.clear();
+ Table_case_summary.rows.add(data.data);
+ Table_case_summary.columns.adjust().draw();
+ $('#search_table_wrapper_4').show();
} else if (val == "notes") {
for (e in data.data) {
let li_anchor = $('
');