Added scheduler

This commit is contained in:
Keanu D?lle 2021-04-15 13:42:02 +02:00
parent 081fd7333c
commit 2736772e42
53 changed files with 1151 additions and 70 deletions

View File

@ -0,0 +1,10 @@
-- This file should undo anything in `up.sql`
DELETE FROM permissions WHERE permission = 'modules.resource_management.vehicles.list.view';
DELETE FROM permissions WHERE permission = 'modules.resource_management.vehicles.core.edit';
alter table vehicles
drop constraint vehicles_vehicle_categories_id_fk;
alter table vehicles
drop vehicle_category;
DROP TABLE vehicle_categories;
DROP TABLE appointments;
DROP TABLE appointment_types;

View File

@ -0,0 +1,47 @@
-- Your SQL goes here
INSERT INTO permissions (permission, description) VALUES('modules.resource_management.vehicles.list.view', 'Permission to see list of vehicles');
INSERT INTO permissions (permission, description) VALUES('modules.resource_management.vehicles.core.edit', 'Permission to edit vehicles core data');
INSERT INTO roles_permissions (role_id, permission_id) VALUES('admin', 'modules.resource_management.vehicles.list.view');
INSERT INTO roles_permissions (role_id, permission_id) VALUES('admin', 'modules.resource_management.vehicles.core.edit');
CREATE TABLE vehicle_categories(
id uuid DEFAULT uuid_generate_v1() PRIMARY KEY ,
name Text NOT NULL,
description Text
);
alter table vehicles
add vehicle_category uuid;
alter table vehicles
add constraint vehicles_vehicle_categories_id_fk
foreign key (vehicle_category) references vehicle_categories (id)
on update cascade on delete set null;
alter table vehicles
drop column IF EXISTS next_inspection;
create table appointment_types
(
type_id uuid default uuid_generate_v1() not null
constraint appointment_types_pk
primary key,
name text not null,
description text,
interval integer
);
create table appointments
(
id uuid default uuid_generate_v1() not null
constraint appointments_pk
primary key,
type_id uuid not null
constraint appointments_appointment_types_type_id_fk
references appointment_types
on update cascade on delete cascade,
entity_id uuid not null
constraint appointments_entities_entity_id_fk
references entities
on update cascade on delete cascade,
appointment_date date not null
);

View File

@ -8,3 +8,8 @@ VALUES ('modules.scheduler.appointments.view', 'Permission to see appointment fo
INSERT INTO permissions (permission, description)
VALUES ('modules.scheduler.appointments.edit', 'Permission to modify appointment for specified (context) entity');
INSERT INTO public.roles_permissions (role_id, permission_id, role_permission_id)
VALUES ('admin', 'modules.scheduler.appointments.edit', DEFAULT);
INSERT INTO public.roles_permissions (role_id, permission_id, role_permission_id)
VALUES ('admin', 'modules.scheduler.appointments.view', DEFAULT);

View File

@ -0,0 +1,142 @@
$( document ).ready(function() {
VehicleModule.get_vehicle_categories();
VehicleModule.get_vehicles();
$(".vehicle_detailed_view_submit").on("click", VehicleModule.save_vehicle);
});
VehicleModule = ( function() {
var vehicle_list = [];
var get_vehicle_categories = function(){
$.ajax({
type: "GET",
url: "/api/resources/vehicles/categories",
contentType: 'application/json',
timeout: 3000,
error: function () {
alert("Verbindung zum Server unterbrochen!");
},
success: function (data) {
if(is_ok(data)) {
$(data).each(function(){
$(".vehicle_categories_select").append("<option data-category-id=\""+this.id+"\">"+this.name+"</option>");
});
}
}
});
};
var get_vehicles = function(){
$.ajax({
type: "GET",
url: "/api/resources/vehicles?entries=20&page=0",
contentType: 'application/json',
timeout: 3000,
error: function () {
alert("Verbindung zum Server unterbrochen!");
},
success: function (data) {
if(is_ok(data)) {
vehicle_list = data;
$(data).each(function(){
var is_operational = "";
if(this.is_operational === true){
is_operational = "✓";
}else{
is_operational = "×"
}
$("#vehicle_list_tbody").append("<tr class=\"vehicle_list_select_tr\" data-vehicle-id=\""+this.entity_id+"\">\n" +
" <td><input type=\"checkbox\" data-vehicle-id=\""+this.entity_id+"\"></td>\n" +
" <td>"+this.identifier+"</td>\n" +
" <td>"+this.numberplate+"</td>\n" +
" <td>"+is_operational+"</td>\n"+
" </tr>");
});
$(".vehicle_list_select_tr").unbind("click").on("click", VehicleModule.load_vehicle_details);
}
}
});
};
var load_vehicle_details = function(){
var tr = this;
$("#vehicle_detailed_view > input").val("");
$("#vehicle_detailed_view").show();
$(vehicle_list).each(function(){
if(this.entity_id === $(tr).data("vehicle-id")){
$("#vehicle_detailed_view_identifier_input").val(this.identifier);
$("#vehicle_detailed_view_numberplate_input").val(this.numberplate);
$("#vehicle_detailed_view_description_input").val(this.description);
if(this.is_operational){
$("#vehicle_detailed_view_is_operational_input").attr("checked", true);
}
$("#vehicle_detailed_view_admissable_total_weight_input").val(this.admissible_total_weight);
$("#vehicle_detailed_view_entity_id").val(this.entity_id);
var entity_id = this.entity_id;
$.ajax({
type: "GET",
url: "/api/info/caller/permissions?permission=modules.scheduler.appointments.view&entity_id="+entity_id,
contentType: 'application/json',
timeout: 3000,
error: function () {
alert("Verbindung zum Server unterbrochen!");
},
success: function (data) {
if(is_ok(data)) {
console.log(data);
if(data){
$(".scheduler").show();
$(".scheduler_add_appointment_entity_id").val(entity_id);
Scheduler.list_appointments();
}
}
}
});
}
});
};
var save_vehicle = function(){
var vehicle = new Object();
vehicle.identifier = $("#vehicle_detailed_view_identifier_input").val();
if($("#vehicle_detailed_view_numberplate_input").val().length > 0){
vehicle.numberplate = $("#vehicle_detailed_view_numberplate_input").val();
}
if($("#vehicle_detailed_view_description_input").val().length > 0){
vehicle.description = $("#vehicle_detailed_view_description_input").val();
}
if($("#vehicle_detailed_view_is_operational_input").prop('checked')){
vehicle.is_operational = true;
}else{
vehicle.is_operational = false;
}
if($("#vehicle_detailed_view_admissable_total_weight_input").val().length > 0){
//vehicle.admissible_total_weight = $("#vehicle_detailed_view_admissable_total_weight_input").val();
}
if($("#vehicle_detailed_view_category_input option:selected").data("category-id") !== null){
vehicle.vehicle_category = $("#vehicle_detailed_view_category_input option:selected").data("category-id");
}
vehicle.entity_id = $("#vehicle_detailed_view_entity_id").val();
console.log(vehicle);
$.ajax({
type: "PUT",
url: "/api/resources/vehicles/"+vehicle.entity_id,
contentType: 'application/json',
timeout: 3000,
data: JSON.stringify(vehicle),
error: function () {
alert("Verbindung zum Server unterbrochen!");
},
success: function (data) {
if(is_ok(data)) {
alert("OK!");
}
}
});
};
return{
get_vehicle_categories: get_vehicle_categories,
get_vehicles: get_vehicles,
load_vehicle_details: load_vehicle_details,
save_vehicle: save_vehicle,
};
})();

92
resources/js/scheduler.js Normal file
View File

@ -0,0 +1,92 @@
$( document ).ready(function() {
Scheduler.refresh_appointment_types();
$(".scheduler_add_appointment_button").on("click", function(){
Scheduler.add_appointment(this);
})
});
Scheduler = ( function() {
var appointment_types = [];
var refresh_appointment_types = function(){
$.ajax({
type: "GET",
url: "/api/appointments/types",
contentType: 'application/json',
timeout: 3000,
error: function () {
alert("Verbindung zum Server unterbrochen!");
},
success: function (data) {
if(is_ok(data)) {
appointment_types = data;
$(data).each(function(){
$(".scheduler_appointment_types").append("<option value=\""+this.type_id+"\" data-interval=\""+this.interval+"\">"+this.name+"</option>")
})
}
}
});
};
var add_appointment = function(submit){
var appointment = {};
var div = $(submit).parent();
appointment.type_id = div.find(".scheduler_appointment_types").val();
appointment.entity_id = div.find(".scheduler_add_appointment_entity_id").val();
appointment.appointment_date = div.find(".scheduler_add_appointment_date").val();
$.ajax({
type: "POST",
url: "/api/appointments",
contentType: 'application/json',
timeout: 3000,
data: JSON.stringify(appointment),
error: function () {
alert("Verbindung zum Server unterbrochen!");
},
success: function (data) {
if(is_ok(data)) {
alert("OK!");
}
}
});
};
var list_appointments = function(){
var entity_id = $(".scheduler_add_appointment_entity_id").val();
$.ajax({
type: "GET",
url: "/api/appointments?entity_id="+entity_id,
contentType: 'application/json',
timeout: 3000,
error: function () {
alert("Verbindung zum Server unterbrochen!");
},
success: function (data) {
if(is_ok(data)) {
$(data).each(function(){
console.log(this);
type = resolve_appointment_type(this.type_id);
$(".scheduler-tbody").append("<tr><td>"+type.name+"</td><td>"+this.appointment_date+"</td></tr>");
})
}
}
});
};
var resolve_appointment_type = function(type_id){
var resolved = [];
appointment_types.every(t => {
if(t.type_id === type_id){
resolved = t;
return false;
}else{
return true;
}
});
return resolved;
};
return{
refresh_appointment_types: refresh_appointment_types,
add_appointment: add_appointment,
list_appointments: list_appointments,
}
})();

View File

@ -7,7 +7,7 @@
<div id="content">
{{> searchbar}}
<hr>
<h1>Member List</h1>
<h1>Mitglieder</h1>
<div class="col-md-6">
<div class="filter">
<form action="/portal/mm" method="get">

View File

@ -0,0 +1,180 @@
{{> header }}
{{> delete-member-modal}}
<div class="container-fluid">
<div class="row">
<div class="wrapper">
{{> sidebar }}
<div id="content">
{{> searchbar}}
<hr>
<h1>Fahrzeuge</h1>
<div class="col">
<div class="row">
<div class="col col-md-6">
<div class="card bg-light mb-3">
<div class="card-header">Fahrzeugliste</div>
<div class="card-body">
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">Bezeichnung</th>
<th scope="col">Kennzeichen</th>
<th scope="col">Einsatzbereit</th>
</tr>
</thead>
<tbody id="vehicle_list_tbody">
</tbody>
</table>
<!--<div class="navigation_buttons">
{{#if previous_page}}<a href="?{{search_parameters}}page={{previous_page}}"><button class="iconbutton"><svg width="1.5em" height="1.5em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#arrow-left-square-fill"/>
</svg></button></a>{{/if}}
<span>Seite {{page}} / {{last_page}}</span>
{{#if next_page}}
<a href="?{{search_parameters}}page={{next_page}}"><button class="iconbutton"><svg width="1.5em" height="1.5em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#arrow-right-square-fill"/>
</svg></button></a>{{/if}}
</div>-->
</div>
</div>
<div class="card bg-light mb-3">
<div class="card-header">
<button class="btn btn-link" data-toggle="collapse" data-target="#collapseNewVehicle" aria-expanded="true" aria-controls="collapseNewVehicle">Neues Fahrzeug</button>
</div>
<div id="collapseNewVehicle" class="collapse" aria-labelledby="collapseNewVehicle" >
<div class="card-body">
<div class="form-group row">
<label for="vehicle_detailed_view_identifier_input" class="col-sm-2 col-form-label">Bezeichnung</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="vehicle_new_identifier_input">
</div>
</div>
<div class="form-group row">
<label for="vehicle_new_numberplate_input" class="col-sm-2 col-form-label">Kennzeichen</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="vehicle_new_numberplate_input">
</div>
</div>
<div class="form-group row">
<label for="vehicle_new_category_input" class="col-sm-2 col-form-label">Kategorie</label>
<div class="col-sm-10">
<select class="form-control vehicle_categories_select" id="vehicle_new_category_input">
<option data-category-id="null">keine</option>
</select>
</div>
</div>
<div class="form-group row">
<label for="vehicle_new_description_input" class="col-sm-2 col-form-label">Beschreibung</label>
<div class="col-sm-10">
<textarea id="vehicle_new_description_input" class="form-control"></textarea>
</div>
</div>
<div class="form-group row">
<label for="vehicle_new_is_operational_input" class="col-sm-2 col-form-label">Einsatzbereit</label>
<div class="col-sm-10">
<input type="checkbox" id="vehicle_new_is_operational_input">
</div>
</div>
<div class="form-group row">
<label for="vehicle_new_admissable_total_weight_input" class="col-sm-2 col-form-label">Zulässige Gesamtmasse</label>
<div class="col-sm-10">
<input type="number" class="form-control" step="0.1" min="0" id="vehicle_new_admissable_total_weight_input">
</div>
</div>
<div class="form-group row">
<label for="vehicle_new_required_license_input" class="col-sm-2 col-form-label">Benötigter Führerschein</label>
<div class="col-sm-10">
<select class="form-control" id="vehicle_new_required_license_input">
</select>
</div>
</div>
<button type="button" class="vehicle_new_submit btn btn-primary" style="float: right; margin-bottom:15px;">Fahrzeug hinzufügen</button>
</div>
</div>
</div>
</div>
<div class="col col-md-6">
<div class="card bg-light mb-3" id="vehicle_detailed_view" style="display:none;">
<div class="card-header">Fahrzeugdetails</div>
<div class="card-body">
<div class="form-group row">
<label for="vehicle_detailed_view_identifier_input" class="col-sm-2 col-form-label">Bezeichnung</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="vehicle_detailed_view_identifier_input">
</div>
</div>
<div class="form-group row">
<label for="vehicle_detailed_view_numberplate_input" class="col-sm-2 col-form-label">Kennzeichen</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="vehicle_detailed_view_numberplate_input">
</div>
</div>
<div class="form-group row">
<label for="vehicle_detailed_view_category_input" class="col-sm-2 col-form-label">Kategorie</label>
<div class="col-sm-10">
<select class="form-control vehicle_categories_select" id="vehicle_detailed_view_category_input"><option data-category-id="null">keine</option></select>
</div>
</div>
<div class="form-group row">
<label for="vehicle_detailed_view_description_input" class="col-sm-2 col-form-label">Beschreibung</label>
<div class="col-sm-10">
<textarea id="vehicle_detailed_view_description_input" class="form-control"></textarea>
</div>
</div>
<div class="form-group row">
<label for="vehicle_detailed_view_is_operational_input" class="col-sm-2 col-form-label">Einsatzbereit</label>
<div class="col-sm-10">
<input type="checkbox" id="vehicle_detailed_view_is_operational_input">
</div>
</div>
<div class="form-group row">
<label for="vehicle_detailed_view_admissable_total_weight_input" class="col-sm-2 col-form-label">Zulässige Gesamtmasse</label>
<div class="col-sm-10">
<input type="number" class="form-control" step="0.1" min="0" id="vehicle_detailed_view_admissable_total_weight_input">
</div>
</div>
<div class="form-group row">
<label for="vehicle_detailed_required_license_input" class="col-sm-2 col-form-label">Benötigter Führerschein</label>
<div class="col-sm-10">
<select class="form-control" id="vehicle_detailed_required_license_input">
</select>
</div>
</div>
<div class="scheduler" style="display: none">
<hr>
<h3>Termine</h3><br>
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Art</th>
<th scope="col">Zeitpunkt</th>
<th scope="col">Aktionen</th>
</tr>
</thead>
<tbody class="scheduler-tbody">
</tbody>
</table><br>
<div class=row>
<b class="col-3">Hinzufügen: </b>
<select class="form-control col-3 scheduler_appointment_types"></select>
<input type="date" class="col-3 form-control scheduler_add_appointment_date">
<input type="hidden" class="scheduler_add_appointment_entity_id">
<button type="button" class="scheduler_add_appointment_button btn btn-secondary col-3">Termin hinzufügen</button>
</div>
</div><br><hr>
<input type="hidden" id="vehicle_detailed_view_entity_id">
<button type="button" class="vehicle_detailed_view_submit btn btn-primary" style="float: right; margin-bottom:15px;">Änderungen Speichern</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{> footer }}

View File

@ -1 +1 @@
v0.1-17-gdcd5a4e
v0.1-22-g081fd73

View File

@ -5,7 +5,7 @@ use crate::diesel::query_dsl::filter_dsl::OrFilterDsl;
use crate::diesel::query_dsl::limit_dsl::LimitDsl;
use crate::diesel::query_dsl::select_dsl::SelectDsl;
use crate::diesel::RunQueryDsl;
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::helper::settings::Settings;
use crate::modules::api::members::get_member::MemberSearchResult;
use diesel::query_dsl::filter_dsl::FilterDsl;
@ -42,7 +42,7 @@ pub fn get_member_search_result(
let member = get_raw_member_search_result(settings, member_entity_id)?;
let groups = get_groups_for_member(settings, member_entity_id);
let readable = check_access(
let readable = check_access_to_member_and_group(
settings,
member_entity_id,
groups,
@ -106,7 +106,7 @@ pub fn get_member_search_result_by_name(
for member in raw_members {
let groups = get_groups_for_member(settings, member.entity_id);
let readable = check_access(
let readable = check_access_to_member_and_group(
settings,
member.entity_id,
groups,

View File

@ -0,0 +1,49 @@
use crate::helper::settings::Settings;
use rocket::State;
use crate::database::model::appointments::{AppointmentType, Appointment};
use crate::database::controller::connector::establish_connection;
use diesel::{RunQueryDsl, ExpressionMethods};
use chrono::NaiveDate;
use diesel::query_dsl::filter_dsl::FilterDsl;
pub fn get_appointment_types(settings: &State<Settings>) -> Result<Vec<AppointmentType>, diesel::result::Error>{
use crate::schema::appointment_types::dsl::*;
let connection = establish_connection(settings);
match appointment_types.load(&connection){
Ok(atype) => Ok(atype),
Err(e) => {
error!("Couldn't get appointment types: {}", e);
Err(e)
}
}
}
pub fn add_appointment(settings: &State<Settings>, type_id2: uuid::Uuid, entity_id2: uuid::Uuid, appointment_date2: NaiveDate) -> Result<Appointment, diesel::result::Error>{
use crate::schema::appointments::dsl::*;
let connection = establish_connection(settings);
match diesel::insert_into(appointments).values((type_id.eq(type_id2), entity_id.eq(entity_id2), appointment_date.eq(appointment_date2))).get_result(&connection){
Ok(appointment) => Ok(appointment),
Err(e) => {
error!("Couldn't insert appointment: {}", e);
Err(e)
}
}
}
pub fn get_appointment_for_entity(settings: &State<Settings>, entity_id2: uuid::Uuid) -> Result<Vec<Appointment>, diesel::result::Error>{
use crate::schema::appointments::dsl::*;
let connection = establish_connection(settings);
match appointments.filter(entity_id.eq(entity_id2)).load(&connection){
Ok(appointment_list) => Ok(appointment_list),
Err(e) => {
error!("Couldn't get appointments for entity: {}", e);
Err(e)
}
}
}

View File

@ -1,7 +1,7 @@
use crate::database::controller::connector::establish_connection;
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::database::model::groups::{GroupMemberCount, RawGroup};
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::helper::settings::Settings;
use crate::modules::member_management::model::groups::{Group, GroupData, GroupUpdateData};
use crate::schema::groups_entities::dsl::group_id;
@ -82,25 +82,25 @@ pub fn get_group_member_count(
name: group.name,
description: group.description,
members_count: get_members_in_groups_count(settings, group.group_id)?,
permission_edit_core: check_member_has_access(
permission_edit_core: check_access_to_resource(
settings,
caller_id,
group.group_id,
crate::permissions::modules::member_management::groups::core::EDIT,
),
permission_delete: check_member_has_access(
permission_delete: check_access_to_resource(
settings,
caller_id,
group.group_id,
crate::permissions::modules::member_management::groups::DELETE,
),
permission_view_members: check_member_has_access(
permission_view_members: check_access_to_resource(
settings,
caller_id,
group.group_id,
crate::permissions::modules::member_management::groups::members::VIEW,
),
permission_edit_members: check_member_has_access(
permission_edit_members: check_access_to_resource(
settings,
caller_id,
group.group_id,

View File

@ -2,7 +2,7 @@ use crate::database::controller::connector::establish_connection;
use crate::database::controller::roles::{
add_permission, add_permission_context, get_role_permission_id, get_roles,
};
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::helper::settings::Settings;
use crate::modules::api::groups::create::GroupRolePermission;
use crate::schema::roles_permissions_context::dsl::roles_permissions_context;

View File

@ -301,7 +301,7 @@ pub(crate) struct TempQuery {
/// * 'caller_id' - UUID of caller requesting access
/// * 'entity' - UUID of entity caller requesting access to
/// * 'permission' - permission caller tries to use on entity
pub fn check_member_has_access(
pub fn check_access_to_resource(
settings: &State<Settings>,
caller_id: uuid::Uuid,
entity: uuid::Uuid,

View File

@ -1,8 +1,8 @@
use crate::database::controller::connector::establish_connection;
use crate::database::controller::groups::get_groups_for_member;
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::database::model::api_members::RawMemberSearchResult;
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::helper::settings::Settings;
use crate::modules::api::members::get_member::MemberSearchResult;
use diesel::{sql_query, ExpressionMethods, JoinOnDsl, QueryDsl, RunQueryDsl};
@ -45,7 +45,7 @@ pub fn get_member_search_results_in_group(
let mut memberlist: Vec<MemberSearchResult> = vec![];
for member in raw_memberlist {
let readable = check_access(
let readable = check_access_to_member_and_group(
settings,
member.entity_id,
get_groups_for_member(&settings, member.entity_id),

View File

@ -17,4 +17,6 @@ pub mod units;
pub mod units_members;
pub mod create_member;
pub mod login_protection;
pub mod password_resets;
pub mod password_resets;
pub mod vehicles;
pub mod appointments;

View File

@ -0,0 +1,50 @@
use crate::helper::settings::Settings;
use rocket::State;
use crate::database::model::vehicles::{VehicleCategory, Vehicle};
use crate::database::controller::connector::establish_connection;
use diesel::{RunQueryDsl, ExpressionMethods};
use diesel::query_dsl::methods::{OrderDsl,OffsetDsl};
use diesel::query_dsl::limit_dsl::LimitDsl;
use crate::modules::api::resources::vehicles::create::CreateVehicleData;
use rocket::logger::error_;
pub fn get_vehicle_categories(settings: &State<Settings>) -> Result<Vec<VehicleCategory>, diesel::result::Error> {
use crate::schema::vehicle_categories::dsl::*;
let connection = establish_connection(settings);
match vehicle_categories.load(&connection){
Ok(categories) => Ok(categories),
Err(e) => {
error!("Couldn't retrieve vehicle categories: {}", e);
Err(e)
}
}
}
pub fn get_vehicles(settings: &State<Settings>, limit: i64, offset: i64) -> Result<Vec<Vehicle>, diesel::result::Error>{
use crate::schema::vehicles::dsl::*;
let connection = establish_connection(settings);
match vehicles.order(identifier.asc()).limit(limit).offset(offset).load(&connection){
Ok(vehicle_list) => Ok(vehicle_list),
Err(e) => {
error!("Couldn't retrieve vehicles: {}", e);
Err(e)
}
}
}
pub fn change_vehicle(settings: &State<Settings>, vehicle: Vehicle) -> Result<(), diesel::result::Error>{
use crate::schema::vehicles::dsl::*;
let connection = establish_connection(settings);
match diesel::update(vehicles).filter(entity_id.eq(vehicle.entity_id)).set(&vehicle).execute(&connection){
Ok(_) => Ok(()),
Err(e) => {
error!("Couldn't change vehicle: {}", e);
Err(e)
}
}
}

View File

@ -0,0 +1,17 @@
use chrono::NaiveDate;
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct Appointment{
id : uuid::Uuid,
type_id: uuid::Uuid,
entity_id: uuid::Uuid,
appointment_date: NaiveDate,
}
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct AppointmentType{
type_id: uuid::Uuid,
name: String,
description: Option<String>,
interval: Option<i32>
}

View File

@ -8,4 +8,6 @@ pub mod members;
pub mod roles;
pub mod users;
pub mod units;
pub mod login_protection;
pub mod login_protection;
pub mod vehicles;
pub mod appointments;

View File

@ -0,0 +1,25 @@
use chrono::NaiveDate;
use crate::schema::vehicles;
#[derive(Queryable, Clone, Deserialize, Serialize, AsChangeset)]
#[table_name = "vehicles"]
#[changeset_options(treat_none_as_null = "true")]
#[primary_key(entity_id)]
pub struct Vehicle{
pub(crate) entity_id: uuid::Uuid,
pub(crate) identifier: String,
pub(crate) numberplate: Option<String>,
pub(crate) description: Option<String>,
pub(crate) is_operational: bool,
pub(crate) admissible_total_weight: Option<f32>,
pub(crate) required_license: Option<String>,
pub(crate) vehicle_category: Option<uuid::Uuid>,
}
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct VehicleCategory{
pub(crate) id: uuid::Uuid,
pub(crate) name: String,
pub(crate) description: Option<String>,
}

View File

@ -1,4 +1,4 @@
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::helper::settings::Settings;
use crate::modules::member_management::model::groups::Group;
use crate::modules::member_management::model::member::Member;
@ -14,7 +14,7 @@ pub fn check_access_legacy(
let mut access = false;
for group in member_to_check.groups.iter() {
if check_member_has_access(
if check_access_to_resource(
settings,
own_member_id,
group.entity_id,
@ -40,7 +40,7 @@ pub fn check_access_legacy(
//Check if any role has direct access to member
if !access {
if check_member_has_access(
if check_access_to_resource(
settings,
own_member_id,
member_to_check.entity_id,
@ -52,7 +52,8 @@ pub fn check_access_legacy(
access
}
pub fn check_access(
/// Checks if caller has access to a specific member's group or member directly
pub fn check_access_to_member_and_group(
settings: &State<Settings>,
member_to_check_id: uuid::Uuid,
member_to_check_groups: Vec<Group>,
@ -62,7 +63,7 @@ pub fn check_access(
let mut access = false;
for group in member_to_check_groups {
if check_member_has_access(
if check_access_to_resource(
settings,
caller_entity_id,
group.entity_id,
@ -86,7 +87,7 @@ pub fn check_access(
//Check if any role has direct access to member
if !access {
if check_member_has_access(settings, caller_entity_id, member_to_check_id, &permission) {
if check_access_to_resource(settings, caller_entity_id, member_to_check_id, &permission) {
access = true;
}
}

View File

@ -150,6 +150,14 @@ fn main() {
modules::member_management::view::create_member::member_management_add_member,
modules::member_management::view::create_member::member_management_add_member_post,
modules::communicator::send_email::communicator_email_get,
modules::resource_management::vehicles::vehicle_list::vehicle_list,
modules::api::resources::vehicles::read::read_vehicle_categories,
modules::api::resources::vehicles::read::read_vehicle_list,
modules::api::resources::vehicles::update::update_vehicle,
modules::api::appointments::read::read_appointment_types,
modules::api::appointments::create::create_appointment,
modules::api::appointments::read::read_appointments_for_entity,
modules::api::info::caller::check_caller_has_permission,
],
)
.mount("/css", StaticFiles::from("resources/css"))

View File

@ -0,0 +1,62 @@
use rocket::State;
use crate::helper::settings::Settings;
use crate::helper::session_cookies::model::SessionCookie;
use rocket_contrib::json::Json;
use crate::database::model::appointments::Appointment;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
use chrono::{NaiveDate, ParseError};
use crate::database::controller::members::check_access_to_resource;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::database::controller::appointments::add_appointment;
use crate::helper::translate_diesel_error::translate_diesel;
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct CreateAppointmentData{
type_id: String,
entity_id: String,
appointment_date: String,
}
/// Creates new Appointment
///
/// # Api Call
/// * POST
/// * /api/appointments
///
/// # Api Result
/// * Api returns Appointment or ApiError in ApiErrorWrapper
///
/// # Permission required
/// * modules.scheduler.appointments.edit on specified entity
#[post("/api/appointments", format = "json", data = "<create_appointment_data>")]
pub fn create_appointment(
settings: State<Settings>,
cookie: SessionCookie,
create_appointment_data: Json<CreateAppointmentData>,
) -> Result<Json<Appointment>, Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
let cad = create_appointment_data.into_inner();
let apentity_id : uuid::Uuid = parse_uuid(cad.entity_id)?;
if !check_access_to_resource(&settings, caller.entity_id, apentity_id, crate::permissions::modules::scheduler::appointments::EDIT){
return Err(Json(
ApiError::new(403, "Keine Berechtigung, Termine anzulegen!".to_string()).to_wrapper(),
));
}
let apdate: NaiveDate = match NaiveDate::parse_from_str(&cad.appointment_date, "%Y-%m-%d") {
Ok(apdate) => apdate,
Err(e) => {
error!("Couldn't parse appointment date: {}", e);
return Err(Json(ApiError::new(400, "Das eingegebene Datum konnte nicht verarbeitet werden.".to_string()).to_wrapper()))
}
};
let aptype_id : uuid::Uuid = parse_uuid(cad.type_id)?;
match add_appointment(&settings, aptype_id, apentity_id, apdate){
Ok(appointment) => Ok(Json(appointment)),
Err(e) => Err(translate_diesel(e))
}
}

View File

@ -0,0 +1,4 @@
pub mod create;
pub mod delete;
pub mod read;
pub mod update;

View File

@ -0,0 +1,66 @@
use rocket::State;
use crate::helper::settings::Settings;
use crate::helper::session_cookies::model::SessionCookie;
use crate::database::model::appointments::{AppointmentType, Appointment};
use rocket_contrib::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
use crate::database::controller::appointments::{get_appointment_types, get_appointment_for_entity};
use crate::helper::translate_diesel_error::translate_diesel;
use crate::database::controller::members::check_access_to_resource;
/// Get list of all appointment types
///
/// # Api Call
/// * GET
/// * /api/appointments/types
///
/// # Api Result
/// *
///
/// # Required permissions
/// * None
#[get("/api/appointments/types", format = "json")]
pub fn read_appointment_types(
settings: State<Settings>,
cookie: SessionCookie,
) -> Result<Json<Vec<AppointmentType>>, Json<ApiErrorWrapper>> {
parse_member_cookie(cookie.member)?;
match get_appointment_types(&settings){
Ok(at) => Ok(Json(at)),
Err(e) => Err(translate_diesel(e)),
}
}
/// Get list of all appointments for specified entity
///
/// # Api Call
/// * GET
/// * /api/appointments?entity_id=<entity id>
///
/// # Api Result
/// *
///
/// # Required permissions
/// * modules.scheduler.appointments.view
#[get("/api/appointments?<entity_id>", format = "json")]
pub fn read_appointments_for_entity(
settings: State<Settings>,
cookie: SessionCookie,
entity_id: String,
) -> Result<Json<Vec<Appointment>>, Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
let entity_id = parse_uuid(entity_id)?;
if !check_access_to_resource(&settings, caller.entity_id, entity_id, crate::permissions::modules::scheduler::appointments::VIEW){
return Err(Json(
ApiError::new(403, "Keine Berechtigung, Termine anzuzeigen!".to_string()).to_wrapper(),
));
}
match get_appointment_for_entity(&settings, entity_id){
Ok(at) => Ok(Json(at)),
Err(e) => Err(translate_diesel(e)),
}
}

View File

@ -12,7 +12,7 @@ use crate::database::controller::api_communication_targets::{get_member_email_ad
use diesel::result::Error;
use crate::helper::translate_diesel_error::translate_diesel;
use uuid::Uuid;
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::database::controller::groups::get_group;
use crate::database::model::groups::RawGroup;
use crate::database::controller::units::get_unit;
@ -116,7 +116,7 @@ pub fn create_email(mq: State<Arc<MailQueue>>, settings: State<Settings>, cookie
None => {}
Some(groups) => {
for group in groups{
if !check_member_has_access(&settings, caller.entity_id, group, crate::permissions::modules::communicator::email::SEND){
if !check_access_to_resource(&settings, caller.entity_id, group, crate::permissions::modules::communicator::email::SEND){
match get_group(&settings, group){
Ok(group) => {
return Err(Json(ApiError::new(403, format!("Keine Berechtigung eine Email an die Gruppe {} zu schicken!", group.name)).to_wrapper()))
@ -139,13 +139,10 @@ pub fn create_email(mq: State<Arc<MailQueue>>, settings: State<Settings>, cookie
}
match mail.selected_units{
None => {
debug!("TEST: failed");
}
None => {}
Some(units) => {
for unit in units{
debug!("TEST: {}", unit);
if !check_member_has_access(&settings, caller.entity_id, unit, crate::permissions::modules::communicator::email::SEND){
if !check_access_to_resource(&settings, caller.entity_id, unit, crate::permissions::modules::communicator::email::SEND){
match get_unit(&settings, unit){
Ok(unit) => {
return Err(Json(ApiError::new(403, format!("Keine Berechtigung eine Email an die Einheit {} zu schicken!", unit.name)).to_wrapper()))

View File

@ -1,7 +1,7 @@
use crate::database::controller::groups::delete_group;
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::database::model::groups::RawGroup;
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
use crate::helper::translate_diesel_error::translate_diesel;
@ -25,7 +25,7 @@ pub fn delete_groups(
let mut permission_error = false;
for group in group_list {
if check_member_has_access(
if check_access_to_resource(
//Check if member has delete permission on specific group
&settings,
caller.entity_id,
@ -54,7 +54,7 @@ pub fn delete_member_from_group(settings: State<Settings>, cookie: SessionCookie
let member_id = parse_uuid(member_id)?;
let group_id = parse_uuid(group_id)?;
if !check_member_has_access(&settings, caller.entity_id, group_id, crate::permissions::modules::member_management::groups::members::EDIT){
if !check_access_to_resource(&settings, caller.entity_id, group_id, crate::permissions::modules::member_management::groups::members::EDIT){
return Err(Json(ApiError::new(403, "Keine Berechtigung Gruppenmitglieder zu ändern!".to_string()).to_wrapper()))
}

View File

@ -1,6 +1,6 @@
use crate::database::controller::groups::{get_group, get_raw_groups};
use crate::database::controller::groups_permissions::{get_group_permission_for_role, get_group_role_permissions, check_role_has_permission_on_entity};
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::database::controller::members_groups::get_member_search_results_in_group;
use crate::database::model::groups::RawGroup;
use crate::helper::session_cookies::model::SessionCookie;
@ -57,7 +57,7 @@ pub fn get_groups(settings: State<Settings>, cookie: SessionCookie, with_caller_
for group in groups{
match &with_caller_permission {
Some(caller_permission) => {
if check_member_has_access(&settings, caller.entity_id, group.group_id, &caller_permission){
if check_access_to_resource(&settings, caller.entity_id, group.group_id, &caller_permission){
groups_with_permission.push(group);
}
},
@ -97,37 +97,37 @@ pub fn read_group(
}
let caller_permissions = CallerGroupPermissions {
permission_groups_core_edit: check_member_has_access(
permission_groups_core_edit: check_access_to_resource(
&settings,
caller.entity_id,
entity_id,
crate::permissions::modules::member_management::groups::core::EDIT,
),
permission_groups_delete: check_member_has_access(
permission_groups_delete: check_access_to_resource(
&settings,
caller.entity_id,
entity_id,
crate::permissions::modules::member_management::groups::DELETE,
),
permission_groups_members_view: check_member_has_access(
permission_groups_members_view: check_access_to_resource(
&settings,
caller.entity_id,
entity_id,
crate::permissions::modules::member_management::groups::members::VIEW,
),
permission_groups_members_edit: check_member_has_access(
permission_groups_members_edit: check_access_to_resource(
&settings,
caller.entity_id,
entity_id,
crate::permissions::modules::member_management::groups::members::EDIT,
),
permission_groups_permissions_view: check_member_has_access(
permission_groups_permissions_view: check_access_to_resource(
&settings,
caller.entity_id,
entity_id,
crate::permissions::modules::member_management::groups::permissions::VIEW,
),
permission_groups_permissions_edit: check_member_has_access(
permission_groups_permissions_edit: check_access_to_resource(
&settings,
caller.entity_id,
entity_id,

View File

@ -6,7 +6,7 @@ use crate::modules::api::member_management::controller::parser::{parse_member_co
use rocket_contrib::json::Json;
use crate::database::controller::members_groups::add_member_to_group;
use crate::helper::translate_diesel_error::translate_diesel;
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::modules::member_management::model::groups::{GroupData, GroupUpdateData};
use crate::database::controller::groups::update_group_core_data;
@ -16,7 +16,7 @@ pub fn put_member_in_group(settings: State<Settings>, cookie: SessionCookie, gro
let member_id = parse_uuid(member_id)?;
let group_id = parse_uuid(group_id)?;
if !check_member_has_access(&settings, caller.entity_id, group_id, crate::permissions::modules::member_management::groups::members::EDIT){
if !check_access_to_resource(&settings, caller.entity_id, group_id, crate::permissions::modules::member_management::groups::members::EDIT){
return Err(Json(ApiError::new(403, "Keine Berechtigung Gruppenmitglieder zu ändern!".to_string()).to_wrapper()))
}
@ -31,7 +31,7 @@ pub fn update_group(settings: State<Settings>, cookie: SessionCookie, update_gro
let caller = parse_member_cookie(cookie.member)?;
let group_id = parse_uuid(group_id)?;
if !check_member_has_access(&settings, caller.entity_id, group_id, crate::permissions::modules::member_management::groups::core::EDIT){
if !check_access_to_resource(&settings, caller.entity_id, group_id, crate::permissions::modules::member_management::groups::core::EDIT){
return Err(Json(ApiError::new(403, "Keine Berechtigung Gruppe zu ändern!".to_string()).to_wrapper()))
}

View File

@ -0,0 +1,39 @@
use rocket::State;
use crate::helper::settings::Settings;
use crate::helper::session_cookies::model::SessionCookie;
use rocket_contrib::json::Json;
use crate::modules::api::model::api_outcome::ApiErrorWrapper;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
use crate::database::controller::groups_permissions::check_role_has_permission_on_entity;
use crate::database::controller::members::check_access_to_resource;
/// Check if caller has permission
///
/// # Api Call
/// * GET
/// * /api/info/caller/permissions?permission=<permission_string : String>&entity_id=<entity_id: Option<String>>
///
/// # Api Result
/// * Result bool / ApiErrorWrapper
///
/// # Required permissions
/// * None
#[get("/api/info/caller/permissions?<permission>&<entity_id>", format = "json")]
pub fn check_caller_has_permission(
settings: State<Settings>,
cookie: SessionCookie,
permission: String,
entity_id: Option<String>,
) -> Result<Json<bool>, Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
match entity_id{
Some(entity_id) => {
let entity_id = parse_uuid(entity_id)?;
Ok(Json(check_access_to_resource(&settings, caller.entity_id, entity_id, &permission)))
},
None => {
Ok(Json(caller.has_permission(permission)))
}
}
}

View File

@ -0,0 +1 @@
pub mod caller;

View File

@ -1,6 +1,6 @@
use crate::database::controller::api_members::delete_entity;
use crate::database::controller::groups::get_groups_for_member;
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::helper::session_cookies::model::SessionCookie;
use crate::helper::settings::Settings;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
@ -19,7 +19,7 @@ pub fn api_members_delete(
let member_id = parse_uuid(entity_id)?;
let groups = get_groups_for_member(&settings, member_id);
if !check_access(
if !check_access_to_member_and_group(
&settings,
member_id,
groups,

View File

@ -8,7 +8,7 @@ use diesel::result::Error;
use rocket::http::Cookies;
use rocket::State;
use rocket_contrib::json::Json;
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::database::controller::groups::get_groups_for_member;
use crate::database::controller::member_communication::{get_communication_target, add_communication_target, remove_communication_target};
use crate::helper::translate_diesel_error::translate_diesel;
@ -59,7 +59,7 @@ pub fn api_communication_targets_create(
let communication_target = communication_target.into_inner();
let groups = get_groups_for_member(&settings, communication_target.entity_id);
if !check_access(&settings, communication_target.entity_id, groups, caller.entity_id, crate::permissions::modules::member_management::profile::communication::EDIT.to_string()){
if !check_access_to_member_and_group(&settings, communication_target.entity_id, groups, caller.entity_id, crate::permissions::modules::member_management::profile::communication::EDIT.to_string()){
return Err(Json(ApiError::new(401, "Keine Berechtigung, ein Kommunikationsziel hinzuzufügen.".to_string()).to_wrapper()))
}
@ -92,7 +92,7 @@ pub fn api_communication_targets_update(
let member_groups = get_groups_for_member(&settings, old_target.entity_id);
if old_target.entity_id != caller.entity_id{ //if Member edits own communication target, do not check permissions
if !check_access(&settings, old_target.entity_id, member_groups, caller.entity_id, "modules.member_management.profile.communication.edit".to_string()) {
if !check_access_to_member_and_group(&settings, old_target.entity_id, member_groups, caller.entity_id, "modules.member_management.profile.communication.edit".to_string()) {
return Err(Json(
ApiError::new(
403,
@ -168,7 +168,7 @@ pub fn api_communication_targets_delete(
let groups = get_groups_for_member(&settings, target.entity_id);
if !check_access(&settings, target.entity_id, groups, member.entity_id, crate::permissions::modules::member_management::profile::communication::EDIT.to_string()){
if !check_access_to_member_and_group(&settings, target.entity_id, groups, member.entity_id, crate::permissions::modules::member_management::profile::communication::EDIT.to_string()){
return Err(Json(ApiError::new(401, "Keine Berechtigung Kommunikationseintrag zu löschen!".to_string()).to_wrapper()))
}

View File

@ -5,7 +5,7 @@ use rocket_contrib::json::Json;
use crate::modules::member_management::model::qualifications::QualificationList;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::database::controller::groups::get_groups_for_member;
use crate::database::controller::member_qualifications::get_qualifcation_categories;
@ -23,7 +23,7 @@ pub fn api_member_qualifications_read(
let groups = get_groups_for_member(&settings, member_id);
if !check_access(&settings, member_id, groups, caller.entity_id, crate::permissions::modules::member_management::profile::qualifications::VIEW.to_string()){
if !check_access_to_member_and_group(&settings, member_id, groups, caller.entity_id, crate::permissions::modules::member_management::profile::qualifications::VIEW.to_string()){
return Err(Json(ApiError::new(401, "Keine Berechtigung Qualifikationen für dieses Mitglied abzurufen!".to_string()).to_wrapper()))
}

View File

@ -4,4 +4,7 @@ pub mod members;
pub mod model;
pub mod units;
pub mod users;
pub mod communicator;
pub mod communicator;
pub mod resources;
pub mod appointments;
pub mod info;

View File

@ -0,0 +1 @@
pub mod vehicles;

View File

@ -0,0 +1,37 @@
use rocket::State;
use crate::helper::settings::Settings;
use crate::helper::session_cookies::model::SessionCookie;
use rocket_contrib::json::Json;
use chrono::NaiveDateTime;
use crate::database::model::vehicles::Vehicle;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::parse_member_cookie;
#[derive(Queryable, Clone, Deserialize, Serialize)]
pub struct CreateVehicleData{
pub(crate) entity_id: uuid::Uuid,
pub(crate) identifier: String,
pub(crate) numberplate: Option<String>,
pub(crate) description: Option<String>,
pub(crate) next_inspection: Option<String>,
pub(crate) is_operational: bool,
pub(crate) admissible_total_weight: Option<f32>,
pub(crate) vehicle_category: Option<String>,
pub(crate) required_license: Option<String>,
}
#[post("/api/resources/vehicles", format = "json", data = "<create_vehicle_data>")]
pub fn create_vehicle(
settings: State<Settings>,
cookie: SessionCookie,
create_vehicle_data: Json<CreateVehicleData>,
) -> Result<Json<Vehicle>, Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission("modules.member_management.groups.create".to_string()) {
return Err(Json(
ApiError::new(403, "Keine Berechtigung, Gruppen anzulegen!".to_string()).to_wrapper(),
));
}
return Err(Json(ApiError::new(501, "Nicht implementiert!".to_string()).to_wrapper()))
}

View File

@ -0,0 +1,3 @@
pub mod create;
pub mod read;
pub mod update;

View File

@ -0,0 +1,65 @@
use rocket::State;
use crate::helper::settings::Settings;
use crate::helper::session_cookies::model::SessionCookie;
use rocket_contrib::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::database::model::vehicles::{VehicleCategory, Vehicle};
use crate::modules::api::member_management::controller::parser::parse_member_cookie;
use crate::database::controller::vehicles::{get_vehicle_categories, get_vehicles};
use crate::helper::translate_diesel_error::translate_diesel;
use crate::database::controller::members::check_access_to_resource;
#[get("/api/resources/vehicles/categories", format = "json")]
pub fn read_vehicle_categories(
settings: State<Settings>,
cookie: SessionCookie,
) -> Result<Json<Vec<VehicleCategory>>, Json<ApiErrorWrapper>> {
parse_member_cookie(cookie.member)?;
match get_vehicle_categories(&settings){
Ok(category) => Ok(Json(category)),
Err(e) => Err(translate_diesel(e))
}
}
#[get("/api/resources/vehicles?<entries>&<page>", format = "json")]
pub fn read_vehicle_list(
settings: State<Settings>,
cookie: SessionCookie,
entries: Option<i64>,
page: Option<i64>,
) -> Result<Json<Vec<Vehicle>>, Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission(crate::permissions::modules::resource_management::vehicles::list::VIEW.to_string()){
return Err(Json(ApiError::new(403, "Keine Berechtigung Fahrzeugliste abzurufen!".to_string()).to_wrapper()))
}
//Apply default limit of 20 entries per page if none given
let entries = match entries{
Some(entries) => {
if entries > 0{
entries
}else{
20
}
}
None => 20
};
//Apply default page 1 if no page given
let page = match page{
Some(page) => {
if page > 0{
page
}else{
1
}
}
None => 1
};
match get_vehicles(&settings, entries, (page-1)*entries){
Ok(category) => Ok(Json(category)),
Err(e) => Err(translate_diesel(e))
}
}

View File

@ -0,0 +1,69 @@
use rocket::State;
use crate::helper::settings::Settings;
use crate::helper::session_cookies::model::SessionCookie;
use rocket_contrib::json::Json;
use crate::modules::api::resources::vehicles::create::CreateVehicleData;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
use crate::database::controller::vehicles::change_vehicle;
use crate::database::model::vehicles::Vehicle;
use chrono::NaiveDate;
use crate::helper::translate_diesel_error::translate_diesel;
#[put("/api/resources/vehicles/<vehicle_id>", format = "json", data = "<change_vehicle_data>")]
pub fn update_vehicle(
settings: State<Settings>,
cookie: SessionCookie,
change_vehicle_data: Json<CreateVehicleData>,
vehicle_id: String,
) -> Result<(), Json<ApiErrorWrapper>> {
let caller = parse_member_cookie(cookie.member)?;
if !caller.has_permission(crate::permissions::modules::resource_management::vehicles::core::EDIT.to_string()) {
return Err(Json(
ApiError::new(403, "Keine Berechtigung, Fahrzeuge zu ändern!".to_string()).to_wrapper(),
));
}
let vehicle_id = parse_uuid(vehicle_id)?;
if vehicle_id != change_vehicle_data.entity_id{
return Err(Json(ApiError::new(400, "Vehicle id doesn't match vehicle id in body!".to_string()).to_wrapper()))
}
let next_inspection = match change_vehicle_data.next_inspection.clone(){
Some(d) => {
match NaiveDate::parse_from_str(&d, "%Y-%m-%d") {
Ok(date) => Some(date),
Err(e) => {
warn!("Couldn't parse submitted vehicle next inspection date: {}", e);
return Err(Json(ApiError::new(400, "Next inspection date couldn't be parsed into Date!".to_string()).to_wrapper()))
}
}
},
None => None
};
let vehicle_category = match change_vehicle_data.vehicle_category.clone(){
Some(c) => {
Some(parse_uuid(c)?)
},
None => None
};
let vehicle = Vehicle{
entity_id: change_vehicle_data.entity_id,
identifier: change_vehicle_data.identifier.clone(),
numberplate: change_vehicle_data.numberplate.clone(),
description: change_vehicle_data.description.clone(),
is_operational: change_vehicle_data.is_operational,
admissible_total_weight: change_vehicle_data.admissible_total_weight,
required_license: None,
vehicle_category
};
match change_vehicle(&settings, vehicle){
Ok(_) => Ok(()),
Err(e) => Err(translate_diesel(e))
}
}

View File

@ -4,7 +4,7 @@ use crate::helper::session_cookies::model::SessionCookie;
use rocket_contrib::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::database::controller::units_members::remove_member_from_unit;
use crate::helper::translate_diesel_error::translate_diesel;
@ -14,7 +14,7 @@ pub fn delete_member_from_unit(settings: State<Settings>, cookie: SessionCookie,
let member_id = parse_uuid(member_id)?;
let unit_id = parse_uuid(unit_id)?;
if !check_member_has_access(&settings, caller.entity_id, unit_id, crate::permissions::modules::units::members::EDIT){
if !check_access_to_resource(&settings, caller.entity_id, unit_id, crate::permissions::modules::units::members::EDIT){
return Err(Json(ApiError::new(403, "Keine Berechtigung Einheitenmitglieder zu ändern!".to_string()).to_wrapper()))
}

View File

@ -5,7 +5,7 @@ use rocket_contrib::json::Json;
use crate::modules::api::model::api_outcome::ApiErrorWrapper;
use crate::database::model::units::RawUnit;
use crate::modules::api::member_management::controller::parser::parse_member_cookie;
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::database::controller::units::get_units;
use crate::helper::translate_diesel_error::translate_diesel;
@ -22,13 +22,12 @@ pub fn read_unit_list(
Err(e) => return Err(translate_diesel(e))
};
match with_caller_permission{
None => Ok(Json(units)),
Some(permission) => {
let mut unit_list : Vec<RawUnit> = vec![];
for unit in units{
if check_member_has_access(&settings, caller.entity_id, unit.unit_id, &permission){
if check_access_to_resource(&settings, caller.entity_id, unit.unit_id, &permission){
unit_list.push(unit);
}
}

View File

@ -4,7 +4,7 @@ use crate::helper::session_cookies::model::SessionCookie;
use rocket_contrib::json::Json;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
use crate::database::controller::members::check_member_has_access;
use crate::database::controller::members::check_access_to_resource;
use crate::database::controller::units_members::add_member_to_unit;
use crate::helper::translate_diesel_error::translate_diesel;
@ -14,7 +14,7 @@ pub fn put_member_in_unit(settings: State<Settings>, cookie: SessionCookie, unit
let member_id = parse_uuid(member_id)?;
let unit_id = parse_uuid(unit_id)?;
if !check_member_has_access(&settings, caller.entity_id, unit_id, crate::permissions::modules::units::members::EDIT){
if !check_access_to_resource(&settings, caller.entity_id, unit_id, crate::permissions::modules::units::members::EDIT){
return Err(Json(ApiError::new(403, "Keine Berechtigung Einheitsmitglieder zu ändern!".to_string()).to_wrapper()))
}

View File

@ -5,7 +5,7 @@ use crate::modules::member_management::model::login::Login;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use rocket_contrib::json::Json;
use crate::modules::api::member_management::controller::parser::parse_member_cookie;
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::database::controller::groups::get_groups_for_member;
use crate::database::controller::users::add_user_to_member;
use crate::helper::translate_diesel_error::translate_diesel;
@ -24,7 +24,7 @@ pub fn create_user(settings: State<Settings>, cookie: SessionCookie, create_user
let member_groups = get_groups_for_member(&settings, data.member_id);
if caller.entity_id != data.member_id { //Skip permission check if user edits own login
if !check_access(&settings, data.member_id, member_groups, caller.entity_id, "modules.member_management.profile.login.edit".to_string()) {
if !check_access_to_member_and_group(&settings, data.member_id, member_groups, caller.entity_id, "modules.member_management.profile.login.edit".to_string()) {
return Err(Json(ApiError::new(401, "Keine Rechte Login für dieses Mitglied anzulegen!".to_string()).to_wrapper()))
}
}

View File

@ -4,7 +4,7 @@ use crate::helper::session_cookies::model::SessionCookie;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use rocket_contrib::json::Json;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::database::controller::groups::get_groups_for_member;
use crate::database::controller::users::remove_user;
use crate::helper::translate_diesel_error::translate_diesel;
@ -24,7 +24,7 @@ pub fn delete_user(settings: State<Settings>, cookie: SessionCookie, user_id: St
let member_groups = get_groups_for_member(&settings, member.entity_id);
if caller.entity_id != member.entity_id { //Skip permission check if user edits own login
if !check_access(&settings, member.entity_id, member_groups, caller.entity_id, "modules.member_management.profile.login.edit".to_string()) {
if !check_access_to_member_and_group(&settings, member.entity_id, member_groups, caller.entity_id, "modules.member_management.profile.login.edit".to_string()) {
return Err(Json(ApiError::new(401, "Keine Rechte Login für dieses Mitglied anzulegen!".to_string()).to_wrapper()))
}
}

View File

@ -5,7 +5,7 @@ use crate::modules::member_management::model::login::Login;
use crate::modules::api::model::api_outcome::{ApiErrorWrapper, ApiError};
use rocket_contrib::json::Json;
use crate::modules::api::member_management::controller::parser::{parse_member_cookie, parse_uuid};
use crate::helper::check_access::check_access;
use crate::helper::check_access::check_access_to_member_and_group;
use crate::database::controller::groups::get_groups_for_member;
use crate::database::controller::users::update_user_email;
use crate::helper::translate_diesel_error::translate_diesel;
@ -31,7 +31,7 @@ pub fn update_user(settings: State<Settings>, cookie: SessionCookie, user_id: St
let member_groups = get_groups_for_member(&settings, data.member_id);
if caller.entity_id != data.member_id { //Skip permission check if user edits own login
if !check_access(&settings, data.member_id, member_groups, caller.entity_id, "modules.member_management.profile.login.edit".to_string()) {
if !check_access_to_member_and_group(&settings, data.member_id, member_groups, caller.entity_id, "modules.member_management.profile.login.edit".to_string()) {
return Err(Json(ApiError::new(401, "Keine Rechte Login für dieses Mitglied zu verändern!".to_string()).to_wrapper()))
}
}

View File

@ -19,7 +19,7 @@ pub fn member_management_selection(
None => return Err(Status::Unauthorized),
};
if !member.has_permission("modules.member_management.list.view".to_string()) {
if !member.has_permission(crate::permissions::modules::member_management::list::VIEW.to_string()) {
return Err(Status::Forbidden);
}

View File

@ -0,0 +1 @@
pub mod vehicles;

View File

@ -0,0 +1 @@
pub mod vehicle_list;

View File

@ -0,0 +1,62 @@
use crate::helper::session_cookies::model::SessionCookie;
use rocket::State;
use crate::helper::settings::Settings;
use crate::modules::member_management::model::filter_form::FilterForm;
use rocket_contrib::templates::Template;
use rocket::http::Status;
use crate::helper::sitebuilder::model::general::{Header, Footer, Script, Stylesheet};
use crate::helper::sitebuilder::model::sidebar::Sidebar;
#[derive(Serialize)]
pub struct VehicleList{
pub header: Header,
pub footer: Footer,
pub sidebar: Sidebar,
}
#[get("/portal/rm/vehicle_list?<page>")]
pub fn vehicle_list(
cookie: SessionCookie,
settings: State<Settings>,
page: Option<i64>
) -> Result<Template, Status> {
let member = match cookie.member {
//Unwraps member from cookie or send user to login if no member specified (user skipped member selection)
Some(member) => member,
None => return Err(Status::Unauthorized),
};
if !member.has_permission(crate::permissions::modules::resource_management::vehicles::list::VIEW.to_string()) {
return Err(Status::Forbidden);
}
let page = match page{
Some(page) => page,
None => 1,
};
let header = Header {
html_language: "de".to_string(),
site_title: "Fahrzeuge".to_string(),
stylesheets: vec![Stylesheet {
path: "/css/errms.css".to_string(),
}],
};
let footer = Footer {
scripts: vec![Script {
path: "/js/resource_management_vehicle_list.js".to_string(),
}, Script{
path: "/js/scheduler.js".to_string()
}],
};
let mut sidebar = Sidebar::new(member.clone());
sidebar.resource_management.active = true;
let vehicle_list = VehicleList{
header,
footer,
sidebar
};
Ok(Template::render("module_resource_management_vehicle_list", vehicle_list))
}

View File

@ -23,6 +23,30 @@ table! {
}
}
table! {
use diesel::sql_types::*;
use diesel_geometry::sql_types::*;
appointment_types (type_id) {
type_id -> Uuid,
name -> Text,
description -> Nullable<Text>,
interval -> Nullable<Int4>,
}
}
table! {
use diesel::sql_types::*;
use diesel_geometry::sql_types::*;
appointments (id) {
id -> Uuid,
type_id -> Uuid,
entity_id -> Uuid,
appointment_date -> Date,
}
}
table! {
use diesel::sql_types::*;
use diesel_geometry::sql_types::*;
@ -290,6 +314,17 @@ table! {
}
}
table! {
use diesel::sql_types::*;
use diesel_geometry::sql_types::*;
vehicle_categories (id) {
id -> Uuid,
name -> Text,
description -> Nullable<Text>,
}
}
table! {
use diesel::sql_types::*;
use diesel_geometry::sql_types::*;
@ -299,15 +334,17 @@ table! {
identifier -> Text,
numberplate -> Nullable<Text>,
description -> Nullable<Text>,
next_inspection -> Nullable<Date>,
is_operational -> Bool,
admissible_total_weight -> Nullable<Float4>,
required_license -> Nullable<Text>,
vehicle_category -> Nullable<Uuid>,
}
}
joinable!(addresses_entities -> addresses (address_id));
joinable!(addresses_entities -> entities (entitiy_id));
joinable!(appointments -> appointment_types (type_id));
joinable!(appointments -> entities (entity_id));
joinable!(buildings -> entities (entity_id));
joinable!(communication_targets -> communication_types (com_type));
joinable!(communication_targets -> entities (entity_id));
@ -335,10 +372,13 @@ joinable!(units_members -> members (member_id));
joinable!(units_members -> units (unit_id));
joinable!(vehicles -> entities (entity_id));
joinable!(vehicles -> license_categories (required_license));
joinable!(vehicles -> vehicle_categories (vehicle_category));
allow_tables_to_appear_in_same_query!(
addresses,
addresses_entities,
appointment_types,
appointments,
buildings,
communication_targets,
communication_types,
@ -363,5 +403,6 @@ allow_tables_to_appear_in_same_query!(
units,
units_members,
users,
vehicle_categories,
vehicles,
);