FEA: redesigned template management

Added num and tag for positions
Introduced quickchange style
This commit is contained in:
Keanu D?lle 2022-01-19 01:18:34 +01:00
parent 4b9ea4a15f
commit 0a6745ee89
24 changed files with 1016 additions and 337 deletions

View File

@ -0,0 +1 @@
<div class="alert alert-{{level}}" role="alert">{{content}}</div>

View File

@ -1,100 +1,60 @@
<div class="card-body template_detailed_card_body">
<div class="form-group row">
<label for="template_detailed_name" class="col-sm-3 col-form-label">Name</label>
<div class="col-sm-9">
<input type="text" class="form-control qsf" id="template_detailed_name" value="{{name}}">
<form action="javascript:void(0);" id="template_detailed_form">
<div class="form-group row">
<label for="template_detailed_name" class="col-sm-3 col-form-label">Name</label>
<div class="col-sm-9">
<input class="form-control qsf" id="template_detailed_name"
oninvalid="this.setCustomValidity('Es muss ein Vorlagenname angegeben werden!')" required
type="text" value="{{name}}"></input>
</div>
</div>
</div>
<div class="form-group row">
<label for="template_detailed_description" class="col-sm-3 col-form-label">Beschreibung</label>
<div class="col-sm-9">
<input type="text" class="form-control qsf" id="template_detailed_description" value="{{description}}">
<div class="form-group row">
<label for="template_detailed_description" class="col-sm-3 col-form-label">Beschreibung</label>
<div class="col-sm-9">
<input class="form-control qsf" id="template_detailed_description" type="text"
value="{{description}}"></input>
</div>
</div>
</div>
<div>
<hr>
<h3>Positionen</h3><br>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>
<button class="iconbutton template_detailed_check_all_positions">
<svg width="1.25em" height="1.25em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#check-all"></use>
</svg>
</button>
</th>
<th scope="col">Position</th>
<th scope="col">Beschreibung</th>
<th scope="col">Bezeichnung</th>
<th scope="col" style="width:15%">Anzahl</th>
</tr>
</thead>
<tbody class="template_detailed_positions_tbody">
{{#each positions}}
<div>
<hr>
<h3>Positionen</h3><br>
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Position</th>
<th scope="col">Beschreibung</th>
<th scope="col">Bezeichnung</th>
<th scope="col" style="width:15%">Anzahl</th>
<th scope="col">Aktionen</th>
</tr>
</thead>
<tbody class="template_detailed_positions_tbody">
{{#each positions}}
{{> em_event_unit_templates_template_detailed_position_row}}
{{/each}}
<tr class="new_row">
<td><input type="checkbox" class="template_detailed_position_checkbox"></td>
<td colspan="2">{{> search base="add_position_search" type="position"}}</td>
<td><input type="text" id="add_position_tag" class="form-control"></td>
<td><input type="number" min="1" value="1" id="add_position_num" class="form-control"></td>
</tr>
</tbody>
</table>
<button type="button" class="btn btn-danger btn-sm templates_detailed_delete_position_button qsf">Löschen</button>
<br><br>
<hr>
<h3>Fahrzeugpositionen</h3><br>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>
<button class="iconbutton template_detailed_check_all_vehicles">
<svg width="1.25em" height="1.25em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#check-all"></use>
</svg>
</button>
</th>
<th scope="col">Name</th>
<th scope="col">Beschreibung</th>
<th scope="col">Fahrzeugkategorie</th>
</tr>
</thead>
<tbody class="template_detailed_vehicles_tbody">
{{#each vehicle_positions}}
<tr>
<td><input type="checkbox" class="template_detailed_vehicle_checkbox" data-vehicle-id="{{id}}">
</td>
<td>{{name}}</td>
<td>{{description}}</td>
<td>{{required_vehicle_category}}</td>
</tr>
{{/each}}
</tbody>
</table>
<button type="button" class="btn btn-danger btn-sm templates_detailed_delete_vehicle_button">Löschen</button>
<br><br>
<b>Hinzufügen:</b>
<div class="form-group row">
<label for="template_detailed_vehicle_name" class="col-sm-3 col-form-label">Bezeichnung</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="template_detailed_vehicle_name" value="{{vehicle_name}}">
</div>
{{/each}}
{{> em_event_unit_templates_template_detailed_position_row_empty base="add_position_search_first"}}
</tbody>
</table>
<hr>
<h3>Fahrzeugpositionen</h3><br>
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Beschreibung</th>
<th scope="col">Fahrzeugkategorie</th>
<th scope="col">Aktionen</th>
</tr>
</thead>
<tbody class="template_detailed_vehicle_positions_tbody">
{{#each vehicle_positions}}
{{> em_event_unit_templates_template_detailed_vehicle_position_row
vehicle_categories=../vehicle_categories }}
{{/each}}
{{> em_event_unit_templates_template_detailed_vehicle_position_row_empty}}
</tbody>
</table>
</div>
<div class="form-group row">
<label for="template_detailed_vehicle_description" class="col-sm-3 col-form-label">Beschreibung</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="template_detailed_vehicle_description" value="{{vehicle_description}}">
</div>
</div>
<div class="form-group row">
<label for="template_detailed_vehicle_category_select" class="col-sm-3 col-form-label">Fahrzeugkategorie:</label>
<div class="col-sm-9">
<select id="template_detailed_vehicle_category_select" class="form-control col-9"></select>
</div>
</div>
<button type="button" class="template_detailed_vehicle_add btn btn-secondary">Fahrzeugposition hinzufügen</button>
</div>
<input type="hidden" id="template_detailed_entity_id" value="{{entity_id}}"><br>
<input id="template_detailed_entity_id" type="hidden" value="{{entity_id}}"></input><br>
</form>
</div>

View File

@ -1,8 +1,19 @@
<tr>
<td><input type="checkbox" class="template_detailed_position_checkbox" data-position-id="{{position.entity_id}}">
</td>
<tr class="position_row" data-position-id="{{position.entity_id}}" data-position-template-id="{{position_template_id}}">
<td>{{position.name}}</td>
<td>{{position.description}}</td>
<td><input type="text" class="form-control qsf" value="{{tag}}"></td>
<td><input type="number" class="form-control qsf" value="{{num}}"></td>
<td><input class="form-control qsf position_tag" type="text" value="{{tag}}"></input></td>
<td><input class="form-control qsf position_num" type="number" value="{{num}}"></input></td>
<td>
<button class="iconbutton remove_position_btn qsf" title="Position von Template entfernen" type="button">
<svg fill="currentColor" height="1.5em" width="1.5em">
<use xlink:href="/img/bootstrap-icons.svg#trash"></use>
</svg>
</button>
<button class="iconbutton unremove_position_btn qsf" style="display: none;"
title="Das Entfernen der Position von Template rückgängig machen" type="button">
<svg fill="currentColor" height="1.5em" width="1.5em">
<use xlink:href="/img/bootstrap-icons.svg#arrow-counterclockwise"></use>
</svg>
</button>
</td>
</tr>

View File

@ -0,0 +1,13 @@
<tr class="empty_row position_row">
<td colspan="2">{{> search type="position"}}</td>
<td><input class="form-control add_position_tag" type="text"></input></td>
<td><input class="form-control add_position_num" min="1" type="number" value="1"></input></td>
<td>
<button class="iconbutton remove_position_new_row_btn qsf" title="Position von Template entfernen"
type="button">
<svg fill="currentColor" height="1.5em" width="1.5em">
<use xlink:href="/img/bootstrap-icons.svg#trash"></use>
</svg>
</button>
</td>
</tr>

View File

@ -0,0 +1,24 @@
<tr class="vehicle_position_row" data-vehicle-position-id="{{entity_id}}">
<td><input class="form-control qsf vehicle_position_name" type="text" value="{{name}}"></input></td>
<td><input class="form-control qsf vehicle_position_description" type="text" value="{{description}}"></input></td>
<td><select class="vehicle_position_category form-control qsf"
data-selected-category="{{required_vehicle_category}}">
{{#each vehicle_categories}}
<option title="{{description}}" value="{{id}}">{{name}}</option>
{{/each}}
</select></td>
<td>
<button class="iconbutton remove_vehicle_position_btn qsf" title="Fahrzeugposition von Template entfernen"
type="button">
<svg fill="currentColor" height="1.5em" width="1.5em">
<use xlink:href="/img/bootstrap-icons.svg#trash"></use>
</svg>
</button>
<button class="iconbutton unremove_vehicle_position_btn qsf" style="display: none;"
title="Das Entfernen der Fahrzeugposition von Template rückgängig machen" type="button">
<svg fill="currentColor" height="1.5em" width="1.5em">
<use xlink:href="/img/bootstrap-icons.svg#arrow-counterclockwise"></use>
</svg>
</button>
</td>
</tr>

View File

@ -0,0 +1,17 @@
<tr class="empty_row vehicle_position_row">
<td><input class="form-control add_vehicle_position_name" type="text"></input></td>
<td><input class="form-control add_vehicle_position_description" type="text"></input></td>
<td><select class="add_vehicle_position_category form-control">
{{#each vehicle_categories}}
<option title="{{description}}" value="{{id}}">{{name}}</option>
{{/each}}
</select></td>
<td>
<button class="iconbutton remove_vehicle_position_new_row_btn" title="Fahrzeugposition von Template entfernen"
type="button">
<svg fill="currentColor" height="1.5em" width="1.5em">
<use xlink:href="/img/bootstrap-icons.svg#trash"></use>
</svg>
</button>
</td>
</tr>

View File

@ -1,6 +0,0 @@
<tr class="eu_vehicle_position_tr" data-entity_id="{{entity_id}}">
<td><input type="checkbox" class="eu_vehicle_position_checkbox" data-entity-id="{{entity_id}}"></td>
<td>{{name}}</td>
<td>{{description}}</td>
<td>{{required_vehicle_category_name}}</td>
</tr>

View File

@ -1,6 +1,7 @@
<div id="{{base}}-search">
<div class="eo-search" id="{{base}}-search">
<div class="input-group">
<input type="text" class="form-control" id="{{base}}-searchbar" autocomplete="off" data-search-type="{{type}}">
<input autocomplete="off" class="form-control eo-searchbar" data-search-type="{{type}}" id="{{base}}-searchbar"
type="text">
<span class="input-group-append">
<span class="btn btn-outline-secondary" type="button">
<svg width="16" height="16" fill="currentColor">
@ -14,7 +15,7 @@
</div>
</div>
<div class="input-group" id="{{base}}_input_group" style="display: none;">
<input type="text" disabled id="{{base}}" class="form-control">
<input class="form-control eo-search-selected" disabled id="{{base}}" type="text">
<span class="input-group-append">
<span class="btn btn-outline-secondary" id="{{base}}_remove"
type="button">

View File

@ -244,17 +244,37 @@ th.rotate > div > span {
padding: 7px;
text-align: center;
}
#sidebar .sidebar-navigation {
text-align: center;
}
}
/* Quick save fields */
input.qsf{
input.qsf {
background-color: #E8EEE9;
}
.modified{
select.qsf {
background-color: #E8EEE9;
}
button.modified {
background-color: initial !important;
border-style: none !important;
}
.modified {
background-color: white !important;
border-style: dashed !important;
}
.marked-for-delete {
background-image: linear-gradient(136deg, #ffd9d9 13.64%, #ffffff 13.64%, #ffffff 50%, #ffd9d9 50%, #ffd9d9 63.64%, #ffffff 63.64%, #ffffff 100%);
background-size: 15.84px 15.29px;
}
/* Overwriting card-header min-height to unify header height if some cards have buttons inside */
.card-header {
min-height: 56px !important;
}

View File

@ -1,34 +1,406 @@
limit = 10;
$(document).ready(async function(){
$(document).ready(async function () {
await EventUnitTemplatesModule.load_templates();
EventUnitTemplatesModule.setup_pagination();
await EventUnitTemplatesModule.load_eu_template_list();
});
EventUnitTemplatesModule = (function(){
EventUnitTemplatesApi = (function () {
let requests = [];
let run_all = async function (successCallback, failureCallback) {
await Promise.all(requests.map(req => $.ajax(req))).then(successCallback, failureCallback);
requests = [];
};
let add_position_to_template = function (position_template_entry) {
requests.push({
url: '/api/events/units/templates/' + position_template_entry.template_id + '/positions/' + position_template_entry.position_entity_id,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(position_template_entry),
success: function (data) {
if (is_ok(data)) {
}
},
timeout: 3000,
error: function () {
EventUnitTemplatesModule.show_alert("danger", "Konnte neue Position nicht speichern!");
}
});
};
let update_position_for_template = function (position_template_entry) {
requests.push({
url: '/api/events/units/templates/' + position_template_entry.template_id + '/positions/' + position_template_entry.position_entity_id + '/' + position_template_entry.position_template_id,
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify(position_template_entry),
success: function (data) {
if (is_ok(data)) {
}
},
timeout: 3000,
error: function () {
EventUnitTemplatesModule.show_alert("danger", "Konnte geänderte Position nicht speichern!");
}
});
};
let remove_position_from_template = function (position_template_id, template_id, position_id) {
requests.push({
url: '/api/events/units/templates/' + template_id + '/positions/' + position_id + '/' + position_template_id,
type: 'DELETE',
contentType: 'application/json',
success: function (data) {
if (is_ok(data)) {
}
},
timeout: 3000,
error: function () {
EventUnitTemplatesModule.show_alert("danger", "Konnte Position nicht von der Vorlage entfernen!");
}
});
};
let update_template_core_data = function (template) {
requests.push({
url: '/api/events/units/templates/' + template.entity_id,
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify(template),
success: function (data) {
if (is_ok(data)) {
}
},
timeout: 3000,
error: function () {
EventUnitTemplatesModule.show_alert("danger", "Konnte Namen & Beschreibung des Templates nicht speichern!");
}
});
};
let add_vehicle_position = function (vehicle_position_entry) {
requests.push({
url: '/api/events/units/vehicle_positions',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(vehicle_position_entry),
success: function (data) {
if (is_ok(data)) {
}
},
timeout: 3000,
error: function () {
EventUnitTemplatesModule.show_alert("danger", "Konnte neue Fahrzeugposition nicht speichern!");
}
});
};
let remove_vehicle_position = function (vehicle_position_id) {
requests.push({
url: '/api/events/units/vehicle_positions/' + vehicle_position_id,
type: 'DELETE',
contentType: 'application/json',
success: function (data) {
if (is_ok(data)) {
}
},
timeout: 3000,
error: function () {
EventUnitTemplatesModule.show_alert("danger", "Konnte Position nicht von der Vorlage entfernen!");
}
});
};
let update_vehicle_position = function (vehicle_position_entry) {
requests.push({
url: '/api/events/units/vehicle_positions/' + vehicle_position_entry.entity_id,
type: 'PUT',
contentType: 'application/json',
data: JSON.stringify(vehicle_position_entry),
success: function (data) {
if (is_ok(data)) {
}
},
timeout: 3000,
error: function () {
EventUnitTemplatesModule.show_alert("danger", "Konnte geänderte Position nicht speichern!");
}
});
};
return {
add_position_to_template,
update_position_for_template,
remove_position_from_template,
update_template_core_data,
add_vehicle_position,
remove_vehicle_position,
update_vehicle_position,
run_all
}
}());
EventUnitTemplatesModule = (function () {
let templates = {};
let eu_templates = new Map();
let loaded_template = {};
let old_offset = 0;
let searchbar_counter = 0;
let pag = null;
let all_checked = false;
let all_checked_vehicles = false;
let positions_all_checked = false;
let template_modified = false;
let activate_modified = function () {
if (!template_modified) { //Only execute on first modification
template_modified = true;
$(".save-button").off("click").on("click", save).show(); //Show save button
}
$(this).addClass("modified");
};
let deactivate_modified = function () {
if (template_modified) { //Only execute on first modification
template_modified = false;
$(".save-button").hide(); //Show save button
}
};
let show_alert = function (level, msg) {
let alerto = {};
alerto.level = level;
alerto.content = msg;
$(".alertbox").append(templates.alert(alerto));
$(".alert").delay(4000).slideUp(500, function () {
$(this).alert('close');
});
};
let delete_templates = function () {
let template_list = [];
$(".eu_template_checkbox").each(function (k, v) {
if ($(v).prop("checked")) {
template_list.push($(v).data("entity-id"));
}
});
let load_templates = async function(){
$.ajax({
url: '/api/events/units/templates/',
type: 'DELETE',
data: JSON.stringify(template_list),
contentType: 'application/json',
success: function (data) {
if (is_ok(data)) {
$(".eu_template_checkbox").each(function (k, v) {
if (template_list.includes($(v).data("entity-id"))) {
$(this).parent().parent().remove();
}
})
}
},
timeout: 3000,
error: function () {
alert("Es ist ein Fehler aufgetreten!");
}
});
};
let create_template = function () {
let pdata = {};
if (!$("#template_new_name").val()) {
alert("Bitte alle Felder ausfüllen!");
return
} else {
pdata.name = $("#template_new_name").val();
}
if ($("#template_new_description").val().length > 0) {
pdata.description = $("#template_new_description").val();
}
$.ajax({
url: '/api/events/units/templates',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(pdata),
success: function (data) {
if (is_ok(data)) {
location.reload();
}
},
timeout: 3000,
error: function () {
alert("Es ist ein Fehler aufgetreten!");
}
});
};
let mod_positions = (function () {
let save = function () {
// Save new positions
$(".position_row.new_row").each(function () {
let position_template_entry = {};
position_template_entry.template_id = loaded_template.entity_id || undefined;
position_template_entry.position_entity_id = $(this).find(".eo-search-selected").data("entity-id") || undefined;
position_template_entry.tag = $(this).find(".add_position_tag").val() || undefined;
position_template_entry.num = $(this).find(".add_position_num").val() || undefined;
if (!position_template_entry.position_entity_id || !position_template_entry.num) { //Skip row if no num or position
return false;
}
EventUnitTemplatesApi.add_position_to_template(position_template_entry);
})
// Save modified positions
// Using .position_row .modified (with whitespace) to select all position_rows where any child has .modified
$(".position_row .modified").each(function () {
let row = $(this).closest(".position_row");
if (row.length === 0 || row.hasClass("marked-for-delete") || row.hasClass("new_row") || row.hasClass("empty_row")) { //Skip row if also marked for deletion or is new (don't edit rows which going to be deleted)
return false;
}
let position_template_entry = {};
position_template_entry.position_template_id = row.data("position-template-id") || undefined;
position_template_entry.template_id = loaded_template.entity_id || undefined;
position_template_entry.position_entity_id = row.data("position-id") || undefined;
position_template_entry.tag = row.find(".position_tag").val() || undefined;
position_template_entry.num = row.find(".position_num").val() || undefined;
EventUnitTemplatesApi.update_position_for_template(position_template_entry);
})
// Save deleted positions
// Using .position_row.marked-for-delete to select all position_rows which also have .marked-for-delete
$(".position_row.marked-for-delete").each(function () {
EventUnitTemplatesApi.remove_position_from_template($(this).data("position-template-id"), loaded_template.entity_id, $(this).data("position-id"));
})
};
let mark_for_delete = function () {
let row = $(this).closest(".position_row");
row.addClass("marked-for-delete");
$(this).hide();
row.find(".unremove_position_btn").show();
};
let unmark_for_delete = function () {
let row = $(this).closest(".position_row");
row.removeClass("marked-for-delete");
$(this).hide();
row.find(".remove_position_btn").show();
}
return {
save,
mark_for_delete,
unmark_for_delete,
}
}());
let mod_vehicle_positions = (function () {
let save = function () {
// Save new vehicle positions
$(".vehicle_position_row.new_row").each(function () {
let vehicle_position_entry = {};
vehicle_position_entry.template_id = loaded_template.entity_id || undefined;
vehicle_position_entry.name = $(this).find(".add_vehicle_position_name").val() || undefined;
vehicle_position_entry.description = $(this).find(".add_vehicle_position_description").val() || undefined;
vehicle_position_entry.required_vehicle_category = $(this).find(".add_vehicle_position_category").val() || undefined;
if (!vehicle_position_entry.template_id || !vehicle_position_entry.name || !vehicle_position_entry.required_vehicle_category) { //Skip row if no num or position
return false;
}
EventUnitTemplatesApi.add_vehicle_position(vehicle_position_entry);
});
// Save modified vehicle positions
// Using .vehicle_position_row .modified (with whitespace) to select all vehicle_position_rows where any child has .modified
$(".vehicle_position_row .modified").each(function () {
let row = $(this).closest(".vehicle_position_row");
if (row.length === 0 || row.hasClass("marked-for-delete") || row.hasClass("new_row") || row.hasClass("empty_row")) { //Skip row if also marked for deletion or is new (don't edit rows which going to be deleted)
return false;
}
let vehicle_position_entry = {};
vehicle_position_entry.entity_id = row.data("vehicle-position-id") || undefined;
vehicle_position_entry.template_id = loaded_template.entity_id || undefined;
vehicle_position_entry.name = row.find(".vehicle_position_name").val() || undefined;
vehicle_position_entry.description = row.find(".vehicle_position_description").val() || undefined;
vehicle_position_entry.required_vehicle_category = row.find(".vehicle_position_category").val() || undefined;
EventUnitTemplatesApi.update_vehicle_position(vehicle_position_entry);
});
// Save deleted vehicle positions
// Using .vehicle_position_row.marked-for-delete to select all vehicle_position_rows which also have .marked-for-delete
$(".vehicle_position_row.marked-for-delete").each(function () {
EventUnitTemplatesApi.remove_vehicle_position($(this).data("vehicle-position-id"));
})
};
let mark_for_delete = function () {
let row = $(this).closest(".vehicle_position_row");
row.addClass("marked-for-delete");
$(this).hide();
row.find(".unremove_vehicle_position_btn").show();
};
let unmark_for_delete = function () {
let row = $(this).closest(".vehicle_position_row");
row.removeClass("marked-for-delete");
$(this).hide();
row.find(".remove_vehicle_position_btn").show();
}
return {
save,
mark_for_delete,
unmark_for_delete,
}
}());
let mod_template = (function () {
let save = function () {
let template = {};
template.entity_id = loaded_template.entity_id || undefined;
template.name = $("#template_detailed_name").val() || undefined;
template.description = $("#template_detailed_description").val() || undefined;
if (template.name !== loaded_template.name || template.description !== loaded_template.description) {
//Name or description changed!
EventUnitTemplatesApi.update_template_core_data(template);
}
};
return {
save: save,
}
}());
let save = async function () {
mod_positions.save();
mod_template.save();
mod_vehicle_positions.save();
EventUnitTemplatesApi.run_all(async function () {
template_modified = false; //Reset modified variable
$(".save-button").hide(); //Hide save button
$(".modified").removeClass("modified"); //Remove modified style from all fields
//TODO: save animation/confirmation
let active_template = loaded_template.entity_id;
await load_eu_template_list(old_offset);
await load_detailed_template(null, active_template);
}, function () {
console.log("Error occurred during one or more requests");
})
};
let load_templates = async function () {
const template_row = $.get("/templates/em_event_unit_templates_template_row.hbs");
const template_detailed = $.get("/templates/em_event_unit_templates_template_detailed.hbs");
const vehicle_row = $.get("/templates/em_event_unit_templates_vehicle_position_row.hbs");
const template_detailed_position_row = $.get("/templates/em_event_unit_templates_template_detailed_position_row.hbs");
const template_detailed_position_row_empty = $.get("/templates/em_event_unit_templates_template_detailed_position_row_empty.hbs");
const template_detailed_vehicle_position_row = $.get("/templates/em_event_unit_templates_template_detailed_vehicle_position_row.hbs");
const template_detailed_vehicle_position_row_empty = $.get("/templates/em_event_unit_templates_template_detailed_vehicle_position_row_empty.hbs");
const search = $.get("/templates/search.hbs");
const pagination = $.get("/templates/pagination.hbs");
const alert = $.get("/templates/alert.hbs");
await Promise.all([template_row, template_detailed, vehicle_row, search, pagination]).then(function(res){
Handlebars.registerPartial('search', Handlebars.compile(res[3]));
await Promise.all([template_row, template_detailed, template_detailed_position_row, template_detailed_position_row_empty, search, pagination, alert, template_detailed_vehicle_position_row, template_detailed_vehicle_position_row_empty]).then(function (res) {
Handlebars.registerPartial('search', Handlebars.compile(res[4]));
Handlebars.registerPartial('em_event_unit_templates_template_detailed_position_row', Handlebars.compile(res[2]));
Handlebars.registerPartial('em_event_unit_templates_template_detailed_position_row_empty', Handlebars.compile(res[3]));
Handlebars.registerPartial('em_event_unit_templates_template_detailed_vehicle_position_row', Handlebars.compile(res[7]));
Handlebars.registerPartial('em_event_unit_templates_template_detailed_vehicle_position_row_empty', Handlebars.compile(res[8]));
templates.template_row = Handlebars.compile(res[0]);
templates.template_detailed = Handlebars.compile(res[1]);
templates.vehicle_row = Handlebars.compile(res[2]);
templates.pagination = Handlebars.compile(res[4]);
templates.template_detailed_position_row_empty = Handlebars.compile(res[3]);
templates.template_detailed_vehicle_position_row_empty = Handlebars.compile(res[8]);
templates.pagination = Handlebars.compile(res[5]);
templates.alert = Handlebars.compile(res[6]);
});
};
let setup_pagination = function(){
@ -40,17 +412,18 @@ EventUnitTemplatesModule = (function(){
}
old_offset = offset;
$.ajax({
url: '/api/events/units/templates?limit='+limit+'&offset='+offset,
await $.ajax({
url: '/api/events/units/templates?limit=' + limit + '&offset=' + offset,
type: 'GET',
contentType: 'application/json',
success: function (data) {
if (is_ok(data)) {
eu_templates = new Map();
for(let t in data.templates){
for (let t in data.templates) {
eu_templates.set(data.templates[t].entity_id, data.templates[t]);
}
$("#template_list_tbody").empty();
for (const [key, value] of eu_templates.entries()) {
$("#template_list_tbody").append(templates.template_row(value));
@ -58,6 +431,8 @@ EventUnitTemplatesModule = (function(){
pag.render(data.total_template_count, offset);
$(".eu_template_tr").off("click").on("click", load_detailed_template);
$(".templates_delete_button").on("click", delete_templates);
$(".template_new_submit").on("click", create_template);
}
},
timeout: 3000,
@ -66,30 +441,40 @@ EventUnitTemplatesModule = (function(){
}
});
};
let load_detailed_template = async function(){
let load_detailed_template = async function (context, selected_template) {
//TODO: add warning modal if pending changes
deactivate_modified(); //Reset modified variable
$(".template_detailed_card").show();
all_checked = false;
all_checked_vehicles = false;
positions_all_checked = false;
$(".eu_template_tr").removeClass("table-primary");
$(this).addClass("table-primary");
let entity_id = $(this).data("entity_id");
let entity_id = ((selected_template) ? selected_template : $(this).data("entity_id"));
$(".template_detailed_card_body").remove();
let eu_template = eu_templates.get(entity_id);
loaded_template = eu_templates.get(entity_id);
if(eu_template){ //Check if template found for id
await load_positions_for_template(eu_template);
if (loaded_template) { //Check if template found for id
await load_positions_for_template(loaded_template);
//await load_vehicle_positions();
//Apply qsf handler:
$(".qsf").off("focusin focusout").on("focusin focusout", activate_modified).keyup(function (e) {
if (event.which === 13) {
activate_modified(e.target);
}
});
$(".template_detailed_card").show();
}
};
let load_positions_for_template = async function(eu_template){
const data = await $.ajax({
url: '/api/events/units/templates/'+eu_template.entity_id+'/positions',
let load_positions_for_template = async function(eu_template) {
let positions = await $.ajax({
url: '/api/events/units/templates/' + eu_template.entity_id + '/positions',
type: 'GET',
contentType: 'application/json',
timeout: 3000,
@ -97,51 +482,106 @@ EventUnitTemplatesModule = (function(){
alert("Es ist ein Fehler aufgetreten!");
}
});
if(is_ok(data)){
eu_template.positions = data;
console.log(eu_template);
let vehicle_positions = await $.ajax({
url: '/api/events/units/templates/' + eu_template.entity_id + '/vehicle_positions',
type: 'GET',
contentType: 'application/json',
timeout: 3000,
error: function () {
alert("Es ist ein Fehler aufgetreten!");
}
});
let vehicle_categories = await $.ajax({
url: '/api/resources/vehicles/categories',
type: 'GET',
contentType: 'application/json',
timeout: 3000,
error: function () {
alert("Es ist ein Fehler aufgetreten!");
}
});
await Promise.all([positions, vehicle_positions, vehicle_categories]).then(function (res) {
positions = res[0];
vehicle_positions = res[1];
vehicle_categories = res[2];
});
//const vehicle_categories =
if (is_ok(positions) && is_ok(vehicle_positions) && is_ok(vehicle_categories)) {
eu_template.positions = positions;
eu_template.vehicle_positions = vehicle_positions;
eu_template.vehicle_categories = vehicle_categories;
$(".template_detailed_card").append(templates.template_detailed(eu_template));
$(".template_detailed_check_all_positions").off("click").on("click", function(){
$($(".template_detailed_position_checkbox")).prop("checked", !positions_all_checked);
positions_all_checked = !positions_all_checked;
});
// --- Positions ---
var position_search = new MiniSearchbar("add_position_search", null);
//Add position search
let position_search = new MiniSearchbar("add_position_search_first", null);
position_search.setup();
$(".new_row").on("click focus", function(){
//Add position remove / unremove buttons
$(".remove_position_btn").off("click").on("click", mod_positions.mark_for_delete); //Add delete button listener
$(".unremove_position_btn").off("click").on("click", mod_positions.unmark_for_delete); //Add undelete button listener
});
/*$(".templates_detailed_delete_position_button").off("click").on("click", delete_positions_from_template);
$(".template_detailed_submit").off("click").on("click", function(){
let template = {};
template.name = $("#template_detailed_name").val();
if($("#template_detailed_description").val().length > 1){
template.description = $("#template_detailed_description").val();
}
template.entity_id = $("#template_detailed_entity_id").val();
if(template.name.length === 0){
alert("Bitte Namen angeben!");
}else{
update_template(template);
}
});
$(".template_detailed_vehicle_add").off("click").on("click", add_vehicle_position);
$(".templates_detailed_delete_vehicle_button").off("click").on("click", delete_vehicle_positions);
$(".template_detailed_check_all_vehicles").off("click").on("click", function(){
$(".eu_vehicle_position_checkbox").prop("checked", !all_checked_vehicles);
all_checked_vehicles = !all_checked_vehicles;
});
$(vehicle_categories).each(function(){
$("#template_detailed_vehicle_category_select").append("<option value='"+this.id+"'>"+this.name+"</option>")
});*/
//Add new empty row when existing new row is clicked
let add_new_empty_position_row = function () {
$(".empty_row.position_row").removeClass("empty_row").addClass("new_row"); //Change row status from empty to new
$(".new_row").off("click focus"); //Remove this function from row
let sid = {};
sid.base = "add_position_search_" + searchbar_counter;
searchbar_counter++;
$(".template_detailed_positions_tbody").append(templates.template_detailed_position_row_empty(sid)); //Add new empty row
let position_search = new MiniSearchbar(sid.base, null);
position_search.setup();
$(".remove_position_btn").off("click").on("click", mod_positions.mark_for_delete); //Add delete button listener
$(".unremove_position_btn").off("click").on("click", mod_positions.unmark_for_delete); //Add undelete button listener
$(".remove_position_new_row_btn").off("click").on("click", function () {
$(this).closest(".new_row").remove();
})
$(".empty_row.position_row").on("click focus", add_new_empty_position_row); //Add this function to the empty row.
activate_modified();
};
$(".empty_row.position_row").on("click focus", add_new_empty_position_row);
// --- Vehicle Positions ---
//Add new empty row when existing new row is clicked
let add_new_empty_vehicle_position_row = function () {
$(".empty_row.vehicle_position_row").removeClass("empty_row").addClass("new_row"); //Change row status from empty to new
$(".new_row").off("click focus"); //Remove this function from row
$(".template_detailed_vehicle_positions_tbody").append(templates.template_detailed_vehicle_position_row_empty(loaded_template)); //Add new empty row
$(".remove_vehicle_position_btn").off("click").on("click", mod_vehicle_positions.mark_for_delete); //Add delete button listener
$(".unremove_vehicle_position_btn").off("click").on("click", mod_vehicle_positions.unmark_for_delete); //Add undelete button listener
$(".remove_vehicle_position_new_row_btn").off("click").on("click", function () {
$(this).closest(".new_row").remove();
})
$(".empty_row.vehicle_position_row").on("click focus", add_new_empty_vehicle_position_row); //Add this function to the empty row.
activate_modified();
};
$(".empty_row.vehicle_position_row").on("click focus", add_new_empty_vehicle_position_row);
//Set vehicle category selects to current category
$(".vehicle_position_category").each(function () {
$(this).val($(this).data("selected-category"));
})
//Add position remove / unremove buttons
$(".remove_vehicle_position_btn").off("click").on("click", mod_vehicle_positions.mark_for_delete); //Add delete button listener
$(".unremove_vehicle_position_btn").off("click").on("click", mod_vehicle_positions.unmark_for_delete); //Add undelete button listener
}
};
return{
return {
load_templates: load_templates,
setup_pagination: setup_pagination,
load_eu_template_list: load_eu_template_list,
show_alert: show_alert,
}
}());

View File

@ -5,6 +5,7 @@
{{> sidebar }}
{{> searchbar}}
<hr>
<div class="alertbox"></div>
<h1>Vorlagen</h1>
<div class="col">
<div class="row">
@ -54,7 +55,11 @@
</div>
<div class="col col-lg-6">
<div class="card bg-light mb-3 template_detailed_card" style="display: none">
<div class="card-header">Vorlage</div>
<div class="card-header d-flex justify-content-between align-items-center">Vorlage
<button class="btn btn-success btn-sm save-button" style="display: none;">Änderungen
Speichern
</button>
</div>
</div>
</div>
</div>

View File

@ -1 +1 @@
v0.2-67-g89a6232
v0.2-71-g4b9ea4a

View File

@ -1,12 +1,12 @@
use crate::helper::settings::Settings;
use rocket::State;
use crate::database::controller::connector::establish_connection;
use diesel::{RunQueryDsl, ExpressionMethods};
use crate::schema::entities::dsl::entities;
use diesel::{ExpressionMethods, RunQueryDsl};
use diesel::query_dsl::filter_dsl::FilterDsl;
use rocket::State;
pub fn generate_entity(settings: &State<Settings>) -> Result<uuid::Uuid, diesel::result::Error>{
use crate::database::controller::connector::establish_connection;
use crate::helper::settings::Settings;
use crate::schema::entities::dsl::entities;
pub fn generate_entity(settings: &State<Settings>) -> Result<uuid::Uuid, diesel::result::Error> {
let connection = establish_connection(settings);
match diesel::insert_into(entities).default_values().returning(crate::schema::entities::dsl::entity_id).get_result(&connection){
@ -18,11 +18,14 @@ pub fn generate_entity(settings: &State<Settings>) -> Result<uuid::Uuid, diesel:
}
}
pub fn remove_entity(settings: &State<Settings>, entity_id: uuid::Uuid) -> Result<(), diesel::result::Error>{
/// Deprecated!
/// Security Issue: This method doesn't check the entity type. This allows users to delete any resource
// TODO: remove
#[deprecated]
pub fn remove_entity(settings: &State<Settings>, entity_id: uuid::Uuid) -> Result<(), diesel::result::Error> {
let connection = establish_connection(settings);
match diesel::delete(entities.filter(crate::schema::entities::dsl::entity_id.eq(entity_id))).execute(&connection){
match diesel::delete(entities.filter(crate::schema::entities::dsl::entity_id.eq(entity_id))).execute(&connection) {
Ok(_) => Ok(()),
Err(e) => {
error!("Couldn't delete entity_id: {}", e);

View File

@ -1,20 +1,26 @@
use diesel::{RunQueryDsl, ExpressionMethods, JoinOnDsl, PgTextExpressionMethods, BoolExpressionMethods, sql_query};
use rocket::State;
use crate::helper::settings::Settings;
use crate::database::model::events::{Event, EventType, EventUnitPosition, EventUnitTemplate, EventUnitInstance, EventUnitVehiclePosition, EventUnitInstancePosition, EventUnitInstanceVehiclePosition};
use crate::database::controller::connector::establish_connection;
use chrono::NaiveDateTime;
use crate::diesel::QueryDsl;
use diesel::pg::types::sql_types::Uuid;
use diesel::{BoolExpressionMethods, ExpressionMethods, JoinOnDsl, PgTextExpressionMethods, RunQueryDsl, sql_query};
use diesel::dsl::any;
use diesel::pg::types::sql_types::Uuid;
use rocket::State;
use crate::database::controller::connector::establish_connection;
use crate::database::controller::events::templates::vehicle_positions::get_eu_vehicle_positions_for_template;
use crate::database::model::events::{Event, EventType, EventUnitInstance, EventUnitInstancePosition, EventUnitInstanceVehiclePosition, EventUnitPosition, EventUnitTemplate, EventUnitVehiclePosition};
use crate::diesel::QueryDsl;
use crate::helper::settings::Settings;
use crate::schema::eu_positions_templates;
pub fn add_event(settings: &State<Settings>, data: Event) -> Result<Event, diesel::result::Error>{
pub mod templates;
//TODO: migrate to multiple files to improve readability
pub fn add_event(settings: &State<Settings>, data: Event) -> Result<Event, diesel::result::Error> {
use crate::schema::events::dsl::*;
let connection = establish_connection(settings);
match diesel::insert_into(events).values(data).get_result(&connection){
match diesel::insert_into(events).values(data).get_result(&connection) {
Ok(org) => Ok(org),
Err(e) => {
error!("Couldn't create event: {}", e);
@ -207,14 +213,14 @@ pub fn add_event_unit_template(settings: &State<Settings>, eut: EventUnitTemplat
}
}
pub fn add_position_to_template(settings: &State<Settings>, template_id2 : uuid::Uuid, position_id : uuid::Uuid, num_of_positions: i32) -> Result<(), diesel::result::Error>{
pub fn add_position_to_template(settings: &State<Settings>, data: RawEventUnitTemplatePosition) -> Result<(), diesel::result::Error> {
use crate::schema::eu_positions_templates::dsl::*;
let connection = establish_connection(settings);
match diesel::insert_into(eu_positions_templates).values((position_entity_id.eq(position_id), template_id.eq(template_id2), num.eq(num_of_positions))).execute(&connection){
match diesel::insert_into(eu_positions_templates).values(data).execute(&connection) {
Ok(_) => Ok(()),
Err(e) => {
error!("Couldn't add position(s) to template: {}", e);
error!("Couldn't add position to template: {}", e);
Err(e)
}
}
@ -258,11 +264,10 @@ pub fn get_event_unit_templates_count(settings: &State<Settings>,) -> Result<i64
}
}
use crate::schema::eu_positions_templates;
#[derive(Queryable, Clone, Deserialize, Serialize, AsChangeset, Insertable)]
#[derive(Queryable, Clone, Deserialize, Serialize, AsChangeset, Insertable, Identifiable)]
#[table_name = "eu_positions_templates"]
#[changeset_options(treat_none_as_null = "true")]
#[primary_key(position_template_id)]
pub struct RawEventUnitTemplatePosition{
pub(crate) position_entity_id: uuid::Uuid,
pub(crate) template_id: uuid::Uuid,
@ -323,25 +328,12 @@ fn get_event_unit_position(settings: &State<Settings>, position_id: uuid::Uuid)
}
}
pub fn get_event_unit_vehicle_positions_for_template(settings: &State<Settings>, template: uuid::Uuid) -> Result<Vec<EventUnitVehiclePosition>, diesel::result::Error>{
use crate::schema::eu_vehicle_positions::dsl::*;
let connection = establish_connection(settings);
match eu_vehicle_positions.filter(template_id.eq(template)).get_results(&connection){
Ok(pos) => Ok(pos),
Err(e) => {
error!("Couldn't get unit positions for template: {}", e);
Err(e)
}
}
}
pub fn remove_positions_from_template(settings: &State<Settings>, template: uuid::Uuid, position_list: Vec<uuid::Uuid>) -> Result<(), diesel::result::Error>{
pub fn remove_position_from_template(settings: &State<Settings>, template: uuid::Uuid, position: uuid::Uuid, position_template_id2: uuid::Uuid) -> Result<(), diesel::result::Error> {
use crate::schema::eu_positions_templates::dsl::*;
let connection = establish_connection(settings);
match diesel::delete(eu_positions_templates.filter(template_id.eq(template)).filter(position_entity_id.eq_any(position_list))).execute(&connection){
match diesel::delete(eu_positions_templates.filter(template_id.eq(template)).filter(position_entity_id.eq(position)).filter(position_template_id.eq(position_template_id2))).execute(&connection) {
Ok(_) => Ok(()),
Err(e) => {
error!("Couldn't delete position from template: {}", e);
@ -350,11 +342,32 @@ pub fn remove_positions_from_template(settings: &State<Settings>, template: uuid
}
}
pub fn update_eu_template(settings: &State<Settings>, template: EventUnitTemplate) -> Result<EventUnitTemplate, diesel::result::Error>{
pub fn update_positions_templates(settings: &State<Settings>, data: RawEventUnitTemplatePosition) -> Result<EventUnitTemplatePosition, diesel::result::Error> {
use crate::schema::eu_positions_templates::dsl::*;
let connection = establish_connection(settings);
let res: RawEventUnitTemplatePosition = match diesel::update(eu_positions_templates).filter(position_template_id.eq(data.position_template_id)).set(data).get_result(&connection) {
Ok(res) => res,
Err(e) => {
error!("Couldn't update position for template: {}", e);
return Err(e)
}
};
Ok(EventUnitTemplatePosition {
position_template_id: res.position_template_id,
tag: res.tag,
num: res.num,
template_id: res.template_id,
position: get_event_unit_position(settings, res.position_entity_id)?,
})
}
pub fn update_eu_template(settings: &State<Settings>, template: EventUnitTemplate) -> Result<EventUnitTemplate, diesel::result::Error> {
use crate::schema::eu_templates::dsl::*;
let connection = establish_connection(settings);
match diesel::update(eu_templates.filter(entity_id.eq(template.entity_id))).set(template).get_result(&connection){
match diesel::update(eu_templates.filter(entity_id.eq(template.entity_id))).set(template).get_result(&connection) {
Ok(res) => Ok(res),
Err(e) => {
error!("Couldn't update event unit template: {}", e);
@ -384,7 +397,7 @@ pub fn add_position_instances_for_instance(settings: &State<Settings>, instance_
Err(e) => return Err(e)
};
let vehicle_positions = match get_event_unit_vehicle_positions_for_template(settings, template_id2){
let vehicle_positions = match get_eu_vehicle_positions_for_template(settings, template_id2) {
Ok(pos) => pos,
Err(e) => return Err(e)
};
@ -472,19 +485,6 @@ pub fn add_vehicle_position(settings: &State<Settings>, position: EventUnitVehic
}
}
pub fn get_vehicle_positions_for_template(settings: &State<Settings>, template_id: uuid::Uuid) -> Result<Vec<EventUnitVehiclePosition>, diesel::result::Error>{
use crate::schema::eu_vehicle_positions::dsl;
let connection = establish_connection(settings);
match dsl::eu_vehicle_positions.filter(dsl::template_id.eq(template_id)).get_results(&connection){
Ok(pos) => Ok(pos),
Err(e) => {
error!("Couldn't get vehicle positions for template: {}", e);
Err(e)
}
}
}
pub fn change_position_instances(settings: &State<Settings>, instance_id2: uuid::Uuid, position_id2: uuid::Uuid, taken_by2: Option<uuid::Uuid>) -> Result<usize, diesel::result::Error>{
use crate::schema::eu_position_instances::dsl::*;

View File

@ -0,0 +1,2 @@
pub mod positions;
pub mod vehicle_positions;

View File

@ -0,0 +1,45 @@
use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl};
use rocket::State;
use crate::database::controller::connector::establish_connection;
use crate::database::model::events::EventUnitVehiclePosition;
use crate::Settings;
pub fn get_eu_vehicle_positions_for_template(settings: &State<Settings>, template_id: uuid::Uuid) -> Result<Vec<EventUnitVehiclePosition>, diesel::result::Error> {
use crate::schema::eu_vehicle_positions::dsl;
let connection = establish_connection(settings);
match dsl::eu_vehicle_positions.filter(dsl::template_id.eq(template_id)).get_results(&connection) {
Ok(pos) => Ok(pos),
Err(e) => {
error!("Couldn't get vehicle positions for template: {}", e);
Err(e)
}
}
}
pub fn delete_eu_vehicle_position(settings: &State<Settings>, vehicle_position_id: uuid::Uuid) -> Result<(), diesel::result::Error> {
use crate::schema::eu_vehicle_positions::dsl::*;
let connection = establish_connection(settings);
match diesel::delete(eu_vehicle_positions.filter(entity_id.eq(vehicle_position_id))).execute(&connection) {
Ok(_) => Ok(()),
Err(e) => {
error!("Couldn't delete vehicle_position: {}", e);
Err(e)
}
}
}
pub fn update_eu_vehicle_position(settings: &State<Settings>, vehicle_position_data: EventUnitVehiclePosition) -> Result<EventUnitVehiclePosition, diesel::result::Error> {
use crate::schema::eu_vehicle_positions::dsl::*;
let connection = establish_connection(settings);
match diesel::update(eu_vehicle_positions.filter(entity_id.eq(vehicle_position_data.entity_id))).set(vehicle_position_data).get_result(&connection) {
Ok(res) => Ok(res),
Err(e) => {
error!("Couldn't update vehicle position: {}", e);
Err(e)
}
}
}

View File

@ -1,30 +1,33 @@
extern crate argon2;
extern crate base64;
extern crate chrono;
extern crate config;
#[macro_use]
extern crate diesel;
extern crate iban;
extern crate log;
#[macro_use]
extern crate rocket;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate argon2;
extern crate chrono;
extern crate iban;
extern crate base64;
extern crate serde_json;
use std::{thread, time};
use std::io::Write;
use std::process::Command;
use std::sync::Arc;
use rocket::fs::FileServer;
use rocket_dyn_templates::handlebars::Handlebars;
use rocket_dyn_templates::Template;
use helper::settings::Settings;
use crate::helper::handlebars_in_list_helper::in_list_block_helper;
use crate::helper::mail_queue::queue::MailQueue;
use crate::helper::mail_templates::MailTemplates;
use crate::helper::session_cookies::model::SessionCookieStorage;
use helper::settings::Settings;
use std::io::Write;
use std::process::Command;
use std::sync::Arc;
use std::{thread, time};
use rocket_dyn_templates::Template;
use rocket::fs::FileServer;
use rocket_dyn_templates::handlebars::Handlebars;
pub mod database;
pub mod helper;
@ -196,13 +199,15 @@ fn rocket() -> _ {
modules::api::events::event_units::position::read::read_event_unit_position,
modules::api::events::event_units::position::delete::delete_event_unit_positions,
modules::api::events::event_units::position::update::update_event_unit_position,
modules::api::events::event_units::position::update::update_vehicle_position,
modules::api::events::event_units::templates::create::create_event_unit_template,
modules::api::events::event_units::templates::update::put_position_in_template,
modules::api::events::event_units::templates::create::put_position_in_template,
modules::api::events::event_units::templates::read::read_event_unit_templates,
modules::api::events::event_units::templates::delete::delete_templates,
modules::api::events::event_units::templates::delete::delete_positions_from_template,
modules::api::events::event_units::templates::read::read_event_unit_template_positions,
modules::api::events::event_units::templates::update::update_template,
modules::api::events::event_units::templates::update::update_position_for_template,
modules::event_management::edit_event::edit_event,
modules::api::events::instances::create::create_instance,
modules::api::events::instances::read::read_instances,

View File

@ -1,11 +1,14 @@
use rocket::State;
use crate::helper::settings::Settings;
use crate::helper::session_cookies::model::SessionCookie;
use diesel::result::Error;
use rocket::serde::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::parse_member_cookie;
use rocket::State;
use crate::database::controller::entities::remove_entity;
use crate::database::controller::events::templates::vehicle_positions::delete_eu_vehicle_position;
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
use crate::helper::translate_diesel_error::translate_diesel;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use crate::modules::api::model::api_outcome::{ApiError, ApiErrorWrapper};
#[delete("/api/events/units/positions", format = "json", data = "<delete_list>")]
pub fn delete_event_unit_positions(
@ -32,11 +35,11 @@ pub fn delete_event_unit_positions(
Ok(())
}
#[delete("/api/events/units/vehicle_positions", format = "json", data = "<delete_list>")]
#[delete("/api/events/units/vehicle_positions/<vehicle_position_id>", format = "json")]
pub fn delete_event_unit_vehicle_positions(
settings: &State<Settings>,
cookie: SessionCookie,
delete_list: Json<Vec<uuid::Uuid>>,
vehicle_position_id: String,
) -> Result<(), Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
@ -45,14 +48,8 @@ pub fn delete_event_unit_vehicle_positions(
));
}
let delete_list = delete_list.into_inner();
for position in delete_list {
match remove_entity(settings, position){
Ok(_) => {}
Err(e) => return Err(translate_diesel(e)),
}
match delete_eu_vehicle_position(settings, parse_uuid_string(vehicle_position_id)?) {
Ok(()) => Ok(()),
Err(e) => return Err(translate_diesel(e))
}
Ok(())
}

View File

@ -1,21 +1,22 @@
use crate::helper::session_cookies::model::SessionCookie;
use rocket::State;
use crate::helper::settings::Settings;
use rocket::serde::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use rocket::State;
use crate::database::model::events::EventUnitPosition;
use crate::database::controller::events::{set_event_unit_position};
use crate::database::controller::events::set_event_unit_position;
use crate::database::controller::events::templates::vehicle_positions::update_eu_vehicle_position;
use crate::database::model::events::{EventUnitPosition, EventUnitVehiclePosition};
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
use crate::helper::translate_diesel_error::translate_diesel;
use crate::modules::api::events::event_units::position::create::CreatePositionData;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use crate::modules::api::model::api_outcome::{ApiError, ApiErrorWrapper};
#[put("/api/events/units/positions/<entity_id>", format = "json", data = "<update_position_data>")]
pub fn update_event_unit_position(
settings: &State<Settings>,
cookie: SessionCookie,
update_position_data: Json<CreatePositionData>,
entity_id : String,
entity_id: String,
) -> Result<Json<EventUnitPosition>, Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
@ -41,9 +42,59 @@ pub fn update_event_unit_position(
requirements
};
match set_event_unit_position(settings, event_position){
match set_event_unit_position(settings, event_position) {
Ok(eup) => Ok(Json(eup)),
Err(e) => Err(translate_diesel(e))
Err(e) => Err(translate_diesel(e))
}
}
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct UpdateVehiclePositionData {
pub entity_id: String,
pub name: String,
pub description: Option<String>,
pub required_vehicle_category: String,
pub template_id: String,
}
/// Update vehicle_position
/// Parameters:
/// * vehicle_position_id: entity_id in eu_vehicle_positions
/// Method: PUT
/// Returns: EventUnitVehiclePosition or ApiError as JSON
#[put("/api/events/units/vehicle_positions/<vehicle_position_id>", format = "json", data = "<update_vehicle_position_data>")]
pub fn update_vehicle_position(
settings: &State<Settings>,
cookie: SessionCookie,
vehicle_position_id: String,
update_vehicle_position_data: Json<UpdateVehiclePositionData>,
) -> Result<Json<EventUnitVehiclePosition>, Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
return Err(Json(
ApiError::new(403, "Keine Berechtigung Fahrzeugposition zu verändern!".to_string()).to_wrapper(),
));
}
let data = update_vehicle_position_data.into_inner();
if data.entity_id != vehicle_position_id {
return Err(Json(
ApiError::new(400, "vehicle_position_id in URI doesn't match PUT data!".to_string()).to_wrapper(),
));
}
let pos = EventUnitVehiclePosition {
entity_id: parse_uuid_string(data.entity_id)?,
name: data.name,
description: data.description,
required_vehicle_category: parse_uuid_string(data.required_vehicle_category)?,
template_id: parse_uuid_string(data.template_id)?,
};
match update_eu_vehicle_position(settings, pos) {
Ok(pos) => Ok(Json(pos)),
Err(e) => Err(translate_diesel(e))
}
}

View File

@ -1,16 +1,17 @@
use rocket::State;
use crate::helper::settings::Settings;
use crate::helper::session_cookies::model::SessionCookie;
use rocket::serde::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::parse_member_cookie;
use rocket::State;
use crate::database::controller::entities::generate_entity;
use crate::database::controller::events::{add_event_unit_template, add_position_to_template, RawEventUnitTemplatePosition};
use crate::database::model::events::EventUnitTemplate;
use crate::database::controller::events::add_event_unit_template;
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
use crate::helper::translate_diesel_error::translate_diesel;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use crate::modules::api::model::api_outcome::{ApiError, ApiErrorWrapper};
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct CreateTemplateData{
pub struct CreateTemplateData {
pub entity_id: Option<String>,
pub name: String,
pub description: Option<String>,
@ -41,9 +42,69 @@ pub fn create_event_unit_template(
description: create_template_data.description,
};
match add_event_unit_template(settings, event_position){
match add_event_unit_template(settings, event_position) {
Ok(eup) => Ok(Json(eup)),
Err(e) => Err(translate_diesel(e))
Err(e) => Err(translate_diesel(e))
}
}
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct PutPositionInTemplateData {
pub template_id: String,
pub position_entity_id: String,
pub tag: Option<String>,
pub num: String,
}
#[post("/api/events/units/templates/<template_id>/positions/<position_id>", format = "json", data = "<put_position_in_template_data>")]
pub fn put_position_in_template(
settings: &State<Settings>,
cookie: SessionCookie,
put_position_in_template_data: Json<PutPositionInTemplateData>,
template_id: String,
position_id: String,
) -> Result<(), Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
return Err(Json(
ApiError::new(403, "Keine Berechtigung Vorlagen zu verändern!".to_string()).to_wrapper(),
));
}
let data = put_position_in_template_data.into_inner();
if (data.template_id != template_id || data.position_entity_id != position_id) {
return Err(Json(
ApiError::new(400, "template_id or position_entity_id in URI doesn't match POST data!".to_string()).to_wrapper(),
));
}
let entity_id = match generate_entity(settings) {
Ok(entity) => entity,
Err(_) => {
return Err(Json(ApiError::new(500, "Konnte keine neue Entität anlegen.".to_string()).to_wrapper()))
},
};
let num = match data.num.parse() {
Ok(num) => num,
Err(e) => {
warn!("Wrong data type for num while putting position in template: {}", e);
return Err(Json(ApiError::new(400, "Wrong data type for num.".to_string()).to_wrapper()))
}
};
let res = RawEventUnitTemplatePosition {
position_entity_id: parse_uuid_string(position_id)?,
template_id: parse_uuid_string(template_id)?,
position_template_id: entity_id,
num,
tag: data.tag,
};
match add_position_to_template(settings, res) {
Ok(()) => Ok(()),
Err(e) => Err(translate_diesel(e))
}
}

View File

@ -1,12 +1,13 @@
use crate::helper::settings::Settings;
use rocket::State;
use crate::helper::session_cookies::model::SessionCookie;
use rocket::serde::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use rocket::State;
use crate::database::controller::entities::remove_entity;
use crate::database::controller::events::remove_position_from_template;
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
use crate::helper::translate_diesel_error::translate_diesel;
use crate::database::controller::events::remove_positions_from_template;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use crate::modules::api::model::api_outcome::{ApiError, ApiErrorWrapper};
#[delete("/api/events/units/templates", format = "json", data = "<template_list>")]
pub fn delete_templates(
@ -33,12 +34,13 @@ pub fn delete_templates(
Ok(())
}
#[delete("/api/events/units/templates/<template_id>/positions", format = "json", data = "<position_list>")]
#[delete("/api/events/units/templates/<template_id>/positions/<position_id>/<position_template_id>", format = "json")]
pub fn delete_positions_from_template(
settings: &State<Settings>,
cookie: SessionCookie,
template_id: String,
position_list: Json<Vec<uuid::Uuid>>,
position_id: String,
position_template_id: String,
) -> Result<(), Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
@ -47,9 +49,7 @@ pub fn delete_positions_from_template(
));
}
let position_list = position_list.into_inner();
match remove_positions_from_template(settings, parse_uuid_string(template_id)?, position_list){
match remove_position_from_template(settings, parse_uuid_string(template_id)?, parse_uuid_string(position_id)?, parse_uuid_string(position_template_id)?) {
Ok(_) => {}
Err(e) => return Err(translate_diesel(e)),
}

View File

@ -1,15 +1,17 @@
use crate::database::model::events::{EventUnitTemplate, EventUnitPosition, EventUnitVehiclePosition};
use rocket::State;
use crate::helper::settings::Settings;
use crate::helper::session_cookies::model::SessionCookie;
use rocket::serde::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use rocket::State;
use crate::database::controller::events::{EventUnitTemplatePosition, get_event_unit_positions_for_template, get_event_unit_templates, get_event_unit_templates_count};
use crate::database::controller::events::templates::vehicle_positions::get_eu_vehicle_positions_for_template;
use crate::database::model::events::{EventUnitPosition, EventUnitTemplate, EventUnitVehiclePosition};
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
use crate::helper::translate_diesel_error::translate_diesel;
use crate::database::controller::events::{get_event_unit_templates, get_event_unit_templates_count, get_event_unit_positions_for_template, get_vehicle_positions_for_template, EventUnitTemplatePosition};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use crate::modules::api::model::api_outcome::{ApiError, ApiErrorWrapper};
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct EventUnitTemplateList{
pub struct EventUnitTemplateList {
pub(crate) templates: Vec<EventUnitTemplate>,
pub(crate) total_template_count: i64,
}
@ -90,7 +92,7 @@ pub fn read_event_unit_template_vehicle_positions(
));
}
let positions = match get_vehicle_positions_for_template(settings, parse_uuid_string(template_id)?){
let positions = match get_eu_vehicle_positions_for_template(settings, parse_uuid_string(template_id)?) {
Ok(pos) => pos,
Err(e) => return Err(translate_diesel(e))
};

View File

@ -1,48 +1,15 @@
use diesel::sql_types::Integer;
use crate::helper::settings::Settings;
use rocket::State;
use crate::helper::session_cookies::model::SessionCookie;
use rocket::serde::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use crate::database::controller::events::{add_position_to_template, update_eu_template};
use crate::helper::translate_diesel_error::translate_diesel;
use rocket::State;
use crate::database::controller::events::{add_position_to_template, EventUnitTemplatePosition, RawEventUnitTemplatePosition, update_eu_template, update_positions_templates};
use crate::database::model::events::EventUnitTemplate;
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
use crate::helper::translate_diesel_error::translate_diesel;
use crate::modules::api::events::event_units::templates::create::CreateTemplateData;
#[put("/api/events/units/templates/<template_id>/positions/<position_id>/times/<num>", format = "json")]
pub fn put_position_in_template(
settings: &State<Settings>,
cookie: SessionCookie,
template_id: String,
position_id: String,
num: String,
) -> Result<(), Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
return Err(Json(
ApiError::new(403, "Keine Berechtigung Vorlagen zu verändern!".to_string()).to_wrapper(),
));
}
let template_id = parse_uuid_string(template_id)?;
let position_id = parse_uuid_string(position_id)?;
let num : i32 = match num.parse(){
Ok(num) => num,
Err(e) => {
warn!("Couldn't parse number of times for putting positions in template: {}", e);
return Err(Json(
ApiError::new(400, "Couldn't parse times as integer!".to_string()).to_wrapper(),
));
}
};
match add_position_to_template(settings, template_id, position_id, num){
Ok(_) => Ok(()),
Err(e) => Err(translate_diesel(e))
}
}
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid_string};
use crate::modules::api::model::api_outcome::{ApiError, ApiErrorWrapper};
#[put("/api/events/units/templates/<template_id>", format = "json", data = "<template>")]
pub fn update_template(
@ -66,9 +33,69 @@ pub fn update_template(
description: template.description
};
match update_eu_template(settings, template){
match update_eu_template(settings, template) {
Ok(template) => Ok(Json(template)),
Err(e) => Err(translate_diesel(e))
Err(e) => Err(translate_diesel(e))
}
}
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct PositionTemplateData {
pub position_template_id: String,
pub template_id: String,
pub position_entity_id: String,
pub tag: Option<String>,
pub num: String,
}
/// Updates eu_positions_templates
/// Parameters:
/// * template_id: current template as uuid
/// * position_id: current position as uuid
/// * position_template_id: position_template to edit
/// * position_template_data: JSON data for update
#[put("/api/events/units/templates/<template_id>/positions/<position_id>/<position_template_id>", format = "json", data = "<position_template_data>")]
pub fn update_position_for_template(
settings: &State<Settings>,
cookie: SessionCookie,
position_template_data: Json<PositionTemplateData>,
template_id: String,
position_id: String,
position_template_id: String,
) -> Result<Json<EventUnitTemplatePosition>, Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission(crate::permissions::modules::event_management::events::EDIT.to_string()) {
return Err(Json(
ApiError::new(403, "Keine Berechtigung Vorlagen zu verändern!".to_string()).to_wrapper(),
));
}
let data = position_template_data.into_inner();
if (data.template_id != template_id || data.position_entity_id != position_id || data.position_template_id != position_template_id) {
return Err(Json(
ApiError::new(400, "template_id or position_entity_id or position_template_id in URI doesn't match PUT data!".to_string()).to_wrapper(),
));
}
let num = match data.num.parse() {
Ok(num) => num,
Err(e) => {
warn!("Wrong data type for num while putting position in template: {}", e);
return Err(Json(ApiError::new(400, "Wrong data type for num.".to_string()).to_wrapper()))
}
};
let res = RawEventUnitTemplatePosition {
position_entity_id: parse_uuid_string(position_id)?,
template_id: parse_uuid_string(template_id)?,
position_template_id: parse_uuid_string(position_template_id)?,
num,
tag: data.tag,
};
match update_positions_templates(settings, res) {
Ok(res) => Ok(Json(res)),
Err(e) => Err(translate_diesel(e))
}
}