This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Access Control {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="/static/assets/css/suggestags.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/bootstrap-multiselect.min.css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="page-inner">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-heading collapsed" href="#collapse_user_mgmt" title="Click to unfold" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_user_mgmt">
|
||||
<span class="accicon float-left mr-3"><i class="fas fa-angle-right rotate-icon"></i></span>
|
||||
<div class="card-title">Users</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_users(true);">Refresh</button>
|
||||
<a class="btn btn-sm btn-dark float-right ml-2" href="access-control/audit/users?cid={{ session['current_case'].case_id }}">Audit users</a>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="add_user();">Add user</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body collapse" id="collapse_user_mgmt">
|
||||
<div class="table-responsive" id="users_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="table_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="users_table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>#ID</th>
|
||||
<th>Name</th>
|
||||
<th>Login Name</th>
|
||||
<th>Email</th>
|
||||
<th>Active</th>
|
||||
<th>Service Account</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>#ID</th>
|
||||
<th>Name</th>
|
||||
<th>Login Name</th>
|
||||
<th>Email</th>
|
||||
<th>Active</th>
|
||||
<th>Service Account</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-heading collapsed" href="#collapse_groups_mgmt" title="Click to unfold" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_groups_mgmt">
|
||||
<span class="accicon float-left mr-3"><i class="fas fa-angle-right rotate-icon"></i></span>
|
||||
<div class="card-title">Groups</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_groups(true);">Refresh</button>
|
||||
<button class="btn btn-sm btn-dark float-right" onclick="add_group();">Add group</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body collapse" id="collapse_groups_mgmt">
|
||||
<div class="table-responsive" id="groups_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="groups_table_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="groups_table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>#ID</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Permissions</th>
|
||||
<th>#Members</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>#ID</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Permissions</th>
|
||||
<th>#Members</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="modal" tabindex="-1" role="dialog" id="modal_access_control" data-backdrop="true">
|
||||
</div>
|
||||
<div class="modal bg-shadow-gradient" tabindex="-1" role="dialog" id="modal_ac_additional" data-backdrop="true">
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="/static/assets/js/plugin/select/bootstrap-multiselect.min.js"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/dataTables.select.min.js"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/dataTables.contextualActions.min.js"></script>
|
||||
|
||||
<script src="/static/assets/js/iris/manage.users.js"></script>
|
||||
<script src="/static/assets/js/iris/manage.cases.common.js"></script>
|
||||
<script src="/static/assets/js/iris/manage.groups.js"></script>
|
||||
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,58 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Access Control {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="/static/assets/css/suggestags.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/bootstrap-select.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/select2.css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="page-inner">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<a class="mb-2 ml-1 text-dark" href="/manage/access-control?cid={{ session['current_case'].case_id }}"><i class="fa-solid fa-arrow-left"></i> Back</a>
|
||||
<div class="card mt-2">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-heading">
|
||||
<div class="card-title">Users audit</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body" id="">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="input-group mb-3">
|
||||
<select id="users_audit_select" name="users_audit_select" class="form-control ml-12"
|
||||
tabindex="-1" style="width: 50%"></select>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-outline-success" id="get_user_audit_btn"
|
||||
onclick="get_user_audit_page();">Audit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="user_audit_content">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="/static/assets/js/plugin/datatables/dataTables.select.min.js"></script>
|
||||
<script src="/static/assets/js/iris/manage.audit.users.js"></script>
|
||||
<script src="/static/assets/js/iris/datatablesUtils.js"></script>
|
||||
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,292 @@
|
||||
<div class="modal-xl modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_access_control_content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-2 mr-4">{% if not group.group_id %}Add Group {% else %} Edit {{ group.group_name }} {% endif %}</h4>
|
||||
<div class="row text-center mr-4">
|
||||
{% if group.group_id %}
|
||||
<ul class="nav nav-pills nav-default mr-4" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active show" data-toggle="pill" href="#group_details_tab" role="tab" aria-controls="group_details_tab" aria-selected="false">Info</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link" data-toggle="pill" href="#group_members_tab" role="tab" aria-controls="group_members_tab" aria-selected="false">Members</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link" data-toggle="pill" href="#group_cac_tab" role="tab" aria-controls="group_cac_tab" aria-selected="false">Cases access</a>
|
||||
</li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row text-right">
|
||||
<button type="button" class="pull-right btn bg-transparent" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div role="tabpanel">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="group_details_tab">
|
||||
<div class="container col-md-12" >
|
||||
<form method="post" action="" id="form_new_group">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
{% if not group.group_id %}
|
||||
<p class="ml-3"><i class="fa-solid fa-circle-info mr-2"></i>Members can be added once the group is created.</p>
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<label for="group_name" class="mr-4">Group name *
|
||||
</label>
|
||||
{{ form.group_name(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="group_description" class="placeholder">Description *</label>
|
||||
{{ form.group_description(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group" data-select2-id="7">
|
||||
<label>Permissions *</label>
|
||||
<div class="select2-input ml-12" data-select2-id="6">
|
||||
<select id="group_permissions" name="group_permissions" class="form-control select2-hidden-accessible ml-12" multiple="" data-select2-id="group_permissions" tabindex="-1" aria-hidden="true" style="width: 100%">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if group.group_id %}
|
||||
<button type="button" class="btn btn-danger mt-5"
|
||||
onclick="delete_group('{{ group.group_id }}');">Delete</button>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_group">Update</button>
|
||||
{% else %}
|
||||
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_group">Save</button>
|
||||
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="group_members_tab">
|
||||
<div class="container col-md-12" >
|
||||
<div class="row d-flex">
|
||||
<div class="col pull-right">
|
||||
<button class="btn btn-dark btn-sm pull-right" onclick="refresh_group_members({{ group.group_id }});">
|
||||
<span class="menu-title">Refresh</span>
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm pull-right mr-2" onclick="add_members_to_group({{ group.group_id }});">
|
||||
<span class="menu-title">Manage</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<table class="table display table-bordered table-striped table-hover responsive" width="100%" cellspacing="0" id="group_members_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User ID</th>
|
||||
<th>User login</th>
|
||||
<th>User display name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>User ID</th>
|
||||
<th>User login</th>
|
||||
<th>User display name</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="group_cac_tab">
|
||||
<div class="container col-md-12" >
|
||||
<div class="row d-flex mb-2">
|
||||
<div class="col">
|
||||
{% if group.group_auto_follow %}
|
||||
<b><i class="fa fa-triangle-exclamation text-warning mr-2"></i>This group is set to automatically include all new cases.</b>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col pull-right">
|
||||
<button class="btn btn-dark btn-sm pull-right" onclick="refresh_group_cac({{ group.group_id }});">
|
||||
<span class="menu-title">Refresh</span>
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm pull-right mr-2" onclick="manage_group_cac({{ group.group_id }});">
|
||||
<span class="menu-title" id="manage_group_cac_button">Set case access</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<table class="table display table-bordered table-striped table-hover responsive" width="100%" cellspacing="0" id="group_cac_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Case ID</th>
|
||||
<th>Case Name</th>
|
||||
<th>Access</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Case ID</th>
|
||||
<th>Case Name</th>
|
||||
<th>Access</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
var data = [
|
||||
{% for e in all_perms %}
|
||||
{
|
||||
value: {{ e.value }},
|
||||
label: "{{ e.name }}"
|
||||
}
|
||||
{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
];
|
||||
|
||||
$('#group_permissions').multiselect({
|
||||
buttonWidth: 400,
|
||||
nonSelectedText: 'Select permissions',
|
||||
includeSelectAllOption: true,
|
||||
enableFiltering: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
filterPlaceholder: 'Search',
|
||||
filterBehavior: 'both',
|
||||
widthSynchronizationMode: 'ifPopupIsSmaller'
|
||||
});
|
||||
|
||||
$('#group_permissions').multiselect('dataprovider', data );
|
||||
|
||||
{% if group.group_permissions_list %}
|
||||
$('#group_permissions').multiselect('select', [
|
||||
{% for perm in group.group_permissions_list %} {{ perm.value }}, {% endfor %}
|
||||
]);
|
||||
|
||||
$('#org_members').multiselect('refresh')
|
||||
|
||||
{% endif %}
|
||||
|
||||
var modal_group_table = $("#group_members_table").DataTable({
|
||||
dom: 'Blfrtip',
|
||||
aaData: [],
|
||||
aoColumns: [
|
||||
{
|
||||
"data": "id",
|
||||
"render": function ( data, type, row ) {
|
||||
return `<i class="fa-solid fa-trash-can mr-2 text-danger" style="cursor:pointer;" title="Remove from group" href="javascript:void(0)" onclick="remove_members_from_group('{{ group.group_id }}',${data})"></i>${data}`;
|
||||
},
|
||||
"className": "dt-center"
|
||||
},
|
||||
{
|
||||
"data": "user",
|
||||
"className": "dt-center",
|
||||
"render": function (data, type, row) {
|
||||
return sanitizeHTML(data);
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": "name",
|
||||
"className": "dt-center",
|
||||
"render": function (data, type, row) {
|
||||
return sanitizeHTML(data);
|
||||
}
|
||||
}
|
||||
],
|
||||
filter: true,
|
||||
info: true,
|
||||
ordering: true,
|
||||
processing: true
|
||||
});
|
||||
|
||||
{% if group.group_id %}
|
||||
modal_group_table.rows.add({{ group.group_members|tojson }});
|
||||
modal_group_table.columns.adjust().draw();
|
||||
{% endif %}
|
||||
|
||||
|
||||
var modal_group_cac_table = $("#group_cac_table").DataTable({
|
||||
dom: 'Blfrtip',
|
||||
aaData: [],
|
||||
aoColumns: [
|
||||
{
|
||||
"data": "case_id",
|
||||
"render": function ( data, type, row ) {
|
||||
return `<i class="fa-solid fa-trash-can mr-2 text-danger" style="cursor:pointer;" title="Remove access to case" href="javascript:void(0)" onclick="remove_case_access_from_group('{{ group.group_id }}',${data})"></i>${data}`;
|
||||
},
|
||||
"className": "dt-center"
|
||||
},
|
||||
{
|
||||
"data": "case_name",
|
||||
"className": "dt-center",
|
||||
"render": function (data, type, row) {
|
||||
return `<a target="_blank" rel="noopener" href="/case?cid=${row.case_id}">${sanitizeHTML(data)}</a>`;
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": "access_level_list",
|
||||
"render": function ( data, type, row ) {
|
||||
ret_data = "";
|
||||
for (acc in data) {
|
||||
ret_data += `<span class="badge ml-2 badge-light">${data[acc].name}</span>`
|
||||
}
|
||||
return ret_data;
|
||||
},
|
||||
"className": "dt-center"
|
||||
}
|
||||
],
|
||||
filter: true,
|
||||
info: true,
|
||||
ordering: true,
|
||||
processing: true,
|
||||
select: true
|
||||
});
|
||||
|
||||
var actionOptionsGroup = {
|
||||
classes: [],
|
||||
contextMenu: {
|
||||
enabled: true,
|
||||
isMulti: true,
|
||||
xoffset: -10,
|
||||
yoffset: -10,
|
||||
headerRenderer: function (rows) {
|
||||
if (rows.length > 1) {
|
||||
return rows.length + ' items selected';
|
||||
} else {
|
||||
let row = rows[0];
|
||||
return 'Quick action';
|
||||
}
|
||||
},
|
||||
},
|
||||
buttonList: {
|
||||
enabled: false,
|
||||
},
|
||||
deselectAfterAction: true,
|
||||
items: [],
|
||||
};
|
||||
|
||||
|
||||
{% if group.group_id %}
|
||||
actionOptionsGroup.items.push({
|
||||
type: 'option',
|
||||
title: 'Remove access',
|
||||
multi: true,
|
||||
iconClass: 'fas fa-trash',
|
||||
buttonClasses: ['btn', 'btn-outline-primary'],
|
||||
action: function(rows){
|
||||
remove_group_cases_from_group_table({{ group.group_id }}, rows);
|
||||
}
|
||||
});
|
||||
modal_group_cac_table.contextualActions(actionOptionsGroup);
|
||||
|
||||
current_group_cases_access_list = {{ group.group_cases_access|tojson }};
|
||||
modal_group_cac_table.rows.add(current_group_cases_access_list);
|
||||
modal_group_cac_table.columns.adjust().draw();
|
||||
{% endif %}
|
||||
</script>
|
@@ -0,0 +1,90 @@
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-2 mr-4">Set case access</h4>
|
||||
<div class="row text-right">
|
||||
<button type="button" class="pull-right btn bg-transparent" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container col-md-12" >
|
||||
<div class="row">
|
||||
<div class="form-group" data-select2-id="7">
|
||||
<label>Set cases access of group <i>{{ group.group_name }}</i> *</label>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" id="enable_auto_follow_cases" name="enable_auto_follow_cases" {% if group.group_auto_follow %}checked{% endif %}>
|
||||
<span class="form-check-sign">Apply to currents and futures cases</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<select id="group_case_access_select" name="org_case_access_select" class="form-control select2-hidden-accessible ml-12" multiple="multiple"
|
||||
tabindex="-1" aria-hidden="true" style="width: 100%">
|
||||
</select>
|
||||
<select id="group_case_ac_select" name="org_case_ac_select" class="form-control select2-hidden-accessible ml-12"
|
||||
tabindex="-1" aria-hidden="true" style="width: 100%">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="grant_case_access_to_group">Set access</button>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
var data = [];
|
||||
|
||||
$('#group_case_access_select').multiselect({
|
||||
buttonWidth: 400,
|
||||
nonSelectedText: 'Select case',
|
||||
emptyText: 'No case available to add',
|
||||
includeSelectAllOption: true,
|
||||
enableFiltering: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
filterPlaceholder: 'Search',
|
||||
filterBehavior: 'both',
|
||||
widthSynchronizationMode: 'ifPopupIsSmaller'
|
||||
});
|
||||
|
||||
$('#group_case_access_select').multiselect('dataprovider', [{% for ocs in outer_cases %}
|
||||
{ label: "{{ ocs.case_name }}", value: {{ ocs.case_id }} }, {% endfor %}]);
|
||||
|
||||
|
||||
$('#group_case_access_select').multiselect('refresh')
|
||||
|
||||
$('#group_case_ac_select').multiselect({
|
||||
nonSelectedText: 'Select access level',
|
||||
includeSelectAllOption: true,
|
||||
enableFiltering: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
filterPlaceholder: 'Search',
|
||||
filterBehavior: 'both',
|
||||
widthSynchronizationMode: 'ifPopupIsSmaller'
|
||||
});
|
||||
|
||||
$('#group_case_ac_select').multiselect('dataprovider', [{% for acc in access_levels %}
|
||||
{ label: "{{ acc.name }}", value: {{ acc.value }} }, {% endfor %}]);
|
||||
|
||||
$('#group_case_ac_select').multiselect('refresh');
|
||||
|
||||
$('#enable_auto_follow_cases').on('change', function() {
|
||||
if (this.checked) {
|
||||
$('#group_case_access_select').multiselect('disable');
|
||||
} else {
|
||||
$('#group_case_access_select').multiselect('enable');
|
||||
}
|
||||
});
|
||||
|
||||
if ($('#enable_auto_follow_cases').is(':checked')) {
|
||||
$('#group_case_access_select').multiselect('disable');
|
||||
}
|
||||
</script>
|
@@ -0,0 +1,62 @@
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-2 mr-4">Manage members of group {{ group.group_name }}</h4>
|
||||
<div class="row text-right">
|
||||
<button type="button" class="pull-right btn bg-transparent" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container col-md-12" >
|
||||
<div class="row">
|
||||
<div class="form-group" data-select2-id="7">
|
||||
<label>Members *</label>
|
||||
<div class="select2-input ml-12" data-select2-id="6">
|
||||
<select id="group_members" name="group_members" class="form-control select2-hidden-accessible ml-12" multiple=""
|
||||
data-select2-id="group_members" tabindex="-1" aria-hidden="true" style="width: 100%">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="save_group_members">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
var data = [];
|
||||
if (current_users_list.length === 0) {
|
||||
refresh_users();
|
||||
}
|
||||
|
||||
for (user in current_users_list) {
|
||||
data.push({
|
||||
label: `${current_users_list[user].user_login} (${current_users_list[user].user_name} - ${current_users_list[user].user_email})`,
|
||||
value: current_users_list[user].user_id
|
||||
});
|
||||
}
|
||||
|
||||
$('#group_members').multiselect({
|
||||
buttonWidth: 400,
|
||||
nonSelectedText: 'Select members',
|
||||
includeSelectAllOption: true,
|
||||
enableFiltering: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
filterPlaceholder: 'Search',
|
||||
filterBehavior: 'both',
|
||||
widthSynchronizationMode: 'ifPopupIsSmaller'
|
||||
});
|
||||
|
||||
$('#group_members').multiselect('dataprovider', data );
|
||||
|
||||
{% if group.group_members %}
|
||||
|
||||
$('#group_members').multiselect('select', [
|
||||
{% for member in group.group_members %} {{ member.id }}, {% endfor %}
|
||||
]);
|
||||
$('#group_members').multiselect('refresh')
|
||||
|
||||
{% endif %}
|
||||
</script>
|
@@ -0,0 +1,343 @@
|
||||
<div class="modal-xl modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_access_control_content">
|
||||
<div class="modal-header">
|
||||
<div class="row w-100 d-flex justify-content-center">
|
||||
<h4 class="modal-title ml-4 mt-3">{% if not user.user_id %}Add User{% else %} Edit user {% endif %}</h4>
|
||||
|
||||
<div class="col">
|
||||
{% if user.user_id %}
|
||||
<ul class="nav nav-pills nav-default justify-content-center" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active show" data-toggle="pill" href="#user_details_tab" role="tab" aria-controls="user_details_tab" aria-selected="false">Info</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link" data-toggle="pill" href="#user_permissions_tab" role="tab" aria-controls="user_permissions_tab" aria-selected="false">Permissions</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link" data-toggle="pill" href="#user_groups_tab" role="tab" aria-controls="user_groups_tab" aria-selected="false">Groups</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link" data-toggle="pill" href="#user_cac_tab" role="tab" aria-controls="user_cac_tab" aria-selected="false">Cases access</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div role="tabpanel">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="user_details_tab">
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_user">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
{% if not user.user_id %}
|
||||
<p class="ml-3"><i class="fa-solid fa-circle-info mr-2"></i>Permissions and groups memberships can be set once the user is created.</p>
|
||||
{% endif %}
|
||||
{% if user.user_is_service_account %}
|
||||
<p class="ml-3 text-warning-high"><i class="fa-solid fa-circle-info mr-2"></i>This is a service account. It cannot login interactively nor have a password.</p>
|
||||
{% endif %}
|
||||
<div class="form-group">
|
||||
<label for="user_name" class="mr-4">Full name
|
||||
</label>
|
||||
{{ form.user_name(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="user_login" class="placeholder">Login</label>
|
||||
{{ form.user_login(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="user_email" class="placeholder">Email</label>
|
||||
{{ form.user_email(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
{% if not user.user_is_service_account %}
|
||||
<div class="form-group mt-3" id="formGroupUserPassword">
|
||||
<label for="user_pwd" class="placeholder">Password (optional for service accounts)</label>
|
||||
<ul>
|
||||
<li><small>Must contain at least {{ server_settings.password_policy_min_length }} chars</small></li>
|
||||
{% if server_settings.password_policy_upper_case %}
|
||||
<li class="text-sm"><small>Must contain at least an upper case</small></li>
|
||||
{% endif %}
|
||||
{% if server_settings.password_policy_lower_case %}
|
||||
<li class="text-sm"><small>Must contain at least a lower case</small></li>
|
||||
{% endif %}
|
||||
{% if server_settings.password_policy_digit %}
|
||||
<li class="text-sm"><small>Must contain at least a digit</small></li>
|
||||
{% endif %}
|
||||
{% if server_settings.password_policy_special_chars %}
|
||||
<li class="text-sm"><small>Must contain at least one of : {{ server_settings.password_policy_special_chars }}</small></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
{{ form.user_password(class='form-control', autocomplete="off") }}
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">
|
||||
<div class="user_show_password" id="toggle_user_password"><i class="fa-solid fa-eye"></i></div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if not user.user_id %}
|
||||
<div class="form-group mt-3">
|
||||
|
||||
<div class="form-check">
|
||||
<label class="form-check-label mt-3" >
|
||||
{{ form.user_is_service_account(class="form-check-input", type="checkbox") }}
|
||||
<span class="form-check-sign" id="formCheckIsServiceAccount"> Use as service account
|
||||
<i class="ml-1 mt-1 fa-regular fa-circle-question" title="If checked, the user won't appear in the attribution suggestions and won't be able to connect on the UI" style="cursor:pointer;"></i>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if user.user_id %}
|
||||
<div class="form-group mt-3">
|
||||
<label for="user_id" class="placeholder">User ID</label>
|
||||
<input autocomplete="off" class="form-control" type="text" value="{{ user.user_id }}" disabled>
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="user_uuid" class="placeholder">User UUID</label>
|
||||
<input autocomplete="off" class="form-control" type="text" value="{{ user.user_uuid }}" disabled>
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="user_uuid" class="placeholder">User API Key</label>
|
||||
<input autocomplete="off" class="form-control" type="text" value="{{ user.user_api_key }}" disabled>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if user.user_id %}
|
||||
<button type="button" class="btn btn-danger mt-5"
|
||||
onclick="delete_user('{{ user.user_id }}');">Delete</button>
|
||||
{% if user.user_active %}
|
||||
<button type="button" class="btn btn-outline-danger mt-5"
|
||||
onclick="deactivate_user('{{ user.user_id }}');">Deactivate</button>
|
||||
{% else %}
|
||||
<button type="button" class="btn btn-outline-success mt-5"
|
||||
onclick="activate_user('{{ user.user_id }}');">Activate</button>
|
||||
{% endif %}
|
||||
|
||||
<button type="button" class="btn btn-outline-success ml-1 mt-5 float-right"
|
||||
id="submit_new_user">Update</button>
|
||||
|
||||
<button type="button" class="btn btn-dark mt-5 float-right"
|
||||
onclick="refresh_user_ac('{{ user.user_id }}');" id="users_refresh_ac_btn">Refresh access</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_user">Save</button>
|
||||
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="user_permissions_tab">
|
||||
<div class="container col-md-12">
|
||||
<p class="mb-4"><i class="fa-solid fa-circle-info mr-2"></i>Permissions are inherited from the groups the user belongs to. The table shows the effective permissions the user has on the platform.</p>
|
||||
<table class="table table-striped" id="user_permissions_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Permission</th>
|
||||
<th>Value</th>
|
||||
<th>Inherited from groups</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for perm in user.user_permissions %}
|
||||
<tr>
|
||||
<td>{{ user.user_permissions[perm].name }}</td>
|
||||
<td>0x{{ perm | int(perm,16) }}</td>
|
||||
<td>{% for group in user.user_permissions[perm].inherited_from %}<span class="badge ml-2 badge-light">{{ group }}</span>{% endfor %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="user_groups_tab">
|
||||
<div class="row">
|
||||
<div class="container col-md-12">
|
||||
<span class="ml-2 mt-3">Groups the user is member of.</span>
|
||||
<button class="btn btn-dark btn-sm pull-right mr-2" onclick="manage_user_groups({{ user.user_id }});">
|
||||
<span class="menu-title">Manage</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="container col-md-12">
|
||||
<table class="table table-striped" id="user_groups_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Group name</th>
|
||||
<th>Group ID</th>
|
||||
<th>Group UUID</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for group in user.user_groups %}
|
||||
<tr>
|
||||
<td>{{ group.group_name }}</td>
|
||||
<td>{{ group.group_id }}</td>
|
||||
<td>{{ group.group_uuid }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="user_cac_tab">
|
||||
<div class="container col-md-12" >
|
||||
<div class="row d-flex mb-4">
|
||||
<div class="col-8">
|
||||
<span>Cases accesses are usually inherited from groups memberships. These are not displayed here. This tab allows to add granular case access if necessary.</span>
|
||||
</div>
|
||||
<div class="col-4 pull-right">
|
||||
<button class="btn btn-dark btn-sm pull-right" onclick="refresh_user_cac({{ user.user_id }});">
|
||||
<span class="menu-title">Refresh</span>
|
||||
</button>
|
||||
<button class="btn btn-dark btn-sm pull-right mr-2" onclick="manage_user_cac({{ user.user_id }});">
|
||||
<span class="menu-title" id="manage_user_cac_button">Set case access</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<table class="table display table-striped table-hover responsive" width="100%" cellspacing="0" id="user_cac_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Case ID</th>
|
||||
<th>Case Name</th>
|
||||
<th>Access</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Case ID</th>
|
||||
<th>Case Name</th>
|
||||
<th>Access</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('#toggle_user_password').on('click', function (e) {
|
||||
const type = $('#user_password').attr('type') === 'password' ? 'text' : 'password';
|
||||
$('#user_password').attr('type', type);
|
||||
$('#toggle_user_password > i').attr('class', type === 'password' ? 'fa-solid fa-eye' : 'fa-solid fa-eye-slash');
|
||||
});
|
||||
|
||||
$('#user_permissions_table').dataTable({
|
||||
"order": [[ 1, "asc" ]]});
|
||||
$('#user_groups_table').dataTable({
|
||||
"order": [[ 1, "asc" ]],
|
||||
"columns": [{
|
||||
"title": "Group name",
|
||||
"render": function ( data, type, row, meta ) {
|
||||
if (type === 'display' ) {
|
||||
return `<i class="fa-solid fa-trash-can mr-2 text-danger" style="cursor:pointer;" title="Remove from group" href="javascript:void(0)" onclick="remove_member_from_group_wrap('${row[1]}','{{ user.user_id }}')"></i>${sanitizeHTML(data)}`;
|
||||
}
|
||||
return data;
|
||||
}},
|
||||
{"title": "Group ID"},
|
||||
{"title": "Group UUID"}
|
||||
]
|
||||
});
|
||||
|
||||
var modal_user_cac_table = $("#user_cac_table").DataTable({
|
||||
dom: 'Blfrtip',
|
||||
aaData: [],
|
||||
aoColumns: [
|
||||
{
|
||||
"data": "case_id",
|
||||
"render": function ( data, type, row ) {
|
||||
return `<i class="fa-solid fa-trash-can mr-2 text-danger" style="cursor:pointer;" title="Remove access to case" href="javascript:void(0)" onclick="remove_case_access_from_user('{{ user.user_id }}',${data})"></i>${data}`;
|
||||
},
|
||||
"className": "dt-center"
|
||||
},
|
||||
{
|
||||
"data": "case_name",
|
||||
"className": "dt-center",
|
||||
"render": function (data, type, row) {
|
||||
return `<a target="_blank" rel="noopener" href="/case?cid=${row.case_id}">${sanitizeHTML(data)}</a>`;
|
||||
}
|
||||
},
|
||||
{
|
||||
"data": "access_level_list",
|
||||
"render": function ( data, type, row ) {
|
||||
ret_data = "";
|
||||
for (acc in data) {
|
||||
ret_data += `<span class="badge ml-2 badge-light">${data[acc].name}</span>`
|
||||
}
|
||||
return ret_data;
|
||||
},
|
||||
"className": "dt-center"
|
||||
}
|
||||
],
|
||||
filter: true,
|
||||
info: true,
|
||||
ordering: true,
|
||||
processing: true,
|
||||
select: true
|
||||
});
|
||||
|
||||
var actionOptionsUser = {
|
||||
classes: [],
|
||||
contextMenu: {
|
||||
enabled: true,
|
||||
isMulti: true,
|
||||
xoffset: -10,
|
||||
yoffset: -10,
|
||||
headerRenderer: function (rows) {
|
||||
if (rows.length > 1) {
|
||||
return rows.length + ' items selected';
|
||||
} else {
|
||||
let row = rows[0];
|
||||
return 'Quick action';
|
||||
}
|
||||
},
|
||||
},
|
||||
buttonList: {
|
||||
enabled: false,
|
||||
},
|
||||
deselectAfterAction: true,
|
||||
items: [],
|
||||
};
|
||||
|
||||
actionOptionsUser.items.push({
|
||||
type: 'option',
|
||||
title: 'Remove access',
|
||||
multi: true,
|
||||
iconClass: 'fas fa-trash',
|
||||
buttonClasses: ['btn', 'btn-outline-primary'],
|
||||
action: function(rows){
|
||||
remove_cases_access_from_user_table('{{ user.user_id }}', rows);
|
||||
}
|
||||
});
|
||||
modal_user_cac_table.contextualActions(actionOptionsUser);
|
||||
|
||||
{% if user.user_id %}
|
||||
current_user_cases_access_list = {{ user.user_cases_access|tojson }};
|
||||
modal_user_cac_table.rows.add(current_user_cases_access_list);
|
||||
modal_user_cac_table.columns.adjust().draw();
|
||||
{% endif %}
|
||||
|
||||
</script>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
@@ -0,0 +1,66 @@
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-2 mr-4">Set case access</h4>
|
||||
<div class="row text-right">
|
||||
<button type="button" class="pull-right btn bg-transparent" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container col-md-12" >
|
||||
<div class="row">
|
||||
<div class="form-group" data-select2-id="7">
|
||||
<label>Set cases access of user <i>{{ user.user_name }}</i> *</label>
|
||||
<div class="col-12">
|
||||
<select id="user_case_access_select" name="org_case_access_select" class="form-control ml-12" multiple="multiple"
|
||||
tabindex="-1" aria-hidden="true" style="width: 100%">
|
||||
</select>
|
||||
<select id="user_case_ac_select" name="org_case_ac_select" class="form-control ml-12"
|
||||
tabindex="-1" aria-hidden="true" style="width: 100%">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="grant_case_access_to_user">Set access</button>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
var data = [];
|
||||
|
||||
$('#user_case_access_select').multiselect({
|
||||
buttonWidth: 400,
|
||||
nonSelectedText: 'Select case',
|
||||
emptyText: 'No case available to add',
|
||||
includeSelectAllOption: true,
|
||||
enableFiltering: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
filterPlaceholder: 'Search',
|
||||
filterBehavior: 'both',
|
||||
widthSynchronizationMode: 'ifPopupIsSmaller'
|
||||
});
|
||||
|
||||
$('#user_case_access_select').multiselect('dataprovider', [{% for ocs in outer_cases %}
|
||||
{ label: "{{ ocs.case_name }}", value: {{ ocs.case_id }} }, {% endfor %}]);
|
||||
|
||||
|
||||
$('#user_case_access_select').multiselect('refresh')
|
||||
|
||||
$('#user_case_ac_select').multiselect({
|
||||
nonSelectedText: 'Select access level',
|
||||
includeSelectAllOption: true,
|
||||
enableFiltering: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
filterPlaceholder: 'Search',
|
||||
filterBehavior: 'both',
|
||||
widthSynchronizationMode: 'ifPopupIsSmaller'
|
||||
});
|
||||
|
||||
$('#user_case_ac_select').multiselect('dataprovider', [{% for acc in access_levels %}
|
||||
{ label: "{{ acc.name }}", value: {{ acc.value }} }, {% endfor %}]);
|
||||
|
||||
$('#user_case_ac_select').multiselect('refresh');
|
||||
</script>
|
@@ -0,0 +1,68 @@
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-2 mr-4">Set case access via groups</h4>
|
||||
<div class="row text-right">
|
||||
<button type="button" class="pull-right btn bg-transparent" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container col-md-12" >
|
||||
<div class="row">
|
||||
<div class="form-group" data-select2-id="7">
|
||||
<label>Set groups case access</label>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<select id="group_case_access_select" name="group_case_access_select" class="form-control select2-hidden-accessible ml-12" multiple="multiple"
|
||||
tabindex="-1" aria-hidden="true" style="width: 100%">
|
||||
</select>
|
||||
<select id="group_case_ac_select" name="group_case_ac_select" class="form-control select2-hidden-accessible ml-12"
|
||||
tabindex="-1" aria-hidden="true" style="width: 100%">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
onclick="set_case_access_via_group('{{ caseid }}')">Set access</button>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
var data = [];
|
||||
|
||||
$('#group_case_access_select').multiselect({
|
||||
buttonWidth: 400,
|
||||
nonSelectedText: 'Select group(s)',
|
||||
emptyText: 'No groups available to set',
|
||||
includeSelectAllOption: true,
|
||||
enableFiltering: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
filterPlaceholder: 'Search',
|
||||
filterBehavior: 'both',
|
||||
widthSynchronizationMode: 'ifPopupIsSmaller'
|
||||
});
|
||||
|
||||
$('#group_case_access_select').multiselect('dataprovider', [{% for ocs in groups %}
|
||||
{ label: "{{ ocs.group_name }}", value: {{ ocs.group_id }} }, {% endfor %}]);
|
||||
|
||||
|
||||
$('#group_case_access_select').multiselect('refresh')
|
||||
|
||||
$('#group_case_ac_select').multiselect({
|
||||
nonSelectedText: 'Select access level',
|
||||
includeSelectAllOption: true,
|
||||
enableFiltering: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
filterPlaceholder: 'Search',
|
||||
filterBehavior: 'both',
|
||||
widthSynchronizationMode: 'ifPopupIsSmaller'
|
||||
});
|
||||
|
||||
$('#group_case_ac_select').multiselect('dataprovider', [{% for acc in access_levels %}
|
||||
{ label: "{{ acc.name }}", value: {{ acc.value }} }, {% endfor %}]);
|
||||
|
||||
$('#group_case_ac_select').multiselect('refresh');
|
||||
</script>
|
@@ -0,0 +1,65 @@
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-heading">
|
||||
<div class="card-title">Case access</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<p>Click on a user to unveil access control path</p>
|
||||
<table class="table table-striped table-bordered" id="case_audit_access_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User ID</th>
|
||||
<th>User Name</th>
|
||||
<th>User UUID</th>
|
||||
<th>Access</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user_id in access_audit %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if access_audit[user_id].user_effective_access_list|length == 0 %}
|
||||
<i class="mr-2 fa-solid text-danger fa-circle-xmark" title="No access"></i>
|
||||
{% elif access_audit[user_id].user_effective_access_list|length == 1 %}
|
||||
<i class="mr-2 fa-solid text-warning fa-circle-minus" title="Partial access"></i>
|
||||
{% else %}
|
||||
<i class="mr-2 fa-solid fa-circle-check text-success" title="All access"></i>
|
||||
{% endif %}
|
||||
{{ user_id }}
|
||||
</td>
|
||||
<td>{{ access_audit[user_id].user_info.user_name }}</td>
|
||||
<td>{{ access_audit[user_id].user_info.user_uuid }}</td>
|
||||
<td>{% if access_audit[user_id].user_effective_access_list|length == 0 %}
|
||||
<span class="badge badge-pill badge-light" title="Click to show trace" href="#collapse_cac_{{user_id}}" style="cursor:pointer;" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_cac_{{user_id}}">No access</span>
|
||||
{% else %}
|
||||
{% for uac in access_audit[user_id].user_effective_access_list %}
|
||||
<span class="badge badge-pill badge-light" title="Click to show trace" href="#collapse_cac_{{user_id}}" style="cursor:pointer;" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_cac_{{user_id}}">{{ uac }}</span>
|
||||
{% endfor %}
|
||||
<i class="fa-solid fa-eye ml-2" title="Click to show trace" href="#collapse_cac_{{user_id}}" style="cursor:pointer;" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_cac_{{user_id}}"></i>
|
||||
{% endif %}
|
||||
<ol class="activity-feed collapse" id="collapse_cac_{{user_id}}">
|
||||
{% if access_audit[user_id].user_effective_access_list|length == 0 %}
|
||||
The user is neither in a group nor an organisation who has access to this case
|
||||
{% endif %}
|
||||
{% for uac in access_audit[user_id].access_trace %}
|
||||
<li class="feed-item {% if uac.state == 'Effective' %} feed-item-success {% else %} feed-item-danger {% endif %}" title="{{ uac.state }}">
|
||||
<span class="text"><span class="badge badge-pill badge-light">{{ uac.name }}</span> ({{ uac.state }})</span><br />
|
||||
<span class="text">Inherited from {{ uac.inherited_from.object_type }} <i class="fa-solid fa-right-long"></i> {{ uac.inherited_from.object_name }} (ID {{ uac.inherited_from.object_id }} :: UUID {{ uac.inherited_from.object_uuid }})</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,62 @@
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-2 mr-4">Manage user groups</h4>
|
||||
<div class="row text-right">
|
||||
<button type="button" class="pull-right btn bg-transparent" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container col-md-12" >
|
||||
<div class="row">
|
||||
<div class="form-group" data-select2-id="7">
|
||||
<label>Groups membership *</label>
|
||||
<div class="select2-input ml-12" data-select2-id="6">
|
||||
<select id="user_groups_membership" name="user_groups_membership" class="form-control select2-hidden-accessible ml-12" multiple=""
|
||||
tabindex="-1" aria-hidden="true" style="width: 100%">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="save_user_groups_membership">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
<script>
|
||||
var data = [];
|
||||
if (current_groups_list.length === 0) {
|
||||
refresh_groups();
|
||||
}
|
||||
|
||||
for (group in current_groups_list) {
|
||||
data.push({
|
||||
label: `${current_groups_list[group].group_name}`,
|
||||
value: current_groups_list[group].group_id
|
||||
});
|
||||
}
|
||||
|
||||
$('#user_groups_membership').multiselect({
|
||||
buttonWidth: 400,
|
||||
nonSelectedText: 'Select groups',
|
||||
includeSelectAllOption: true,
|
||||
enableFiltering: true,
|
||||
enableCaseInsensitiveFiltering: true,
|
||||
filterPlaceholder: 'Search',
|
||||
filterBehavior: 'both',
|
||||
widthSynchronizationMode: 'ifPopupIsSmaller'
|
||||
});
|
||||
|
||||
$('#user_groups_membership').multiselect('dataprovider', data );
|
||||
|
||||
{% if user.user_groups %}
|
||||
|
||||
$('#user_groups_membership').multiselect('select', [
|
||||
{% for group in user.user_groups %} {{ group.group_id }}, {% endfor %}
|
||||
]);
|
||||
$('#user_groups_membership').multiselect('refresh')
|
||||
|
||||
{% endif %}
|
||||
</script>
|
@@ -0,0 +1,94 @@
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-heading">
|
||||
<div class="card-title">User permissions</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<p class="mb-4">Permissions are inherited from the groups the user belongs to. The table shows the effective permissions the user has on the platform.</p>
|
||||
<table class="table table-striped table-bordered" id="user_audit_permissions_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Permission</th>
|
||||
<th>Value</th>
|
||||
<th>Inherited from groups</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for perm in permissions_audit['details'] %}
|
||||
<tr>
|
||||
<td>{{ permissions_audit['details'][perm].name }}</td>
|
||||
<td>0x{{ perm | int(perm,16) }}</td>
|
||||
<td>{% for group_id in permissions_audit['details'][perm].inherited_from %}<span class="badge ml-2 badge-light">{{ permissions_audit['details'][perm].inherited_from[group_id].group_name }}</span>{% endfor %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-heading">
|
||||
<div class="card-title">User cases access</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<p>Click on a case to unveil access control path</p>
|
||||
<table class="table table-striped table-bordered" id="user_audit_access_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Case name</th>
|
||||
<th>Access</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for case_id in access_audit %}
|
||||
<tr>
|
||||
<td>
|
||||
{% if access_audit[case_id].user_effective_access|length == 0 or 'deny_all' in access_audit[case_id].user_effective_access[0].name %}
|
||||
<i class="mr-2 fa-solid text-danger fa-eye-slash" title="No access"></i>
|
||||
{% elif 'read_only' in access_audit[case_id].user_effective_access[0].name %}
|
||||
<i class="mr-2 fa-solid text-warning fa-lock" title="Read only access"></i>
|
||||
{% else %}
|
||||
<i class="mr-2 fa-solid fa-circle-check text-success" title="Full access"></i>
|
||||
{% endif %}
|
||||
{{ access_audit[case_id].case_info.case_name }}
|
||||
</td>
|
||||
<td>{% if access_audit[case_id].user_effective_access|length == 0 %}
|
||||
<span class="badge badge-pill badge-light" title="Click to show trace" href="#collapse_cac_{{case_id}}" style="cursor:pointer;" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_cac_{{case_id}}">No access</span>
|
||||
{% else %}
|
||||
{% for uac in access_audit[case_id].user_effective_access %}
|
||||
<span class="badge badge-pill badge-light" title="Click to show trace" href="#collapse_cac_{{case_id}}" style="cursor:pointer;" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_cac_{{case_id}}">{{ uac.name }}</span>
|
||||
{% endfor %}
|
||||
<i class="fa-solid fa-eye ml-2" title="Click to show trace" href="#collapse_cac_{{case_id}}" style="cursor:pointer;" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_cac_{{case_id}}"></i>
|
||||
{% endif %}
|
||||
<ol class="activity-feed collapse" id="collapse_cac_{{case_id}}">
|
||||
{% if access_audit[case_id].user_effective_access|length == 0 %}
|
||||
The user is neither in a group nor an organisation who has access to this case
|
||||
{% endif %}
|
||||
{% for uac in access_audit[case_id].user_access %}
|
||||
<li class="feed-item {% if uac.state == 'Effective' %} feed-item-success {% else %} feed-item-danger {% endif %}" title="{{ uac.state }}">
|
||||
<span class="text">{% for ac in uac.access_list %}<span class="badge badge-pill badge-light">{{ ac.name }}</span>{% endfor %} ({{ uac.state }})</span><br />
|
||||
<span class="text">Inherited from {{ uac.inherited_from.object_type }} <i class="fa-solid fa-right-long"></i> {{ uac.inherited_from.object_name }} (ID {{ uac.inherited_from.object_id }} :: UUID {{ uac.inherited_from.object_uuid }})</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,82 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Manage Attributes {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="/static/assets/css/suggestags.css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="page-inner">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card-title">Objects Attributes</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_attribute_table();">
|
||||
Refresh
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="table-responsive" id="hooks_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="table_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="attributes_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#ID</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>#ID</th>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal" tabindex="-1" id="modal_add_attribute" data-backdrop="true">
|
||||
<div class="modal-xxl modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_add_attribute_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
<div class="modal bg-primary-gradient" tabindex="-1" id="modal_preview_attribute" data-backdrop="true">
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_preview_attribute_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="/static/assets/js/plugin/ace/src-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/assets/js/plugin/ace/src-noconflict/ext-language_tools.js" type="text/javascript"
|
||||
charset="utf-8"></script>
|
||||
|
||||
<script src="/static/assets/js/iris/manage.attributes.js"></script>
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,93 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Manage Case Templates {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="page-inner">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card-title">Case Templates</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_case_template_table();">
|
||||
Refresh
|
||||
</button>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="add_case_template();">
|
||||
Add case template
|
||||
</button>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="fire_upload_case_template();">
|
||||
Upload case template
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="table-responsive" id="hooks_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="table_buttons"></span>
|
||||
</div>
|
||||
<table aria-describedby="Case template list"
|
||||
class="table display table table-striped table-hover"
|
||||
style="width: 100%; border-spacing: 0;" id="case_templates_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#ID</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">Added by</th>
|
||||
<th scope="col">Created at</th>
|
||||
<th scope="col">Updated at</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th scope="col">#ID</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Description</th>
|
||||
<th scope="col">Added by</th>
|
||||
<th scope="col">Created at</th>
|
||||
<th scope="col">Updated at</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal" tabindex="-1" id="modal_case_template" data-backdrop="true">
|
||||
<div class="modal-xxl modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_case_template_json">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
<div class="modal" tabindex="-1" role="dialog" id="modal_upload_case_template" data-backdrop="true">
|
||||
<div class="modal-xl modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_upload_case_template_json">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="/static/assets/js/plugin/ace/src-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/assets/js/plugin/ace/src-noconflict/ext-language_tools.js" type="text/javascript"
|
||||
charset="utf-8"></script>
|
||||
<script src="/static/assets/js/iris/manage.case.templates.js"></script>
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,184 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Manage Cases {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="/static/assets/css/dataTables.select.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/bootstrap-select.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/bootstrap-multiselect.min.css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="page-inner">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">Cases management</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="col-md-12">
|
||||
<div class="row">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<ul class="nav nav-pills nav-dark" id="pills-tabs-manage-case"
|
||||
role="tablist">
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link active show" id="add-tab" data-toggle="pill" href="#add" role="tab"
|
||||
aria-controls="pills-home-nobd" aria-selected="true">New</a>
|
||||
</li>
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link" id="view-tab" data-toggle="pill" href="#view" role="tab"
|
||||
aria-controls="view-tab" aria-selected="false">Cases list</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="myTab1Content" class="tab-content col-md-12">
|
||||
<div id="add" role="tabpanel" aria-labelledby="add-tab"
|
||||
class="tab-pane fade px-4 py-5 show active">
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-lg-6 col-sm-12">
|
||||
<h4 class="border-bottom pb-3">General info</h4>
|
||||
Fields with an asterix are required.
|
||||
<form method="post" action='' id="form_new_case" autocomplete="off">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="mt-4 col-md-12 col-lg-12 col-sm-12">
|
||||
<div class="input-group mb-4">
|
||||
{{ form.case_customer(class="selectpicker form-control") }}
|
||||
</div>
|
||||
<div class="input-group mb-4">
|
||||
{{ form.case_template_id(class="selectpicker form-control", data_actions_box="true") }}
|
||||
</div>
|
||||
<div class="input-group mb-4">
|
||||
{{ form.classification_id(class="selectpicker form-control") }}
|
||||
</div>
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Case name *</span>
|
||||
</div>
|
||||
{{ form.case_name(class="form-control", type="text") }}
|
||||
</div>
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Short description *</span>
|
||||
</div>
|
||||
{{ form.case_description(class="form-control", type="text") }}
|
||||
</div>
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">SOC ticket ID</span>
|
||||
</div>
|
||||
{{ form.case_soc_id(class="form-control", type="text") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-12 col-lg-6 col-sm-12">
|
||||
{% if attributes and attributes|length > 0 %}
|
||||
<h4><ul class="nav nav-tabs nav-lines mr-4" role="tablist">
|
||||
{% for ca in attributes %}
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link {% if loop.index == 1 %}{{"active show"}}{% endif %}" data-toggle="tab" href="#itab_{{ loop.index }}_{{ ca.lower() | replace(' ', '_' ) }}"
|
||||
role="tab" aria-selected="false">{{ca}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
</ul></h4>
|
||||
<div role="tabpanel">
|
||||
<div class="tab-content">
|
||||
{% set is_case_page = True %}
|
||||
{% include 'modals/modal_attributes_tabs.html' %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-outline-success ml-4 mt-5 float-right" id="submit_new_case_btn" onclick="submit_new_case();">Create</button>
|
||||
</div>
|
||||
<div id="view" role="tabpanel" aria-labelledby="view-tab" class="tab-pane fade px-4 py-5">
|
||||
<button type="button" class="btn btn-sm btn-outline-dark float-right mr-3"
|
||||
onclick="refresh_case_table();">
|
||||
Refresh
|
||||
</button>
|
||||
<div class="table-responsive" id="cases_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="table_buttons"></span>
|
||||
</div>
|
||||
<table class="table display wrap col-border table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="cases_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Customer</th>
|
||||
<th>State</th>
|
||||
<th>Open date</th>
|
||||
<th>Close date</th>
|
||||
<th>SOC Ticket</th>
|
||||
<th>Opening user</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Customer</th>
|
||||
<th>State</th>
|
||||
<th>Open date</th>
|
||||
<th>Close date</th>
|
||||
<th>SOC Ticket</th>
|
||||
<th>Opening user</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- End bordered tabs -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal " tabindex="-1" role="dialog" id="modal_case_detail" data-backdrop="true">
|
||||
<div class="modal-xl modal-dialog" role="document">
|
||||
<div class="modal-content" id="info_case_modal_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
<div class="modal bg-shadow-gradient" tabindex="-1" role="dialog" id="modal_ac_additional" data-backdrop="true">
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="/static/assets/js/core/jquery.validate.js"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/dataTables.cellEdit.js"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/dataTables.buttons.min.js"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/dataTables.select.min.js"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/dataTables.responsive.min.js"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/buttons.html5.min.js"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/buttons.print.min.js"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/buttons.print.min.js"></script>
|
||||
|
||||
<script src="/static/assets/js/plugin/select/bootstrap-select.min.js"></script>
|
||||
<script src="/static/assets/js/plugin/select/bootstrap-multiselect.min.js"></script>
|
||||
|
||||
<script src="/static/assets/js/iris/datatablesUtils.js"></script>
|
||||
<script src="/static/assets/js/iris/manage.cases.common.js"></script>
|
||||
<script src="/static/assets/js/iris/manage.cases.js"></script>
|
||||
|
||||
<script>
|
||||
$('form#form_new_case').validate();
|
||||
</script>
|
||||
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,191 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Manage Customers {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
|
||||
<link rel="stylesheet" href="/static/assets/css/suggestags.css">
|
||||
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="page-inner">
|
||||
<a class="mb-2 ml-1 text-dark" href="/manage/customers?cid={{ session['current_case'].case_id }}"><i class="fa-solid fa-arrow-left"></i> Back</a>
|
||||
<div class="mt-2 mb-4">
|
||||
<div class="row ml-2 mr-2">
|
||||
<h2 class="pb-2">Customer > {{ customer.customer_name }}</h2>
|
||||
<button class="btn btn-light btn-sm ml-auto" onclick="customer_detail('{{ customer.customer_id }}');">Edit customer</button>
|
||||
</div>
|
||||
</div>
|
||||
<input id="customer_id" style="display:none;" value="{{ customer.customer_id }}"/>
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<div class="card card-dark bg-success-gradient">
|
||||
<div class="card-body pb-0">
|
||||
<div class="h1 fw-bold float-right"></div>
|
||||
<h2 id="current_open_cases" class="mb-2">0</h2>
|
||||
<p>Current open cases</p>
|
||||
<div class="pull-in sparkline-fix chart-as-background">
|
||||
<div id="chart_current_open_cases"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="card card-dark bg-info-gradient">
|
||||
<div class="card-body pb-0">
|
||||
<div class="h5 fw-bold float-right"><span id="ratio_month"></span></div>
|
||||
<h2 id="cases_current_month" class="mb-2"></h2>
|
||||
<p>Current month</p>
|
||||
<div class="pull-in sparkline-fix chart-as-background">
|
||||
<div id="chart_month_cases"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="card card-dark bg-info-gradient">
|
||||
<div class="card-body pb-0">
|
||||
<div class="h1 fw-bold float-right"></div>
|
||||
<h2 id="cases_last_month" class="mb-2">0</h2>
|
||||
<p>Last month</p>
|
||||
<div class="pull-in sparkline-fix chart-as-background">
|
||||
<div id=""></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="card card-dark bg-info-gradient">
|
||||
<div class="card-body pb-0">
|
||||
<div class="h5 fw-bold float-right"><span id="ratio_year"></span></div>
|
||||
<h2 id="cases_current_year" class="mb-2">0</h2>
|
||||
<p>Current year </p>
|
||||
<div class="pull-in sparkline-fix chart-as-background">
|
||||
<div id="chart_year_cases"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="card card-dark bg-info-gradient">
|
||||
<div class="card-body pb-0">
|
||||
<div class="h3 fw-bold float-right"></div>
|
||||
<h2 id="cases_last_year" class="mb-2">0</h2>
|
||||
<p>Last year (<span id="last_year"></span>)</p>
|
||||
<div class="pull-in sparkline-fix chart-as-background">
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="card card-dark bg-close-gradient">
|
||||
<div class="card-body pb-0">
|
||||
<div class="h1 fw-bold float-right"></div>
|
||||
<h2 id="cases_total" class="mb-2">0</h2>
|
||||
<p>Total</p>
|
||||
<div class="pull-in sparkline-fix chart-as-background">
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card card-customer">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-3 info-customer">
|
||||
<h5 class="sub"><b>Customer name</b></h5>
|
||||
<p>{{ customer.customer_name }}</p>
|
||||
</div>
|
||||
<div class="col-md-3 info-customer">
|
||||
<h5 class="sub"><b>Customer Description</b></h5>
|
||||
<p>{{ customer.customer_description }}</p>
|
||||
</div>
|
||||
<div class="col-md-3 info-customer">
|
||||
<h5 class="sub text-bold"><b>Customer SLAs</b></h5>
|
||||
<p>{{ customer.customer_sla }}</p>
|
||||
</div>
|
||||
<div class="col-md-3 info-customer">
|
||||
<h5 class="sub text-bold"><b>Average case duration</b></h5>
|
||||
<p><span id="average_case_duration"></span> days</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card card-customer">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<h3><strong><i class="ml-1 fa-regular fa-address-book mr-1"></i> Contacts</strong></h3>
|
||||
<button class="btn btn-light btn-sm ml-auto" onclick="add_new_contact({{ customer.customer_id }});">Add Contact</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="customer-list">
|
||||
{% for contact in contacts %}
|
||||
<div class="contact-list-item">
|
||||
<div class="contact-list-detail">
|
||||
<span class="date float-right"><button class="btn btn-light btn-sm" onclick="edit_contact('{{ contact.id }}','{{ customer.customer_id }}');">Edit</button></span>
|
||||
<span class="h4">{{ contact.contact_name }}</span>
|
||||
<p class="ml-2">
|
||||
{% if contact.contact_role %}
|
||||
<b>Role: </b>{{ contact.contact_role }}<br/>
|
||||
{% endif %}
|
||||
{% if contact.contact_email %}
|
||||
<b>Email: </b>{{ contact.contact_email }}<br/>
|
||||
{% endif %}
|
||||
{% if contact.contact_work_phone %}
|
||||
<b>Work phone: </b>{{ contact.contact_work_phone }}<br/>
|
||||
{% endif %}
|
||||
{% if contact.contact_mobile_phone %}
|
||||
<b>Mobile phone: </b>{{ contact.contact_mobile_phone }}<br/>
|
||||
{% endif %}
|
||||
{% if contact.contact_note %}
|
||||
<b>Notes: </b>{{ contact.contact_note }}<br/>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="modal" tabindex="-1" role="dialog" id="modal_add_customer" data-backdrop="true">
|
||||
<div class="modal-xl modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_add_customer_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
<div class="modal" tabindex="-1" role="dialog" id="modal_add_contact" data-backdrop="true">
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_add_contact_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="/static/assets/js/iris/manage.customers.js"></script>
|
||||
<script src="/static/assets/js/iris/view.customers.js"></script>
|
||||
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,74 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Manage Customers {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
|
||||
<link rel="stylesheet" href="/static/assets/css/suggestags.css">
|
||||
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="page-inner">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card-title">Customers management</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_customer_table(true);">
|
||||
Refresh
|
||||
</button>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="add_customer();">Add customer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="table-responsive" id="customers_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="table_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="customers_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal" tabindex="-1" role="dialog" id="modal_add_customer" data-backdrop="true">
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_add_customer_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="/static/assets/js/iris/manage.customers.js"></script>
|
||||
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,120 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>IRIS - Server updates</title>
|
||||
<meta content='width=device-width, initial-scale=1.0, shrink-to-fit=no' name='viewport' />
|
||||
<link rel="icon" href="/static/assets/img/logo.ico" type="image/x-icon"/>
|
||||
|
||||
<!-- Fonts and icons -->
|
||||
<script src="/static/assets/js/plugin/webfont/webfont.min.js"></script>
|
||||
<script>
|
||||
WebFont.load({
|
||||
custom: {"families":["Lato:300,400,700,900", "Flaticon", "Font Awesome 5 Solid", "Font Awesome 5 Regular", "Font Awesome 5 Brands", "simple-line-icons"],
|
||||
urls: ['/static/assets/css/fonts.css']},
|
||||
active: function() {
|
||||
sessionStorage.fonts = true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- CSS Files -->
|
||||
<link rel="stylesheet" href="/static/assets/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/atlantis.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/bootstrap-select.min.css">
|
||||
|
||||
</head>
|
||||
<body class="bg-dark-gradient p-4" style="height: 100vh;">
|
||||
<div class="container bg-white shadow-lg p-3 rounded mb-4">
|
||||
<div class="mt-2 row">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<a href="/" class="logo ml-2 text-center">
|
||||
<img src="/static/assets/img/logo-alone-2-black.png" alt="navbar brand" class='image-update navbar-brand' width="50">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 row">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<h1 class="text-dark text-center">Server Updates</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row ">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<i class="text-dark">Some great improvements are hopefully on their way, hang tight</i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<h4 class="text-danger text-center">Please do not leave or refresh the page once updates have started</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4 update_start_txt">
|
||||
<div class="col pl-4 justify-content-center">
|
||||
<p class="text-center">Ensure users are disconnected. Any unsaved work might be lost.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4 justify-content-center update_start_txt">
|
||||
<div class="col-6">
|
||||
<p class="text-center">The following steps might occur during updates, depending on the updates scope : </p>
|
||||
<ul>
|
||||
<li>Fetch of updates information from github.com</li>
|
||||
<li>Download of updates assets from github</li>
|
||||
<li>Signatures verification</li>
|
||||
<li>Compatibility verifications</li>
|
||||
<li>Back up of the current server code to backup storage defined in <code>BACKUP_PATH</code></li>
|
||||
<li>Server stop and update of application</li>
|
||||
<li>Server restarts</li>
|
||||
<li>Version check</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col d-flex justify-content-center ">
|
||||
<a href='#' onclick="start_updates();" class="btn btn-outline-success text-center" id="update_start_btn">Start updates</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="container-updates" class="row shadow-lg ml-4 mr-4 rounded" style="display:none;">
|
||||
<div class="col justify-content-left text-dark pl-4 pb-4 pt-4 pr-4 mh-100">
|
||||
<div class="col">
|
||||
<div id="updates_log">
|
||||
</div>
|
||||
<div id="updates_log_end"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-dark">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<div id="offline_time" style="display:none;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<div id="tag_bottom" style="display:none;" class="lds-ellipsis"><div></div><div></div><div></div><div></div></div>
|
||||
<a href='/manage/settings' class="btn btn-dark ml-mr-auto" style="display:none;" id="update_return_button">Go back to server</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Core JS Files -->
|
||||
|
||||
<script src="/static/assets/js/core/jquery.3.2.1.min.js"></script>
|
||||
<script src="/static/assets/js/core/popper.min.js"></script>
|
||||
<script src="/static/assets/js/core/bootstrap.min.js"></script>
|
||||
|
||||
<!-- jQuery UI -->
|
||||
<script src="/static/assets/js/plugin/jquery-ui-1.12.1.custom/jquery-ui.min.js"></script>
|
||||
<script src="/static/assets/js/plugin/jquery-ui-touch-punch/jquery.ui.touch-punch.min.js"></script>
|
||||
|
||||
<!-- jQuery Scrollbar -->
|
||||
<script src="/static/assets/js/plugin/jquery-scrollbar/jquery.scrollbar.min.js"></script>
|
||||
|
||||
<!-- Atlantis JS -->
|
||||
<script src="/static/assets/js/atlantis.min.js"></script>
|
||||
{% if current_user.in_dark_mode %}<script src="/static/assets/js/dark-mode.js"></script>{% endif %}
|
||||
|
||||
<script src="/static/assets/js/core/socket.io.js"></script>
|
||||
<script src="/static/assets/js/iris/updates.handler.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -0,0 +1,143 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Manage Modules {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="/static/assets/css/suggestags.css">
|
||||
<link rel="stylesheet" href="/static/assets/css/dataTables.group.min.css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="page-inner">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card-title">Modules management</div>
|
||||
{{ form.hidden_tag() }}
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_modules();">
|
||||
Refresh
|
||||
</button>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="add_module();">Add module</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="table-responsive" id="module_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="table_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="modules_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#ID</th>
|
||||
<th>Module name</th>
|
||||
<th>Has pipeline</th>
|
||||
<th>Module version</th>
|
||||
<th>Interface version</th>
|
||||
<th>Date added</th>
|
||||
<th>Added by</th>
|
||||
<th>Active</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>#ID</th>
|
||||
<th>Module name</th>
|
||||
<th>Has pipeline</th>
|
||||
<th>Module version</th>
|
||||
<th>Interface version</th>
|
||||
<th>Date added</th>
|
||||
<th>Added by</th>
|
||||
<th>Active</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card-title">Registered hooks</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-icon btn-round btn-outline-black float-right" onclick="refresh_modules_hooks();">
|
||||
<i class="fas fa-sync rotate"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="table-responsive" id="hooks_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="table_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="hooks_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#ID</th>
|
||||
<th>Registrant module</th>
|
||||
<th>Hook name</th>
|
||||
<th>Hook description</th>
|
||||
<th>Automatic trigger</th>
|
||||
<th>Active</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>#ID</th>
|
||||
<th>Registrant module</th>
|
||||
<th>Hook name</th>
|
||||
<th>Hook description</th>
|
||||
<th>Automatic trigger</th>
|
||||
<th>Active</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal" tabindex="-1" role="dialog" id="modal_add_module" data-backdrop="true">
|
||||
<div class="modal-xl modal-dialog modal-dialog-scrollable" role="document">
|
||||
<div class="modal-content" id="modal_add_module_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
<div class="modal bg-shadow-gradient" tabindex="-1" role="dialog" id="modal_update_param" data-backdrop="true">
|
||||
<div class="modal-xl modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document">
|
||||
<div class="modal-content shadow-lg p-3 mb-5 rounded" id="modal_update_param_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="/static/assets/js/plugin/ace/src-noconflict/ace.js" type="text/javascript" charset="utf-8"></script>
|
||||
<script src="/static/assets/js/plugin/ace/src-noconflict/ext-language_tools.js" type="text/javascript"
|
||||
charset="utf-8"></script>
|
||||
<script src="/static/assets/js/plugin/datatables/dataTables.group.min.js"></script>
|
||||
<script src="/static/assets/js/iris/manage.modules.js"></script>
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,209 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Manage Objects {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="/static/assets/css/suggestags.css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="page-inner">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col col-heading collapsed" href="#collapse_assets" title="Click to unfold" data-toggle="collapse" aria-expanded="false" role="button" aria-controls="collapse_assets">
|
||||
<span class="accicon float-left mr-3"><i class="fas fa-angle-right rotate-icon"></i></span>
|
||||
<div class="card-title">Assets types</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_asset_table();">
|
||||
Refresh
|
||||
</button>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="add_asset_type();">Add new</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body collapse" id="collapse_assets">
|
||||
|
||||
<div class="table-responsive" id="assets_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="table_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="assets_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Icon - not compromised</th>
|
||||
<th>Icon - compromised</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Icon - not compromised</th>
|
||||
<th>Icon - compromised</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header" >
|
||||
<div class="row">
|
||||
<div class="col col-heading collapsed" href="#collapse_ioc" title="Click to unfold" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_ioc">
|
||||
<span class="accicon float-left mr-3"><i class="fas fa-angle-right rotate-icon"></i></span>
|
||||
<div class="card-title">IOC types</div>
|
||||
</div>
|
||||
<div class="col float-right">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_ioc_table();">
|
||||
Refresh
|
||||
</button>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="add_ioc_type();">Add new</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body collapse" id="collapse_ioc">
|
||||
<div class="table-responsive" id="ioc_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="ioc_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="ioc_table">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Taxonomy</th>
|
||||
<th>Validation regex</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Taxonomy</th>
|
||||
<th>Validation regex</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header" >
|
||||
<div class="row">
|
||||
<div class="col col-heading collapsed" href="#collapse_classifications" title="Click to unfold" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_classifications">
|
||||
<span class="accicon float-left mr-3"><i class="fas fa-angle-right rotate-icon"></i></span>
|
||||
<div class="card-title">Case classifications</div>
|
||||
</div>
|
||||
<div class="col float-right">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_classification_table();">
|
||||
Refresh
|
||||
</button>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="add_classification();">Add new</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body collapse" id="collapse_classifications">
|
||||
<div class="table-responsive" id="classification_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="classification_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="classification_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Expanded name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Expanded name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header" >
|
||||
<div class="row">
|
||||
<div class="col col-heading collapsed" href="#collapse_state" title="Click to unfold" data-toggle="collapse" role="button" aria-expanded="false" aria-controls="collapse_state">
|
||||
<span class="accicon float-left mr-3"><i class="fas fa-angle-right rotate-icon"></i></span>
|
||||
<div class="card-title">Case state</div>
|
||||
</div>
|
||||
<div class="col float-right">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_state_table();">
|
||||
Refresh
|
||||
</button>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="add_state();">Add new</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body collapse" id="collapse_state">
|
||||
<div class="table-responsive" id="state_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="state_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="state_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal" tabindex="-1" id="modal_add_type" data-backdrop="true">
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_add_type_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="/static/assets/js/iris/manage.objects.js"></script>
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,218 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Server Settings {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="/static/assets/css/suggestags.css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="page-inner">
|
||||
<div class="row ">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">Server versions</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="col-12 mb-4">
|
||||
<dl class="row">
|
||||
<dt class="col-sm-3">IRIS server version:</dt>
|
||||
<dd class="col-sm-8">{{ versions.iris_current }}</dd>
|
||||
|
||||
<dt class="col-sm-3">Database revision:</dt>
|
||||
<dd class="col-sm-8">{{ versions.db_revision }}</dd>
|
||||
|
||||
<dt class="col-sm-3">Min. API version supported:</dt>
|
||||
<dd class="col-sm-8">{{ versions.api_min }}</dd>
|
||||
|
||||
<dt class="col-sm-3">Max. API version supported:</dt>
|
||||
<dd class="col-sm-8">{{ versions.api_current }}</dd>
|
||||
|
||||
<dt class="col-sm-3">Min. module interface version supported:</dt>
|
||||
<dd class="col-sm-8">{{ versions.interface_min }}</dd>
|
||||
|
||||
<dt class="col-sm-3">Max. module interface version supported:</dt>
|
||||
<dd class="col-sm-8">{{ versions.interface_current }}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="row">-->
|
||||
<!-- <div class="col-12">-->
|
||||
<!-- <div class="float-right mt-4">-->
|
||||
<!-- <button class="btn btn-outline-primary" id="check_updates" type="button" onclick="check_updates()">Check for updates</button>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">Global settings</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row mt-2">
|
||||
<div class="col-12">
|
||||
<form id="form_srv_settings">
|
||||
{{ form.hidden_tag() }}
|
||||
<h2>Proxy</h2>
|
||||
<div class="mb-4">
|
||||
<p>Proxy settings can be used by modules to access external resources.</p>
|
||||
<div class="row mb-4">
|
||||
<div class="col-6">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
HTTP Proxy
|
||||
</span>
|
||||
</div>
|
||||
<input class="form-control" name="http_proxy" placeholder="HTTP Proxy" value="{{ settings.http_proxy }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
HTTP Proxy
|
||||
</span>
|
||||
</div>
|
||||
<input class="form-control" name="https_proxy" placeholder="HTTPS Proxy" value="{{ settings.http_proxy }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="mt-4">Post-init Behavior</h2>
|
||||
<div class="col-12 mb-4">
|
||||
<!-- <div class="form-check">-->
|
||||
<!-- <label class="form-check-label">-->
|
||||
<!-- <input class="form-check-input" type="checkbox" id="enable_updates_check" name="enable_updates_check" {% if settings.enable_updates_check %}checked{% endif %}>-->
|
||||
<!-- <span class="form-check-sign">Enable automatic daily check for updates</span>-->
|
||||
<!-- </label>-->
|
||||
<!-- </div>-->
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" id="prevent_post_mod_repush" name="prevent_post_mod_repush" {% if settings.prevent_post_mod_repush %}checked{% endif %}>
|
||||
<span class="form-check-sign">Prevent post-init step to register default modules again during boot</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" id="prevent_post_objects_repush" name="prevent_post_objects_repush" {% if settings.prevent_post_objects_repush %}checked{% endif %}>
|
||||
<span class="form-check-sign">Prevent post-init step to register default case objects again during boot</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="mt-4">Password Policy</h2>
|
||||
<p>A password policy change applies to new or updated passwords.</p>
|
||||
<div class="row mb-2">
|
||||
<div class="col-4">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
Minimum Password Length
|
||||
</span>
|
||||
</div>
|
||||
<input class="form-control" name="password_policy_min_length" placeholder="12" type="number" value="{{ settings.password_policy_min_length }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">
|
||||
Include Special chars
|
||||
</span>
|
||||
</div>
|
||||
<input class="form-control" name="password_policy_special_chars" placeholder="Set empty to disable" type="text" value="{{ settings.password_policy_special_chars }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" id="password_policy_upper_case" name="password_policy_upper_case" {% if settings.password_policy_upper_case %}checked{% endif %}>
|
||||
<span class="form-check-sign">Must include uppercase char</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" id="password_policy_lower_case" name="password_policy_lower_case" {% if settings.password_policy_lower_case %}checked{% endif %}>
|
||||
<span class="form-check-sign">Must include lowercase char</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<input class="form-check-input" type="checkbox" id="password_policy_digit" name="password_policy_digit" {% if settings.password_policy_digit %}checked{% endif %}>
|
||||
<span class="form-check-sign">Must include digits</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="float-right mt-4">
|
||||
<button class="btn btn-outline-primary float-right" id="save_srv_settings" type="button" onclick="update_settings()">Save changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">Backups</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row mt-2">
|
||||
<div class="col-12">
|
||||
<h2>Database</h2>
|
||||
<p>Initiate a database backup. The backup file is stored on the configured path <code>BACKUP_PATH</code></p>
|
||||
<div class="float-right mt-4">
|
||||
<button class="btn btn-outline-primary" id="init_db_backup" type="button" onclick="init_db_backup()">Backup database</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal " tabindex="-1" role="dialog" id="modal_updates" data-backdrop="true">
|
||||
<div class="modal-xl modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_updates_content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-2 mr-4">Server Updates</h4>
|
||||
<button type="button" class="pull-right btn btn-white" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container col-md-12">
|
||||
<div class="row">
|
||||
<h3>Please wait while we look for updates</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="/static/assets/js/plugin/showdown/showdown.min.js"></script>
|
||||
|
||||
<script src="/static/assets/js/iris/manage.server.settings.js"></script>
|
||||
<script>
|
||||
|
||||
</script>
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,82 @@
|
||||
{% extends "layouts/default.html" %}
|
||||
|
||||
{% block title %} Manage Templates {% endblock title %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link rel="stylesheet" href="/static/assets/css/suggestags.css">
|
||||
{% endblock stylesheets %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if current_user.is_authenticated %}
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="page-inner">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card-title">Report Templates Management</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-dark float-right ml-2" onclick="refresh_template_table();">
|
||||
Refresh
|
||||
</button>
|
||||
<button class="btn btn-sm btn-dark float-right ml-2" onclick="add_report_template();">Add template</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="table-responsive" id="assets_table_wrapper">
|
||||
<div class="selectgroup">
|
||||
<span id="table_buttons"></span>
|
||||
</div>
|
||||
<table class="table display table table-striped table-hover" width="100%"
|
||||
cellspacing="0" id="reports_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Naming format</th>
|
||||
<th>Date created</th>
|
||||
<th>Created by</th>
|
||||
<th>Language</th>
|
||||
<th>Type</th>
|
||||
<th>Download</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Naming format</th>
|
||||
<th>Date created</th>
|
||||
<th>Created by</th>
|
||||
<th>Language</th>
|
||||
<th>Type</th>
|
||||
<th>Download</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade " tabindex="-1" role="dialog" id="modal_add_report_template" data-backdrop="true">
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content" id="modal_report_template_content">
|
||||
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
<script src="/static/assets/js/iris/manage.templates.js"></script>
|
||||
{% endblock javascripts %}
|
@@ -0,0 +1,80 @@
|
||||
<div class="modal-header">
|
||||
<h4>Add Asset Type</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_asset_type" enctype="multipart/form-data">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
<label for="asset_type" class="mr-4">Asset Type
|
||||
</label>
|
||||
{{ form.asset_name(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="asset_description" class="placeholder">Asset Type description</label>
|
||||
{{ form.asset_description(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="row ml-2">
|
||||
{% if assettype.asset_icon_not_compromised %}
|
||||
<div class="form-group col-2">
|
||||
<label for="asset_icon_not_compromised" class="mr-4">Preview</label>
|
||||
<div id="asset_icon_not_compromised">
|
||||
<img style="width:2em;height:2em" src="{{ assettype.asset_icon_not_compromised_path }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col">
|
||||
<label for="asset_icon_compromised" class="mr-4">Asset Icon - not compromised
|
||||
</label>
|
||||
{{ form.asset_icon_not_compromised(class='form-control',type='file', accept='.svg, .png') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-group col">
|
||||
<label for="asset_icon_compromised" class="mr-4">Asset Icon - not compromised
|
||||
</label>
|
||||
{{ form.asset_icon_not_compromised(class='form-control',type='file', required='false', value=assettype.asset_icon_not_compromised, accept='.svg, .png') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row ml-2">
|
||||
{% if assettype.asset_icon_compromised %}
|
||||
<div class="form-group col-2">
|
||||
<label for="asset_icon_compromised" class="mr-4">Preview</label>
|
||||
<div id="asset_icon_compromised">
|
||||
<img style="width:2em;height:2em" src="{{ assettype.asset_icon_compromised_path }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group col">
|
||||
<label for="asset_icon_compromised" class="mr-4">Asset Icon - compromised
|
||||
</label>
|
||||
{{ form.asset_icon_compromised(class='form-control',type='file', accept='.svg, .png') }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="form-group col">
|
||||
<label for="asset_icon_compromised" class="mr-4">Asset Icon - compromised
|
||||
</label>
|
||||
{{ form.asset_icon_compromised(class='form-control', type='file', required='false', value=assettype.asset_icon_compromised, accept='.svg, .png') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if assettype.asset_id %}
|
||||
<button type="button" class="btn btn-outline-danger mt-5"
|
||||
onclick="delete_asset_type('{{ assettype.asset_id }}');">Delete</button>
|
||||
<button type="submit" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_assettype">Update</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button type="submit" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_assettype">Save</button>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
@@ -0,0 +1,154 @@
|
||||
<div class="modal-header">
|
||||
<h4>Edit attribute {{ attribute.attribute_display_name }}</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_attribute" enctype="multipart/form-data">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="accordion accordion-primary">
|
||||
<h2>{{ attribute.attribute_display_name }} attributes</h2>
|
||||
<p>Attributes allow to extend the fields available for analysts when they add or edit {{ attribute.attribute_display_name }}.</p>
|
||||
<div class="alert-std alert-warning" role="alert">
|
||||
Attributes can be added by administrator in this UI, or they can be pushed by modules.<br/>
|
||||
This means each {{ attribute.attribute_display_name }} object may have a different set of attributes.
|
||||
Updating the default objects here will result in an update of every existing object, which might take a huge amount of time.
|
||||
<p>Typing wrong attributes here might result in UI breaks. IRIS will attempt to validate the attributes' taxonomy before committing.</p>
|
||||
<b>To avoid this, use the Preview button before saving. It displays a 1-to-1 UI representation of the attributes</b>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header collapsed" id="drop_attr_description" data-toggle="collapse" data-target="#drop_attr_desc" aria-expanded="false" aria-controls="drop_attr_desc" role="button">
|
||||
<div class="span-icon">
|
||||
<div class="flaticon-tea-cup"></div>
|
||||
</div>
|
||||
<div class="span-title">
|
||||
More details
|
||||
</div>
|
||||
<div class="span-mode"></div>
|
||||
</div>
|
||||
|
||||
<div id="drop_attr_desc" class="collapse" aria-labelledby="drop_tax_attr" style="">
|
||||
<div class="card-body">
|
||||
<p>These attributes are stored in each {{ attribute.attribute_display_name }} object in the form of a JSON structure.</p>
|
||||
<p>Attributes in this page represent the default attributes of each new {{ attribute.attribute_display_name }} objects. Existing object are updated if they
|
||||
don't hold the specified attributes. <b>Other existing attributes are not deleted.</b></p>
|
||||
Attributes can have the following purposes:
|
||||
<ul>
|
||||
<li><b>Inputs</b>: Offer analysts the possibility to fill additional details. Multiple types of inputs are supported. See taxonomy for more details</li>
|
||||
<li><b>Raw</b>: A static content rendered in raw text. HTML is not interpreted.</li>
|
||||
<li><b>HTML</b>: A static content rendered as HTML for infinite possibilities. <b>Careful, this is by nature prone to vulnerabilities.</b></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header collapsed" id="drop_attr_taxonomy" data-toggle="collapse" data-target="#drop_tax_attr" aria-expanded="false" aria-controls="drop_tax_attr" role="button">
|
||||
<div class="span-icon">
|
||||
<div class="flaticon-pencil"></div>
|
||||
</div>
|
||||
<div class="span-title">
|
||||
Attributes taxonomy
|
||||
</div>
|
||||
<div class="span-mode"></div>
|
||||
</div>
|
||||
|
||||
<div id="drop_tax_attr" class="collapse" aria-labelledby="drop_tax_attr" style="">
|
||||
<div class="card-body">
|
||||
Attributes are defined as below.
|
||||
<pre>
|
||||
{
|
||||
"Tab Name 1": { // Defines a new tab in the {{ attribute.attribute_display_name }} modal
|
||||
"Field 1": { // Defines a new field within the Tab Name 1
|
||||
"type": "input_string", // Defines the type of field, here a standard string input
|
||||
"mandatory": true, // Indicates whether the field is mandatory upon saving
|
||||
"value": "" // Default value if any, else empty
|
||||
},
|
||||
"Field 2": { // Defines a second field within the tab Tab Name 1
|
||||
"type": "input_checkbox", // Defines an input checkbox
|
||||
"mandatory": false, // Indicates whether the field is mandatory upon saving
|
||||
"value": true // Default value
|
||||
}
|
||||
},
|
||||
"VT report": { // Defines a second tab named VT report
|
||||
"Content": { // Defines a new field Content within the VT Report
|
||||
"type": "html", // Defines an HTML interpreted content
|
||||
"value": "" // Default value if any, else empty
|
||||
}
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h4>Field types</h4>
|
||||
The supported fields types are:
|
||||
<ul>
|
||||
<li>input_string: Standard input text</li>
|
||||
<li>input_textfield: Standard input textfield</li>
|
||||
<li>input_checkbox: Standard checkbox</li>
|
||||
<li>input_date: Standard date input</li>
|
||||
<li>input_datetime: Standard date and time input</li>
|
||||
<li>input_select: Standard select input. Need "options" tag to describe the available options</li>
|
||||
<li>raw: A static content rendered in raw text. HTML is not interpreted.</li>
|
||||
<li>html: A static content rendered as HTML. <b>Careful, this is by nature prone to vulnerabilities.</b></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header collapsed" id="drop_attr_over" data-toggle="collapse" data-target="#drop_attr_overwrite" aria-expanded="false" aria-controls="drop_attr_overwrite" role="button">
|
||||
<div class="span-icon">
|
||||
<div class="flaticon-exclamation"></div>
|
||||
</div>
|
||||
<div class="span-title">
|
||||
Overwrite features
|
||||
</div>
|
||||
<div class="span-mode"></div>
|
||||
</div>
|
||||
|
||||
<div id="drop_attr_overwrite" class="collapse" aria-labelledby="drop_tax_attr" style="">
|
||||
<div class="card-body">
|
||||
<p>Changing types of fields in attributes might result in incompatibles types and existing objects being unable to be migrated.</p>
|
||||
<p>When this happens, IRIS will not update the fields of these objects and let them as is to prevent any data loss.</p>
|
||||
<p>This behavior can however be changed by using the <kbd>Complete overwrite</kbd> and <kbd>Partial overwrite</kbd> buttons.</p>
|
||||
|
||||
<p><kbd>Partial overwrite</kbd> basically resets the attributes values of every {{ attribute.attribute_display_name }} objects that matches the current ones, and then applies the current attributes.
|
||||
All associated values are lost. This does not impact attributes pushed by modules.</p>
|
||||
<p><kbd>Complete overwrite</kbd> resets all attributes of every {{ attribute.attribute_display_name }} objects, including the ones created by modules, and then applies the current attributes.
|
||||
All associated values are lost.</p>
|
||||
|
||||
<b>In any case, none of the native values of the {{ attribute.attribute_display_name }} objects are modified. This only concerns custom attributes.</b>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
<label for="Attribute content" class="mr-4">Attribute definition
|
||||
</label>
|
||||
<div id="editor_detail">{{ attribute.attribute_content|tojsonsafe }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="alert alert-warning" style="display:none;" role="alert" id="alert_attributes_details">
|
||||
<span id="alert_attributes_edit"></span><br/>
|
||||
<b>Logs:</b>
|
||||
<ul id="attributes_err_details_list">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-danger float-right" id="submit_complete_overwrite">Complete overwrite</button>
|
||||
<button type="button" class="btn btn-outline-danger mr-auto" id="submit_partial_overwrite">Partial overwrite</button>
|
||||
<button type="button" class="btn btn-outline-black float-right" id="preview_attribute">Preview</button>
|
||||
<button type="button" class="btn btn-outline-success float-right" id="submit_new_attribute">Update</button>
|
||||
</div>
|
@@ -0,0 +1,72 @@
|
||||
<div class="modal-header">
|
||||
<div class="col md-12">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h4 class="modal-title mt-1 mr-4">{% if customer.client_id %}Edit customer #{{ customer.client_id }}{% else %}Add customer{% endif %}</h4>
|
||||
<small><a class="text-muted">{% if customer.client_uuid %}#{{ customer.client_uuid }}{% endif %}</a></small>
|
||||
</div>
|
||||
{% include 'modals/modal_attributes_nav.html' %}
|
||||
<div class="col ">
|
||||
<div class="row float-right">
|
||||
<button type="button" class="pull-right btn bg-transparent" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div role="tabpanel">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="details">
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_customer" enctype="multipart/form-data">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
<label for="customer" class="mr-4">Name *</label>
|
||||
{{ form.customer_name(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="description" class="mr-4">Description</label>
|
||||
{{ form.customer_description(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="sla" class="mr-4">SLAs</label>
|
||||
{{ form.customer_sla(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'modals/modal_attributes_tabs.html' %}
|
||||
</div>
|
||||
{% if customer.client_id %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-danger mt-5"
|
||||
onclick="delete_customer('{{ customer.client_id }}');"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_customer"
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_customer"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,49 @@
|
||||
<div class="modal-header">
|
||||
<h4>Add IOC Type</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_ioc_type" enctype="multipart/form-data">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
<label for="type_name" class="mr-4">Type name
|
||||
</label>
|
||||
{{ form.type_name(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="type_description" class="placeholder">Type description</label>
|
||||
{{ form.type_description(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="type_taxonomy" class="placeholder">Type taxonomy</label>
|
||||
{{ form.type_taxonomy(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="type_description" class="placeholder">Type validation regex</label>
|
||||
{{ form.type_validation_regex(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="type_description" class="placeholder">Type validation expect explanation</label>
|
||||
{{ form.type_validation_expect(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
|
||||
{% if ioc_type.type_id %}
|
||||
<button type="button" class="btn btn-outline-danger mt-5"
|
||||
onclick="delete_ioc_type('{{ ioc_type.type_id }}');">Delete</button>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_ioc_type">Update</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_ioc_type">Save</button>
|
||||
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
@@ -0,0 +1,40 @@
|
||||
<div class="modal-header">
|
||||
<h4>Add Module</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_module">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
|
||||
<div class="form-group">
|
||||
<h3>Module extensions</h3>
|
||||
<p>Iris can be extended with compatible modules. Modules are pip packages providing a specific interface which allows
|
||||
Iris and the module to communicate. Enter below a pip package name already installed.</p>
|
||||
<p>Ex: iris_evtx</p>
|
||||
<i class="">Tips: you can develop your own module by following <a target=”_blank” href="https://docs.dfir-iris.org/development/modules/" >this link</a></i>
|
||||
<div class="mt-4">
|
||||
<strong class="text-danger">Note :</strong> Modules are running as the same trust level as Iris. They can thus access all the information
|
||||
stored on Iris as well as run code on the server. Please be cautious and review modules before installing them.
|
||||
</div>
|
||||
<label for="module_name" class="mr-4 mt-3">Module name</label>
|
||||
{{ form.module_name(class='form-control', autocomplete="off") }}
|
||||
<div class="alert-std alert-warning" style="display:none;" role="alert" id="alert_mod_add">
|
||||
</div>
|
||||
<div class="alert-std alert-warning" style="display:none;" role="alert" id="alert_mod_details">
|
||||
<b>Logs</b>
|
||||
<ul id="details_list">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_module">Validate module</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
@@ -0,0 +1,75 @@
|
||||
<div class="modal-header">
|
||||
<h4>Add Report Template</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_report_template" enctype="multipart/form-data">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group mt-3">
|
||||
<label for="report_name" class="placeholder">Template name</label>
|
||||
{{ form.report_name(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="report_type" class="mr-4">Template type
|
||||
</label>
|
||||
{{ form.report_type(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<label for="report_language" class="mr-4">Template language
|
||||
</label>
|
||||
{{ form.report_language(class="selectpicker pl--6 col-md-12") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="report_description" class="placeholder">Template description</label>
|
||||
{{ form.report_description(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group ml--2">
|
||||
{{ form.report_language(class="selectpicker pl--6") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="report_name_format" class="placeholder">Template name format</label>
|
||||
<br/>This is the name of the generated report file. Do not input extension.
|
||||
Available tags:
|
||||
<ul>
|
||||
<li>%date% : date of generation</li>
|
||||
<li>%customer% : customer name</li>
|
||||
<li>%case_name% : name of the case</li>
|
||||
<li>%code_name%: autogenerated enterprise code name</li>
|
||||
</ul>
|
||||
Example: <i>analysis_%customer%_%date%</i>
|
||||
|
||||
{{ form.report_name_format(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="report_name_format" class="placeholder">Template file : </label>
|
||||
<input type=file name=file>
|
||||
</div>
|
||||
|
||||
{% if report_template.asset_id %}
|
||||
<button type="button" class="btn btn-outline-danger mt-5"
|
||||
onclick="delete_report_template('{{ assettype.asset_id }}');">Delete</button>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_report_template">Update</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button type="submit" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_report_template">Save</button>
|
||||
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
@@ -0,0 +1,42 @@
|
||||
<div class="modal-header">
|
||||
<h4>Case classification</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_case_classification" enctype="multipart/form-data">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
<label for="name" class="mr-4">Classification name
|
||||
</label>
|
||||
{{ form.name(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="name_expanded" class="placeholder">Classification expanded name</label>
|
||||
{{ form.name_expanded(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="description" class="placeholder">Classification description</label>
|
||||
{{ form.description(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
|
||||
{% if case_classification.id %}
|
||||
<button type="button" class="btn btn-outline-danger mt-5"
|
||||
onclick="delete_case_classification('{{ case_classification.id }}');">Delete</button>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_case_classification">Update</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_case_classification">Save</button>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
@@ -0,0 +1,421 @@
|
||||
{% set attributes = data.custom_attributes %}
|
||||
<div class="modal-header">
|
||||
<div class="col md-12">
|
||||
<div class="row">
|
||||
<div class="col align-self-center">
|
||||
<h4 class="modal-title mr-4">{{ data.case_name|unquote }}
|
||||
{% if data.modification_history %}
|
||||
<i class="fa-solid fa-clock-rotate-left ml-3 mt-2" data-toggle="popover" data-html="true" id="pop_history" style="cursor: pointer;"
|
||||
title="Modifications history"
|
||||
data-content="<small>{% for mod in data.modification_history %}<code>{{ mod|format_datetime('%Y-%m-%d %H:%M') }}</code> - {{ data.modification_history[mod].action }} by {{ data.modification_history[mod].user }}<br/>{% endfor %}</small>">
|
||||
</i>
|
||||
{% endif %}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="row text-center">
|
||||
<ul class="nav nav-pills nav-default mr-4" id="pills-tab-custom-attr" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active show" id="pills-home-tab-nobd" data-toggle="pill" href="#details" role="tab" aria-controls="pills-home-nobd" aria-selected="false">Info</a>
|
||||
</li>
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link" data-toggle="pill" href="#case-info-access" role="tab" aria-controls="case-info-access" aria-selected="false">Access</a>
|
||||
</li>
|
||||
{% if attributes and attributes|length > 0 %}
|
||||
{% for ca in attributes %}
|
||||
<li class="nav-item submenu">
|
||||
<a class="nav-link" data-toggle="pill" href="#{{page_uid}}{{ loop.index }}_{{ ca.lower() | replace(' ', '_' ) }}" role="tab" aria-controls="{{page_uid}}{{ loop.index }}_{{ ca.lower() | replace(' ', '_' ) }}" aria-selected="false">{{ca}}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col ">
|
||||
<div class="row float-right">
|
||||
<button type="button" class="float-right btn bg-transparent" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container col-md-12">
|
||||
<div role="tabpanel">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="details">
|
||||
<div id="case_gen_info_content">
|
||||
<h4>General info <button class="ml-2 btn btn-sm float-right" onclick="edit_case_info();">Edit</button></h4>
|
||||
<div class="row">
|
||||
<div class="col-6 col-xs-12 col-md-6">
|
||||
<div class="form-group">
|
||||
<label>Case name :</label>
|
||||
<span type="text" class="">{{ data.case_name|unquote }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Case description :</label>
|
||||
<span type="text" class="">{{ data.case_description[0:50] }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Customer :</label>
|
||||
<span type="text" class="text-faded">{{ data.customer_name }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Case tags :</label>
|
||||
<span type="text" class="text-faded">{% if data.case_tags %} {% for tag in data.case_tags.split(',') %}
|
||||
<span class="badge badge-pill badge-light ml-1"><i class="fa fa-tag mr-1"></i>{{ tag }}</span> {% endfor %}{% endif %}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>SOC ID :</label>
|
||||
<span type="text" class="text-faded">{{ data.case_soc_id }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Case ID :</label>
|
||||
<span type="text" class="text-faded">{{ data.case_id }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Case UUID :</label>
|
||||
<span type="text" class="text-faded">{{ data.case_uuid }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 col-xs-12 col-md-6">
|
||||
<div class="form-group mt--3">
|
||||
<label>Classification :</label>
|
||||
{% if data.classification %}
|
||||
<span type="text" class="text-faded">{{ data.classification }}</span>
|
||||
{% else %}
|
||||
<span type="text" class="text-faded">Unknown</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>State :</label>
|
||||
<span type="text" class="text-faded">{{ data.state_name }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Open date :</label>
|
||||
<span type="text" class="">{{ data.open_date }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Opening user :</label>
|
||||
<span type="text" class="">{{ data.open_by_user }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Owner :</label>
|
||||
<span type="text" class="">{{ data.owner }}</span>
|
||||
</div>
|
||||
{% if data.reviewer %}
|
||||
<div class="form-group mt--3">
|
||||
<label>Reviewer :</label>
|
||||
<span type="text" class="">{{ data.reviewer }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if data.review_status %}
|
||||
<div class="form-group mt--3">
|
||||
<label>Reviewer :</label>
|
||||
<span type="text" class="">{{ data.review_status.status_name }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if data.close_date %}
|
||||
<div class="form-group mt--3">
|
||||
<label>Close date :</label>
|
||||
<span type="text" class="">{{ data.close_date }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if protagonists %}
|
||||
{% for protagonist in protagonists %}
|
||||
<div class="form-group mt--3">
|
||||
<label>{{ protagonist.role }}: </label>
|
||||
<span type="text" class="">{{ protagonist.name }} ({{protagonist.contact}})</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="case_gen_info_edit" style="display:none;">
|
||||
<form method="post" action='' id="form_update_case" autocomplete="off">
|
||||
<h4 class=" pb-3">Edit case information</h4>
|
||||
<div class="col-12">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="mt-4">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-6">
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">Case name <i class="ml-2">{{"#{} - ".format(data.case_id)}}</i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="case_name" value="{{ data.case_name.replace('#{} - '.format(data.case_id), '')}}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-6">
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">SOC ticket ID</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="case_soc_id" value="{{ data.case_soc_id }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-6">
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend fix-label-item">
|
||||
<span class="input-group-text">Classification</span>
|
||||
</div>
|
||||
<select class="selectpicker form-control"
|
||||
id="case_quick_classification" name="classification_id">
|
||||
{% for clc in case_classifications %}
|
||||
<option value="{{ clc.id }}" {% if data.classification_id == clc.id %}selected{% endif %} class="badge-text">{{ clc.name_expanded }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-6">
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend fix-label-item">
|
||||
<span class="input-group-text">Owner</span>
|
||||
</div>
|
||||
<select class="selectpicker form-control"
|
||||
id="case_quick_owner" name="owner_id">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-6">
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend fix-label-item">
|
||||
<span class="input-group-text">State</span>
|
||||
</div>
|
||||
<select class="selectpicker form-control"
|
||||
id="case_state" name="state_id">
|
||||
{% for clc in case_states %}
|
||||
<option value="{{ clc.state_id }}" {% if data.state_id == clc.state_id %}selected{% endif %} class="badge-text">{{ clc.state_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-6">
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend fix-label-item">
|
||||
<span class="input-group-text">Outcome</span>
|
||||
</div>
|
||||
<select class="form-control selectpicker"
|
||||
id="case_quick_status" name="status_id">
|
||||
<option value="0" {% if data.status_id == 0 %}selected{% endif %} class="badge-text">Unknown</option>
|
||||
<option value="1" {% if data.status_id == 1 %}selected{% endif %} class="badge-text">False Positive</option>
|
||||
<option value="2" {% if data.status_id == 2 %}selected{% endif %} class="badge-text">True Positive with impact</option>
|
||||
<option value="4" {% if data.status_id == 4 %}selected{% endif %} class="badge-text">True Positive without impact</option>
|
||||
<option value="3" {% if data.status_id == 3 %}selected{% endif %} class="badge-text">Not applicable</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-6">
|
||||
<div class="input-group mb-2">
|
||||
<div class="input-group-prepend fix-label-item">
|
||||
<span class="input-group-text">Customer</span>
|
||||
</div>
|
||||
<select class="selectpicker form-control"
|
||||
id="case_quick_customer" name="case_customer">
|
||||
{% for cst in customers %}
|
||||
<option value="{{ cst.customer_id }}" {% if data.customer_id == cst.customer_id %}selected{% endif %} class="badge-text">{{ cst.customer_name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-6">
|
||||
<div class="input-group mb-4">
|
||||
<div class="input-group-prepend fix-label-item">
|
||||
<span class="input-group-text">Reviewer</span>
|
||||
</div>
|
||||
<select class="selectpicker form-control"
|
||||
id="case_quick_reviewer" name="reviewer_id">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group px-0">
|
||||
<label for="asset_tags">Case tags
|
||||
</label>
|
||||
<input type="text" id="case_tags"
|
||||
class="form-control col-md-12" {% if data.case_tags %} value="{{ data.case_tags }}" {% endif %}/>
|
||||
</div>
|
||||
<div class="form-group px-4 py-4 mt-3" id="protagonists_form_group">
|
||||
{% if protagonists %}
|
||||
<label>Protagonists
|
||||
</label>
|
||||
{% for iprota in protagonists %}
|
||||
<div class="input-group mb-2 mt-2" id="protagonist_{{loop.index}}">
|
||||
<div class="col-6">
|
||||
<h6># {{loop.index}}</h6>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="ingrole_{{loop.index}}">Role</span>
|
||||
</div>
|
||||
<input type="text" aria-describedby="ingrole_{{loop.index}}" list="roles-list" class="form-control" name="protagonist_role_{{loop.index}}" value="{{ iprota.role }}" placeholder="Role">
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="ingname_{{loop.index}}">Name</span>
|
||||
</div>
|
||||
<input type="text" aria-describedby="ingname_{{loop.index}}" class="form-control" name="protagonist_name_{{loop.index}}" placeholder="Name" list="username-list" value="{{ iprota.name }}">
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="ingp_{{loop.index}}">Contact</span>
|
||||
</div>
|
||||
<input type="text" aria-describedby="ingp_{{loop.index}}" class="form-control" name="protagonist_contact_{{loop.index}}" value="{{ iprota.contact }}" placeholder="Contact" list="emails-list">
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-dark mr-2 mt-1" onclick="remove_protagonist('{{loop.index}}');">
|
||||
Remove
|
||||
</button>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div id="protagonist_list_edit">
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-dark mt-2 mr-2" id="add_protagonist_btn" onclick="add_protagonist();">Add protagonist</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane" id="case-info-access">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card-title">Case access</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="btn btn-dark btn-sm ml-3 float-right" onclick="access_case_info_reload('{{ data.case_id }}');">Refresh</button>
|
||||
<button class="btn btn-dark btn-sm ml-2 float-right" onclick="view_case_access_via_group('{{ data.case_id }}');">Set access via group</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col">
|
||||
<table class="table display table-striped table-hover responsive" width="100%" cellspacing="0" id="case_access_users_list_table" >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User ID</th>
|
||||
<th>User Name</th>
|
||||
<th>User Login</th>
|
||||
<th>User Access</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th>User ID</th>
|
||||
<th>User Name</th>
|
||||
<th>User Login</th>
|
||||
<th>User Access</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'modals/modal_attributes_tabs.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="protagonist_list_edit_template" style="display:none;">
|
||||
<div class="input-group mb-2 mt-2" id="protagonist___PROTAGONIST_ID__">
|
||||
<div class="col-6">
|
||||
<h5>Protagonist</h5>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="ingrole___PROTAGONIST_ID__">Role</span>
|
||||
</div>
|
||||
<input type="text" aria-describedby="ingrole___PROTAGONIST_ID__" list="roles-list" class="form-control" name="protagonist_role___PROTAGONIST_ID__" value="" placeholder="Role">
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="ingname___PROTAGONIST_ID__">Name</span>
|
||||
</div>
|
||||
<input type="text" aria-describedby="ingname___PROTAGONIST_ID__" class="form-control" name="protagonist_name___PROTAGONIST_ID__" placeholder="Name" list="username-list" value="">
|
||||
</div>
|
||||
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="ingp___PROTAGONIST_ID__">Contact</span>
|
||||
</div>
|
||||
<input type="text" aria-describedby="ingp___PROTAGONIST_ID__" class="form-control" name="protagonist_contact___PROTAGONIST_ID__" value="" list="emails-list" placeholder="Contact">
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-dark mr-2 mt-1" onclick="remove_protagonist('__PROTAGONIST_ID__');">
|
||||
Remove
|
||||
</button>
|
||||
<hr/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<datalist id="roles-list">
|
||||
<option value="Analyst">
|
||||
<option value="Lead">
|
||||
<option value="Communication">
|
||||
<option value="Customer contact">
|
||||
</datalist>
|
||||
|
||||
<datalist id="username-list">
|
||||
</datalist>
|
||||
<datalist id="emails-list">
|
||||
</datalist>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-danger " onclick="remove_case('{{ data.case_id }}');"
|
||||
id="delete_case_info">Delete case</button>
|
||||
|
||||
{% if not data.close_date %}
|
||||
<button type="button" class="btn btn-outline-warning mr-auto" onclick="close_case('{{ data.case_id }}');"
|
||||
id="close_case_info">Close case</button>
|
||||
{% else %}
|
||||
<button type="button" class="btn btn-success" onclick="reopen_case('{{ data.case_id }}');"
|
||||
id="reopen_case_info">Reopen case</button>
|
||||
{% endif %}
|
||||
<button type="button" class="btn btn-outline-dark mr-2" style="display:none;" id="cancel_case_info" onclick="cancel_case_edit();">Cancel</button>
|
||||
<button type="button" class="btn btn-outline-success mr-2" style="display:none;" id="save_case_info" onclick="save_case_edit({{ data.case_id }});">Save</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$('[data-toggle="popover"]').popover();
|
||||
$('#case_quick_classification').selectpicker({
|
||||
liveSearch: true,
|
||||
title: "Classification",
|
||||
style: "btn-outline-white"
|
||||
});
|
||||
$('#case_quick_owner').selectpicker({
|
||||
liveSearch: true,
|
||||
title: "Owner",
|
||||
style: "btn-outline-white"
|
||||
});
|
||||
$('#case_quick_reviewer').selectpicker({
|
||||
liveSearch: true,
|
||||
title: "Reviewer",
|
||||
style: "btn-outline-white"
|
||||
});
|
||||
$('#case_state').selectpicker({
|
||||
liveSearch: true,
|
||||
title: "Case state",
|
||||
style: "btn-outline-white"
|
||||
});
|
||||
$('#case_quick_status').selectpicker({
|
||||
liveSearch: true,
|
||||
title: "Outcome",
|
||||
style: "btn-outline-white"
|
||||
});
|
||||
$('#case_quick_customer').selectpicker({
|
||||
liveSearch: true,
|
||||
title: "Customer",
|
||||
style: "btn-outline-white"
|
||||
});
|
||||
|
||||
access_case_info_reload('{{ data.case_id }}', '{{ data.owner_id }}', '{{ data.reviewer_id }}');
|
||||
</script>
|
@@ -0,0 +1,42 @@
|
||||
<div class="modal-header">
|
||||
<h4>Case state</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_case_state" enctype="multipart/form-data">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
<label for="name" class="mr-4">State name
|
||||
</label>
|
||||
{{ form.state_name(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
<label for="description" class="placeholder">State description</label>
|
||||
{{ form.state_description(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
|
||||
{% if not case_state.protected %}
|
||||
{% if case_state.state_id %}
|
||||
<button type="button" class="btn btn-outline-danger mt-5"
|
||||
onclick="delete_case_state('{{ case_state.state_id }}');">Delete</button>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_case_state">Update</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_case_state">Save</button>
|
||||
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<i class="fa fa-lock mt-4 mr-2 ml-3 text-danger mb-4" aria-hidden="true"></i> This state is protected and cannot be deleted or updated.
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
@@ -0,0 +1,177 @@
|
||||
<div class="modal-header">
|
||||
{% if case_template.id %}
|
||||
<h4>Edit case template {{ case_template.display_name }}</h4>
|
||||
{% else %}
|
||||
<h4>Add case template</h4>
|
||||
{% endif %}
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_case_template" enctype="multipart/form-data">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="accordion accordion-primary">
|
||||
{% if case_template.id %}
|
||||
<h2>{{ case_template.display_name }} template</h2>
|
||||
{% else %}
|
||||
<h2>New template</h2>
|
||||
{% endif %}
|
||||
<p>Case templates allow to prefill case objects such as tasks, tags, and notes.<br/>
|
||||
It can be used to add procedures defining how to react against a specific kind of incident (phishing, ransomware, APT...)</p>
|
||||
<div class="alert-std alert-warning" role="alert">
|
||||
Case templates can be added and edited in this UI, or they can be uploaded as JSON files.<br/>
|
||||
<p>IRIS will attempt to validate the contents of the case template before committing.</p>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header collapsed" id="drop_case_template_taxonomy" data-toggle="collapse" data-target="#drop_tax_case_template" aria-expanded="false" aria-controls="drop_tax_attr" role="button">
|
||||
<div class="span-icon">
|
||||
<div class="flaticon-pencil"></div>
|
||||
</div>
|
||||
<div class="span-title">
|
||||
Case Template taxonomy
|
||||
</div>
|
||||
<div class="span-mode"></div>
|
||||
</div>
|
||||
<div id="drop_tax_case_template" class="collapse" aria-labelledby="drop_tax_case_template" style="">
|
||||
<div class="card-body">
|
||||
<h4>Field types</h4>
|
||||
The supported fields types are:
|
||||
<ul>
|
||||
<li>name: The name of the case template (required).</li>
|
||||
<li>display_name: The displayed name of the case template.</li>
|
||||
<li>description: The description of the case template.</li>
|
||||
<li>author: The author of the case template (not related to the current user).</li>
|
||||
<li>classification: The classification of the case template. Should be a lowercase name matching an existing classification in IRIS.</li>
|
||||
<li>title_prefix: A prefix to add to case title.</li>
|
||||
<li>summary: content to prefill the summary.</li>
|
||||
<li>tags: A list of case tags.</li>
|
||||
<li>tasks: A list of dictionaries defining tasks. Tasks are defined by title (required), description, and list of tags.</li>
|
||||
<li>note_groups: A list of dictionaries defining note groups. Note groups are defined by title (required), and list of notes. Notes have title (required) and content</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mt-4">
|
||||
<div class="card-header collapsed" id="drop__template_example" data-toggle="collapse" data-target="#drop_case_template_example" aria-expanded="false" aria-controls="drop_tax_attr" role="button">
|
||||
<div class="span-icon">
|
||||
<div class="flaticon-pencil"></div>
|
||||
</div>
|
||||
<div class="span-title">
|
||||
Case Template Example
|
||||
</div>
|
||||
<div class="span-mode"></div>
|
||||
</div>
|
||||
<div id="drop_case_template_example" class="collapse" aria-labelledby="drop_tax_case_template" style="">
|
||||
<div class="card-body">
|
||||
A case template is defined as below.
|
||||
<pre>
|
||||
|
||||
{
|
||||
"name": "ransomware_infection",
|
||||
"display_name": "Ransomware Infection Template",
|
||||
"description": "This case template describes first-response tasks to handle information system compromised by a ransomware.",
|
||||
"author": "DFIR-IRIS",
|
||||
"classification": "malicious-code:ransomware",
|
||||
"title_prefix": "[RANS]",
|
||||
"summary": "# Context \n\n\n# Contact \n\n\n# Actions \n\n\n",
|
||||
"tags": ["ransomware","malware"],
|
||||
"tasks": [
|
||||
{
|
||||
"title": "Identify the perimeter",
|
||||
"description": "The perimeter of compromise must be identified",
|
||||
"tags": ["identify"]
|
||||
},
|
||||
{
|
||||
"title": "Collect compromised hosts",
|
||||
"description": "Deploy Velociraptor and start collecting evidence",
|
||||
"tags": ["collect", "velociraptor"]
|
||||
},
|
||||
{
|
||||
"title": "Containment"
|
||||
}
|
||||
],
|
||||
"note_groups": [
|
||||
{
|
||||
"title": "Identify",
|
||||
"notes": [
|
||||
{
|
||||
"title": "Identify the compromised accounts",
|
||||
"content": "# Observations\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Collect",
|
||||
"notes": [
|
||||
{
|
||||
"title": "Velociraptor deployment"
|
||||
},
|
||||
{
|
||||
"title": "Assets collected",
|
||||
"content": "# Assets collected\n\n# Assets not collected"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
<div class="row">
|
||||
<label for="editor_detail" class="mr-4">Case template definition
|
||||
</label><button type="button" class="btn btn-sm ml-auto" onclick="downloadCaseTemplateDefinition();">Download definition</button>
|
||||
</div>
|
||||
<div id="editor_detail">{{ form.case_template_json.data|tojsonsafe }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="alert alert-warning" style="display:none;" role="alert" id="alert_case_template_details">
|
||||
<span id="alert_case_template_edit"></span><br/>
|
||||
<b>Logs:</b>
|
||||
<ul id="case_template_err_details_list">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
{% if case_template.id %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-danger mr-auto"
|
||||
id="submit_delete_case_template"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-success ml-4 float-right"
|
||||
id="submit_new_case_template"
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-success ml-4 float-right"
|
||||
id="submit_new_case_template"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@@ -0,0 +1,101 @@
|
||||
<div class="modal-header">
|
||||
<div class="col md-12">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h4 class="modal-title mt-2 mr-4">{% if contact.id %}Edit contact #{{ contact.id }}{% else %}Add contact{% endif %}</h4>
|
||||
<small><a class="text-muted">{% if contact.contact_uuid %}#{{ contact.contact_uuid }}{% endif %}</a></small>
|
||||
</div>
|
||||
<div class="col ">
|
||||
<div class="row float-right">
|
||||
<button type="button" class="pull-right btn bg-transparent" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div role="tabpanel">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="details">
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_new_contact" enctype="multipart/form-data">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group row">
|
||||
<label for="contact_name" class="col-lg-3 col-md-3 col-sm-4 mt-sm-2 text-right">Contact name *</label>
|
||||
<div class="col-lg-8 col-md-9 col-sm-8">
|
||||
{{ form.contact_name(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="contact_role" class="col-lg-3 col-md-3 col-sm-4 mt-sm-2 text-right">Contact Role</label>
|
||||
<div class="col-lg-8 col-md-9 col-sm-8">
|
||||
{{ form.contact_role(class='form-control', autocomplete="off", list="contact_roles_list") }}
|
||||
</div>
|
||||
<datalist id="contact_roles_list">
|
||||
<option value="CISO">
|
||||
<option value="CEO">
|
||||
<option value="Manager">
|
||||
<option value="Sales">
|
||||
<option value="Support">
|
||||
<option value="Billing">
|
||||
<option value="Other">
|
||||
</datalist>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="email" class="col-lg-3 col-md-3 col-sm-4 mt-sm-2 text-right">Contact email</label>
|
||||
<div class="col-lg-8 col-md-9 col-sm-8">
|
||||
{{ form.contact_email(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="work_phone" class="col-lg-3 col-md-3 col-sm-4 mt-sm-2 text-right">Contact work phone</label>
|
||||
<div class="col-lg-8 col-md-9 col-sm-8">
|
||||
{{ form.contact_work_phone(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="mobile_phone" class="col-lg-3 col-md-3 col-sm-4 mt-sm-2 text-right">Contact mobile phone</label>
|
||||
<div class="col-lg-8 col-md-9 col-sm-8">
|
||||
{{ form.contact_mobile_phone(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="notes" class="col-lg-3 col-md-3 col-sm-4 mt-sm-2 text-right">Additional notes</label>
|
||||
<div class="col-lg-8 col-md-9 col-sm-8">
|
||||
{{ form.contact_note(class='form-control', autocomplete="off") }}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if contact.id %}
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-danger mt-5"
|
||||
id="submit_delete_contact"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_contact"
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
|
||||
{% else %}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_new_contact"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,130 @@
|
||||
<div class="modal-header">
|
||||
<h4>{{ data.module_human_name|unquote }} - Module Information</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="container col-6">
|
||||
<div class="form-group">
|
||||
<label>Name :</label>
|
||||
<span type="text" class="">{{ data.module_human_name|unquote }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Description :</label>
|
||||
<span type="text" class="">{{ data.module_description }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Target package :</label>
|
||||
<span type="text" class="text-faded">{{ data.module_name }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Date added :</label>
|
||||
<span type="text" class="text-faded">{{ data.date_added }}</span>
|
||||
</div>
|
||||
{% if not is_configured %}
|
||||
<div class="form-group">
|
||||
<b class="text-danger">The module was automatically disabled because mandatory parameters are not set.</b>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="container col-6">
|
||||
<div class="form-group">
|
||||
<label>Module version :</label>
|
||||
<span type="text" class="text-faded">{{ data.module_version }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Interface version :</label>
|
||||
<span type="text" class="text-faded">{{ data.interface_version }}</span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Is active :</label>
|
||||
<span type="text" class="text-faded">{{ data.is_active }} </span>
|
||||
</div>
|
||||
<div class="form-group mt--3">
|
||||
<label>Provides pipeline :</label>
|
||||
<span type="text" class="text-faded">{{ data.has_pipeline }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="container col-12">
|
||||
<hr/>
|
||||
<div class="form-group mt-3">
|
||||
<label>Configuration (click on a setting to edit)</label>
|
||||
<button type="button" class="btn btn-sm btn-outline-dark float-right" onclick="export_mod_config('{{ data.id }}');">Export configuration</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-dark float-right mr-2" data-toggle="modal" data-target="#modal_input_config">Import configuration</button>
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
|
||||
<table id="datatable_db_list" class="table display table-bordered table-striped table-hover mt-4" width="100%"
|
||||
cellspacing="0">
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th>Section</th>
|
||||
<th>Parameter</th>
|
||||
<th>Value</th>
|
||||
<th>Mandatory</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for id in config %}
|
||||
<tr role="row">
|
||||
<td>{{ id["section"] or "Main" }}</td>
|
||||
<td><a href="#" onclick="update_param({{ data.id }}, '{{ data.id }}##{{ id['param_name'] }}');">
|
||||
{% if (id['param_name'] in missing_params) %}
|
||||
<i class="fa-solid fa-triangle-exclamation text-danger" title="Mandatory parameter not set"></i>
|
||||
{% endif %}
|
||||
{{ id["param_human_name"] }}
|
||||
</a></td>
|
||||
<td>{% if id["value"] is not none %}{% if id["type"] != "sensitive_string" %} {% if id["value"] is string %}{{ id["value"][0:20] }}{% else %}{{id["value"]}}{% endif %} {% else %} *************** {% endif %}{% endif %}</td>
|
||||
<td>{{ id["mandatory"] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-danger mr-auto" onclick="remove_module('{{ data.id }}');">Remove module</button>
|
||||
{% if is_configured and not data.is_active %}
|
||||
<button type="button" class="btn btn-outline-success" onclick="enable_module('{{ data.id }}');">Enable module</button>
|
||||
{% elif is_configured and data.is_active %}
|
||||
<button type="button" class="btn btn-outline-warning" onclick="disable_module('{{ data.id }}');">Disable module</button>
|
||||
{% endif %}
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Dismiss</button>
|
||||
</div>
|
||||
|
||||
<div class="modal bg-shadow-gradient" tabindex="-1" role="dialog" id="modal_input_config" data-backdrop="true">
|
||||
<div class="modal-lg modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5>Import module configuration from file</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<p>Select a configuration file to upload. Existing configuration for this module will be overwritten.</p>
|
||||
<label class="placeholder">Configuration file : </label>
|
||||
<input id="input_configuration_file" type="file" accept="text/json">
|
||||
<button type="button" class="btn btn-outline-success float-right mr-2" onclick="import_mod_config('{{ data.id }}');">Import</button>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("#datatable_db_list").DataTable({
|
||||
filter: true,
|
||||
order: [[0, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 0
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
@@ -0,0 +1,22 @@
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-1">Attribute preview
|
||||
</h4>
|
||||
{% include 'modals/modal_attributes_nav.html' %}
|
||||
<div class="row text-right">
|
||||
<button type="button" class="pull-right btn btn-white" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div role="tabpanel">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active text-center" id="details">
|
||||
<h2>Base object information</h2>
|
||||
<b>This is for preview purpose only. Standard object information will be rendered here.</b><br/>
|
||||
Don't mind the background, it's for preview also
|
||||
</div>
|
||||
|
||||
{% include 'modals/modal_attributes_tabs.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@@ -0,0 +1,21 @@
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title mt-2 mr-4">Server Updates</h4>
|
||||
<button type="button" class="pull-right btn btn-white" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true"><i class="fa fa-times"></i></span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container col-md-12">
|
||||
<div class="col-md-12" id="updates_content_md">
|
||||
{{ updates_content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Dismiss</button>
|
||||
|
||||
{% if has_updates %}
|
||||
<a type="button" class="btn btn-success" href="/manage/server/make-update?cid={{session['current_case'].case_id}}">Update server</a>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
@@ -0,0 +1,74 @@
|
||||
<div class="modal-header">
|
||||
<h4>Update {{ parameter["param_human_name"] }} of {{ mod_name }} </h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_update_param">
|
||||
<div class="col-md-12 col-lg-12 col-sm-12">
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="form-group">
|
||||
<b>Description :</b> {{ parameter["param_description"] }}<br/>
|
||||
<b>Default :</b> {{ parameter["default"] }} <br/>
|
||||
<b>Mandatory :</b> {{ parameter["mandatory"] }}<br/>
|
||||
<b>Expected type :</b> {{ parameter["type"] }}<br/>
|
||||
</div>
|
||||
<div class="form-group mt-3">
|
||||
|
||||
|
||||
{% if parameter["type"].startswith("textfield_") %}
|
||||
<label class="placeholder"><b>Value</b></label>
|
||||
<div id="editor_detail">{{ parameter["value"] }}</div>
|
||||
{% elif parameter["type"] == 'bool' %}
|
||||
<div class="form-check">
|
||||
<label class="form-check-label">
|
||||
<input type="checkbox" id="parameter_value"
|
||||
class="form-control"
|
||||
{% if parameter["value"] == True %} checked {% endif %}
|
||||
/>
|
||||
<span class="form-check-sign">Check to set to true</span>
|
||||
</label>
|
||||
</div>
|
||||
{% else %}
|
||||
<label class="placeholder"><b>Value</b></label>
|
||||
<input class="form-control required" name="parameter_value" type="text" value="{{ parameter["value"] }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
<button type="button" class="btn btn-outline-success ml-4 mt-5 float-right"
|
||||
id="submit_save_parameter">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
if ($('#editor_detail').length != 0) {
|
||||
var editor = ace.edit("editor_detail",
|
||||
{
|
||||
autoScrollEditorIntoView: true,
|
||||
minLines: 30,
|
||||
});
|
||||
editor.setTheme("ace/theme/tomorrow");
|
||||
|
||||
{% if parameter["type"].endswith("json") %}
|
||||
editor.session.setMode("ace/mode/json");
|
||||
{% elif parameter["type"].endswith("html") %}
|
||||
editor.session.setMode("ace/mode/html");
|
||||
{% elif parameter["type"].endswith("markdown") %}
|
||||
editor.session.setMode("ace/mode/markdown");
|
||||
{% endif %}
|
||||
|
||||
editor.renderer.setShowGutter(true);
|
||||
editor.setOption("showLineNumbers", true);
|
||||
editor.setOption("showPrintMargin", false);
|
||||
editor.setOption("displayIndentGuides", true);
|
||||
editor.setOption("maxLines", "Infinity");
|
||||
editor.session.setUseWrapMode(true);
|
||||
editor.setOption("indentedSoftWrap", true);
|
||||
editor.renderer.setScrollMargin(8, 5);
|
||||
}
|
||||
});
|
||||
</script>
|
@@ -0,0 +1,121 @@
|
||||
<div class="modal-header">
|
||||
<h4>Upload case template</h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
|
||||
aria-hidden="true">×</span></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="container col-md-12">
|
||||
<form method="post" action="" id="form_upload_case_template">
|
||||
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<div class="accordion accordion-primary">
|
||||
<p>Case templates allow to prefill case objects such as tasks, tags, and notes.<br/>
|
||||
It could be used to add procedures defining how to react against a specific kind of incident (phishing, ransomware, APT...)</p>
|
||||
<div class="alert-std alert-warning" role="alert">
|
||||
Case templates can be uploaded as JSON files, or they can be added and edited in the Add/Edit case template UI.<br/>
|
||||
</div>
|
||||
<label class="placeholder">JSON File format example</label>
|
||||
<div class="card">
|
||||
<div class="card-header collapsed" id="drop_up_case_template_taxonomy" data-toggle="collapse" data-target="#drop_up_tax_case_template" aria-expanded="false" aria-controls="drop_up_tax_attr" role="button">
|
||||
<div class="span-icon">
|
||||
<div class="flaticon-pencil"></div>
|
||||
</div>
|
||||
<div class="span-title">
|
||||
Case Template taxonomy
|
||||
</div>
|
||||
<div class="span-mode"></div>
|
||||
</div>
|
||||
|
||||
<div id="drop_up_tax_case_template" class="collapse" aria-labelledby="drop_up_tax_case_template" style="">
|
||||
<div class="card-body">
|
||||
A case template is defined as below.
|
||||
<pre>
|
||||
|
||||
{
|
||||
"name": "ransomware_infection",
|
||||
"display_name": "Ransomware Infection Template",
|
||||
"description": "This case template describes first-response tasks to handle information system compromised by a ransomware.",
|
||||
"author": "DFIR-IRIS",
|
||||
"title_prefix": "RANS",
|
||||
"summary": "# Context \n\n\n # Contact \n\n\n # Actions \n\n\n",
|
||||
"tags": ["ransomware","malware"],
|
||||
"tasks": [
|
||||
{
|
||||
"title": "Identify the perimeter",
|
||||
"description": "The perimeter of compromise must be identified",
|
||||
"tags": ["identify"]
|
||||
},
|
||||
{
|
||||
"title": "Collect compromised hosts",
|
||||
"description": "Deploy Velociraptor and start collecting evidence",
|
||||
"tags": ["collect", "velociraptor"]
|
||||
},
|
||||
{
|
||||
"title": "Contain"
|
||||
}
|
||||
],
|
||||
"note_groups": [
|
||||
{
|
||||
"title": "Identify",
|
||||
"notes": [
|
||||
{
|
||||
"title": "Identify the compromised accounts",
|
||||
"content": "# Observations\n\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Collect",
|
||||
"notes": [
|
||||
{
|
||||
"title": "Velociraptor deployment"
|
||||
},
|
||||
{
|
||||
"title": "Assets collected",
|
||||
"content": "# Assets collected\n\n# Assets not collected"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h4>Field types</h4>
|
||||
The supported fields types are:
|
||||
<ul>
|
||||
<li>name: The name of the case template (required).</li>
|
||||
<li>display_name: The displayed name of the case template.</li>
|
||||
<li>description: The description of the case template.</li>
|
||||
<li>author: The author of the case template (not related to the current user).</li>
|
||||
<li>title_prefix: A prefix to add to case title.</li>
|
||||
<li>summary: content to prefill the summary.</li>
|
||||
<li>tags: A list of case tags.</li>
|
||||
<li>tasks: A list of dictionaries defining tasks. Tasks are defined by title (required), description, and list of tags.</li>
|
||||
<li>note_groups: A list of dictionaries defining note groups. Note groups are defined by title (required), and list of notes. Notes have title (required) and content</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="placeholder">Choose JSON file to import : </label>
|
||||
<input id="input_upload_case_template" type="file" accept="text/json">
|
||||
</div>
|
||||
</div>
|
||||
<div class='invalid-feedback' id='ctempl-invalid-msg'></div>
|
||||
</div><!-- /.modal-content -->
|
||||
</form>
|
||||
</div>
|
||||
<div class="alert alert-warning" style="display:none;" role="alert" id="alert_upload_case_template_details">
|
||||
<span id="alert_upload_case_template"></span><br/>
|
||||
<b>Logs:</b>
|
||||
<ul id="upload_case_template_err_details_list">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-outline-success" onclick="upload_case_template();">Upload</button>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user