Files
crmPRO/templates/site/layout-logged.php
Jacek Pyziak a4a35c8d62 feat: Implement module permissions system with database-driven access control
- Added `users_permissions` table for managing user permissions.
- Created `PermissionRepository` for handling permission logic.
- Refactored `controls\Users::permissions()` to utilize the new database structure.
- Introduced AJAX endpoint for saving user permissions.
- Enhanced user management UI with permission checkboxes.
- Added vacation management template for handling employee absences.
- Implemented tests for `PermissionRepository`.
2026-02-26 20:17:03 +01:00

171 lines
8.4 KiB
PHP

<!DOCTYPE html>
<html lang="pl">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>crmPro</title>
<meta name="keywords" content="">
<meta name="description" content="">
<meta name="robots" content="all">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.43/moment-timezone-with-data.min.js"></script>
<script type="text/javascript" src="/libraries/framework/vendor/jquery/jquery_ui/jquery-ui.min.js"></script>
<script type="text/javascript" src="/libraries/framework/vendor/plugins/moment/pl.js"></script>
<script type="text/javascript" src="/libraries/framework/vendor/plugins/datepicker/js/bootstrap-datetimepicker.js"></script>
<script type="text/javascript" src="/libraries/framework/vendor/plugins/daterange/daterangepicker.js"></script>
<script type="text/javascript" src="/libraries/jquery-confirm/jquery-confirm.min.js"></script>
<script type="text/javascript" src="/libraries/select2/js/select2.full.min.js"></script>
<script type="text/javascript" src="/libraries/Simple-Gant-master/frappe-gantt.js"></script>
<script type="text/javascript" src="/libraries/icheck-1.0.2/icheck.min.js"></script>
<script type="text/javascript" src="/libraries/functions.js"></script>
<link rel="Stylesheet" type="text/css" href="/libraries/framework/skin/default_skin/css/theme.css">
<link rel="stylesheet" type="text/css" href="/libraries/framework/vendor/plugins/datepicker/css/bootstrap-datetimepicker.css">
<link rel="Stylesheet" type="text/css" href="/libraries/framework/vendor/plugins/daterange/daterangepicker.css">
<link rel="stylesheet" type="text/css" href="/libraries/jquery-confirm/jquery-confirm.min.css">
<link rel="stylesheet" type="text/css" href="/libraries/select2/css/select2.min.css">
<link rel="stylesheet" type="text/css" href="/libraries/select2/css/select2-bootstrap-5-theme.min.css">
<link rel="stylesheet" type="text/css" href="/libraries/font-awesome-4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="/libraries/Simple-Gant-master/frappe-gantt.css">
<link rel="stylesheet" type="text/css" href="/libraries/icheck-1.0.2/skins/all.css">
<link rel="stylesheet" type="text/css" href="/layout/style.css">
</head>
<body class="logged">
<div class="sidebar" id="sidebar">
<div class="sidebar-header">
<a href="/" class="sidebar-logo">crm<span>Pro</span></a>
<div class="sidebar-toggle" id="sidebar-toggle"><i class="fa fa-angle-double-left"></i></div>
</div>
<nav class="sidebar-nav">
<ul>
<? $can_manage_users = (int)$this -> user['id'] === 1;?>
<? if ( \controls\Users::permissions( $this -> user[ 'id' ], 'tasks' ) ):?>
<li>
<a href="/tasks/main_view/"><i class="fa fa-check-square-o"></i> <span>Zadania</span></a>
</li>
<? endif;?>
<? if ( \controls\Users::permissions( $this -> user[ 'id' ], 'projects' ) ):?>
<li>
<a href="/projects/main_view/"><i class="fa fa-folder-open"></i> <span>Projekty</span></a>
</li>
<? endif;?>
<? if ( \controls\Users::permissions( $this -> user[ 'id' ], 'work_time' ) ):?>
<li>
<a href="/tasks/work_time/"><i class="fa fa-clock-o"></i> <span>Czas pracy</span></a>
</li>
<? endif;?>
<? if ( \controls\Users::permissions( $this -> user[ 'id' ], 'finances' ) ):?>
<li>
<a href="/finances/main_view/"><i class="fa fa-money"></i> <span>Finanse</span></a>
</li>
<? endif;?>
<? if ( \controls\Users::permissions( $this -> user[ 'id' ], 'crm' ) ):?>
<li>
<a href="/crm/main_view/"><i class="fa fa-address-book"></i> <span>CRM</span></a>
</li>
<? endif;?>
<? if ( \controls\Users::permissions( $this -> user[ 'id' ], 'wiki' ) ):?>
<li>
<a href="/wiki/main_view/"><i class="fa fa-book"></i> <span>Wiki</span></a>
</li>
<? endif;?>
<? if ( $can_manage_users ):?>
<li class="has-submenu">
<a href="#" class="submenu-toggle"><i class="fa fa-users"></i> <span>U&#380;ytkownicy</span> <i class="fa fa-angle-down submenu-arrow"></i></a>
<ul class="sidebar-submenu">
<li><a href="/users/main_view/"><i class="fa fa-list"></i> <span>Lista</span></a></li>
<li><a href="/users/vacations/"><i class="fa fa-calendar-times-o"></i> <span>Urlopy</span></a></li>
</ul>
</li>
<? endif;?>
</ul>
</nav>
<div class="sidebar-footer">
<? $impersonator_user = \S::get_session( 'impersonator_user' );?>
<? if ( is_array( $impersonator_user ) and isset( $impersonator_user['id'] ) and (int)$impersonator_user['id'] === 1 ):?>
<a href="/users/back_to_admin/" class="sidebar-footer-link"><i class="fa fa-sign-in"></i> <span>Powrót do admina</span></a>
<? endif;?>
<div class="sidebar-user">
<i class="fa fa-user"></i> <span><?= htmlspecialchars( $this -> user[ 'email' ] );?></span>
</div>
<a href="/users/settings/" class="sidebar-footer-link"><i class="fa fa-cog"></i> <span>Ustawienia</span></a>
<a href="/users/logout/" class="sidebar-footer-link logout"><i class="fa fa-sign-out"></i> <span>Wyloguj się</span></a>
</div>
</div>
<div class="content-wrapper" id="content-wrapper">
<div class="top-bar">
<div class="top-bar-left">
<i class="fa fa-bars" id="mobile-toggle"></i>
</div>
</div>
<div class="main">
<? if ( $this -> alert ):?>
<div class="alert"><?= htmlspecialchars( $this -> alert );?></div>
<? endif;?>
<?= $this -> content;?>
</div>
</div>
<div class="default_popup">
<div class="popup_content">
<div class="popup_header">
<div class="title"></div>
<div class="close"><i class="fa fa-times"></i></div>
</div>
<div class="popup_body"></div>
</div>
</div>
<script type="text/javascript">
$( function() {
$( 'input.date' ).datepicker({
language: 'pl',
autoClose: true
});
});
$( 'body' ).on( 'click', '.default_popup .close', function(e) {
e.preventDefault();
$( '.default_popup .popup_body' ).empty();
$( '.default_popup' ).hide();
return false;
});
function show_default_popup( content ) {
$( '.default_popup .popup_body' ).html( content );
$( '.default_popup' ).fadeIn();
}
// Sidebar toggle
$( '#sidebar-toggle, #mobile-toggle' ).on( 'click', function() {
$( '#sidebar' ).toggleClass( 'collapsed' );
$( '#content-wrapper' ).toggleClass( 'expanded' );
var icon = $( '#sidebar-toggle i' );
if ( $( '#sidebar' ).hasClass( 'collapsed' ) ) {
icon.removeClass( 'fa-angle-double-left' ).addClass( 'fa-angle-double-right' );
} else {
icon.removeClass( 'fa-angle-double-right' ).addClass( 'fa-angle-double-left' );
}
});
// Submenu toggle
$( '.submenu-toggle' ).on( 'click', function(e) {
e.preventDefault();
var $li = $( this ).closest( '.has-submenu' );
$li.toggleClass( 'open' );
});
// Auto-open submenu if current page matches
$( '.sidebar-submenu a' ).each( function() {
if ( window.location.pathname.indexOf( $( this ).attr( 'href' ) ) === 0 ) {
$( this ).closest( '.has-submenu' ).addClass( 'open' );
$( this ).closest( 'li' ).addClass( 'active' );
}
});
</script>
</body>
</html>