vesione staibile - debug fix
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
<?php $__env->startSection('title', __('Not Found')); ?>
|
||||||
|
<?php $__env->startSection('code', '404'); ?>
|
||||||
|
<?php $__env->startSection('message', __('Not Found')); ?>
|
||||||
|
|
||||||
|
<?php echo $__env->make('errors::minimal', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH /var/www/html/glastree/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/views/404.blade.php ENDPATH**/ ?>
|
||||||
@@ -0,0 +1,350 @@
|
|||||||
|
<?php $__env->startSection('title', 'Email - ' . ucfirst($folder)); ?>
|
||||||
|
<?php $__env->startSection('page_title', 'Email'); ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$currentFolder = $folders->firstWhere('type', $folder);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php $__env->startSection('content'); ?>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title"><i class="fas fa-envelope mr-2"></i>Email</h3>
|
||||||
|
<div class="card-tools">
|
||||||
|
<div class="btn-group mr-2">
|
||||||
|
<?php $__currentLoopData = $folders; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $f): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
<a href="<?php echo e(route('email.index', $f->type)); ?>"
|
||||||
|
class="btn btn-xs <?php echo e($folder === $f->type ? 'btn-primary' : 'btn-default'); ?>">
|
||||||
|
<i class="fas <?php echo e($f->icon); ?>"></i>
|
||||||
|
<?php echo e($f->name); ?>
|
||||||
|
|
||||||
|
<?php if($f->type === 'inbox' && $messages->where('is_read', false)->count() > 0): ?>
|
||||||
|
<span class="badge badge-light"><?php echo e($messages->where('is_read', false)->count()); ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
</div>
|
||||||
|
<a href="<?php echo e(route('email.compose')); ?>" class="btn btn-success btn-xs">
|
||||||
|
<i class="fas fa-plus"></i> Nuova Email
|
||||||
|
</a>
|
||||||
|
<button class="btn btn-primary btn-xs" onclick="syncEmails()" id="syncBtn">
|
||||||
|
<i class="fas fa-sync"></i> Ricevi/Invia
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<div class="card-header pb-0">
|
||||||
|
<div class="row align-items-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="form-inline">
|
||||||
|
<div class="custom-control custom-checkbox">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="selectAll" onchange="toggleAll(this)">
|
||||||
|
<label class="custom-control-label" for="selectAll">Seleziona tutto</label>
|
||||||
|
</div>
|
||||||
|
<span class="ml-3 text-muted" id="selectedCount">0 selezionati</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="input-group input-group-sm float-right" style="width: 220px;">
|
||||||
|
<select class="form-control" id="bulkAction">
|
||||||
|
<option value="">Azioni di massa...</option>
|
||||||
|
<?php if($folder !== 'trash'): ?>
|
||||||
|
<option value="mark_read">Marca come letto</option>
|
||||||
|
<option value="mark_unread">Marca come non letto</option>
|
||||||
|
<option value="star">Aggiungi a preferiti</option>
|
||||||
|
<option value="unstar">Rimuovi da preferiti</option>
|
||||||
|
<option value="move_trash">Sposta nel cestino</option>
|
||||||
|
<?php else: ?>
|
||||||
|
<option value="empty_trash">Svuota cestino</option>
|
||||||
|
<?php endif; ?>
|
||||||
|
</select>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button class="btn btn-secondary" type="button" onclick="executeBulkAction()">Applica</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 30px;"></th>
|
||||||
|
<th style="width: 30px;"></th>
|
||||||
|
<th style="width: 150px;">
|
||||||
|
<?php $sort = request('sort'); $dir = request('direction'); ?>
|
||||||
|
<?php if($folder === 'sent' || $folder === 'inviate'): ?>
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'to_email', 'direction' => $sort === 'to_email' && $dir === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark text-decoration-none">
|
||||||
|
Destinatario <?php echo $sort === 'to_email' ? ($dir === 'asc' ? '▲' : '▼') : ''; ?>
|
||||||
|
|
||||||
|
</a>
|
||||||
|
<?php else: ?>
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'from_email', 'direction' => $sort === 'from_email' && $dir === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark text-decoration-none">
|
||||||
|
Mittente <?php echo $sort === 'from_email' ? ($dir === 'asc' ? '▲' : '▼') : ''; ?>
|
||||||
|
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'subject', 'direction' => $sort === 'subject' && $dir === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark text-decoration-none">
|
||||||
|
Oggetto <?php echo $sort === 'subject' ? ($dir === 'asc' ? '▲' : '▼') : ''; ?>
|
||||||
|
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th style="width: 120px;">
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'received_at', 'direction' => $sort === 'received_at' && $dir === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark text-decoration-none">
|
||||||
|
Data <?php echo $sort === 'received_at' ? ($dir === 'asc' ? '▲' : '▼') : ''; ?>
|
||||||
|
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php $__empty_1 = true; $__currentLoopData = $messages; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $message): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||||||
|
<tr class="<?php echo e($message->is_read ? '' : 'font-weight-bold'); ?>">
|
||||||
|
<td style="width: 30px;" onclick="event.stopPropagation()">
|
||||||
|
<input type="checkbox" class="email-checkbox" value="<?php echo e($message->id); ?>" onchange="updateCount()">
|
||||||
|
</td>
|
||||||
|
<td style="width: 30px;" onclick="event.stopPropagation(); window.location='<?php echo e(route('email.show', [$folder, $message->id])); ?>'">
|
||||||
|
<?php if($message->is_starred): ?>
|
||||||
|
<i class="fas fa-star text-warning"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td onclick="window.location='<?php echo e(route('email.show', [$folder, $message->id])); ?>'">
|
||||||
|
<?php echo e($message->is_sent ? 'A: ' . $message->to_email : ($message->from_name ?: $message->from_email)); ?>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td onclick="window.location='<?php echo e(route('email.show', [$folder, $message->id])); ?>'">
|
||||||
|
<?php echo e($message->subject ?? '(senza oggetto)'); ?>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php if($message->received_at): ?>
|
||||||
|
<?php echo e($message->received_at->format('d/m/Y')); ?>
|
||||||
|
|
||||||
|
<?php elseif($message->sent_at): ?>
|
||||||
|
<?php echo e($message->sent_at->format('d/m/Y')); ?>
|
||||||
|
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="5" class="text-center text-muted py-4">
|
||||||
|
<i class="fas fa-inbox fa-2x mb-2"></i>
|
||||||
|
<p>Nessuna email</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<?php echo e($messages->withQueryString()->links('vendor.pagination.simple-bootstrap-4')); ?>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
|
||||||
|
<?php $__env->startPush('styles'); ?>
|
||||||
|
<style>
|
||||||
|
/* Bootstrap 4 Pagination override */
|
||||||
|
.pagination {
|
||||||
|
display: flex !important;
|
||||||
|
padding-left: 0;
|
||||||
|
list-style: none;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
margin: 0;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-item {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-link {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
padding: 0.5rem 0.75rem;
|
||||||
|
margin-left: -1px;
|
||||||
|
line-height: 1.25;
|
||||||
|
color: #007bff;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-item.active .page-link {
|
||||||
|
z-index: 3;
|
||||||
|
color: #fff;
|
||||||
|
background-color: #007bff;
|
||||||
|
border-color: #007bff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-item.disabled .page-link {
|
||||||
|
color: #6c757d;
|
||||||
|
pointer-events: none;
|
||||||
|
background-color: #fff;
|
||||||
|
border-color: #dee2e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-link:hover {
|
||||||
|
color: #0056b3;
|
||||||
|
background-color: #e9ecef;
|
||||||
|
border-color: #dee2e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Icons as text characters */
|
||||||
|
.pagination .page-link::before,
|
||||||
|
.pagination .page-link::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<?php $__env->stopPush(); ?>
|
||||||
|
|
||||||
|
<?php if($syncInterval > 0 && $folder === 'inbox'): ?>
|
||||||
|
<?php $__env->startPush('scripts'); ?>
|
||||||
|
<script>
|
||||||
|
let syncInterval = <?php echo e($syncInterval * 60 * 1000); ?>;
|
||||||
|
let syncTimeout;
|
||||||
|
|
||||||
|
function autoSync() {
|
||||||
|
fetch('<?php echo e(url('email/sync/quick')); ?>', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
|
console.log('Auto sync completed');
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('Auto sync failed');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function startAutoSync() {
|
||||||
|
if (syncInterval > 0) {
|
||||||
|
syncTimeout = setInterval(autoSync, syncInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopAutoSync() {
|
||||||
|
if (syncTimeout) {
|
||||||
|
clearInterval(syncTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
startAutoSync();
|
||||||
|
|
||||||
|
document.addEventListener('visibilitychange', function() {
|
||||||
|
if (document.hidden) {
|
||||||
|
stopAutoSync();
|
||||||
|
} else {
|
||||||
|
startAutoSync();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<?php $__env->stopPush(); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php $__env->startSection('scripts'); ?>
|
||||||
|
<script>
|
||||||
|
function toggleAll(checkbox) {
|
||||||
|
const checkboxes = document.querySelectorAll('.email-checkbox');
|
||||||
|
checkboxes.forEach(function(cb) {
|
||||||
|
cb.checked = checkbox.checked;
|
||||||
|
});
|
||||||
|
updateCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCount() {
|
||||||
|
const checkboxes = document.querySelectorAll('.email-checkbox:checked');
|
||||||
|
document.getElementById('selectedCount').textContent = checkboxes.length + ' selezionati';
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeBulkAction() {
|
||||||
|
const select = document.getElementById('bulkAction');
|
||||||
|
const action = select.value;
|
||||||
|
if (!action) {
|
||||||
|
alert('Seleziona un\'azione');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action === 'empty_trash') {
|
||||||
|
if (!confirm('Sei sicuro di voler svuotare il cestino? Questa azione non è reversibile.')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkboxes = document.querySelectorAll('.email-checkbox:checked');
|
||||||
|
if (action !== 'empty_trash' && checkboxes.length === 0) {
|
||||||
|
alert('Seleziona almeno una email');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ids = [];
|
||||||
|
if (action !== 'empty_trash') {
|
||||||
|
ids = Array.from(checkboxes).map(function(cb) {
|
||||||
|
return cb.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('<?php echo e(route('email.bulk')); ?>', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ ids: ids, action: action })
|
||||||
|
}).then(function(response) {
|
||||||
|
return response.json();
|
||||||
|
}).then(function(data) {
|
||||||
|
if (data.success) {
|
||||||
|
// Reset checkboxes before reload to avoid ghost selection
|
||||||
|
document.querySelectorAll('.email-checkbox').forEach(function(cb) {
|
||||||
|
cb.checked = false;
|
||||||
|
});
|
||||||
|
document.getElementById('selectAll').checked = false;
|
||||||
|
updateCount();
|
||||||
|
window.location.href = window.location.href;
|
||||||
|
} else {
|
||||||
|
alert(data.message || 'Errore');
|
||||||
|
}
|
||||||
|
}).catch(function() {
|
||||||
|
alert('Errore');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncEmails() {
|
||||||
|
const btn = document.getElementById('syncBtn');
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Sincronizzazione...';
|
||||||
|
|
||||||
|
fetch('<?php echo e(url('email/sync/quick')); ?>', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'X-CSRF-TOKEN': '<?php echo e(csrf_token()); ?>',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}).then(function(response) {
|
||||||
|
return response.json();
|
||||||
|
}).then(function(data) {
|
||||||
|
if (data.success) {
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
alert(data.message || 'Errore durante la sincronizzazione');
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.innerHTML = '<i class="fas fa-sync"></i> Ricevi/Invia';
|
||||||
|
}
|
||||||
|
}).catch(function(error) {
|
||||||
|
alert('Errore di connessione');
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.innerHTML = '<i class="fas fa-sync"></i> Ricevi/Invia';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
<?php echo $__env->make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH /var/www/html/glastree/resources/views/email/index.blade.php ENDPATH**/ ?>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php if($paginator->hasPages()): ?>
|
||||||
|
<ul class="pagination justify-content-center" role="navigation">
|
||||||
|
|
||||||
|
<?php if($paginator->onFirstPage()): ?>
|
||||||
|
<li class="page-item disabled" aria-disabled="true" aria-label="<?php echo app('translator')->get('pagination.previous'); ?>">
|
||||||
|
<span class="page-link" aria-hidden="true">‹</span>
|
||||||
|
</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="<?php echo e($paginator->previousPageUrl()); ?>" rel="prev" aria-label="<?php echo app('translator')->get('pagination.previous'); ?>">‹</a>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
|
||||||
|
<?php $__currentLoopData = $elements; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $element): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
|
||||||
|
<?php if(is_string($element)): ?>
|
||||||
|
<li class="page-item disabled" aria-disabled="true"><span class="page-link"><?php echo e($element); ?></span></li>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
|
||||||
|
<?php if(is_array($element)): ?>
|
||||||
|
<?php $__currentLoopData = $element; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $page => $url): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
<?php if($page == $paginator->currentPage()): ?>
|
||||||
|
<li class="page-item active" aria-current="page"><span class="page-link"><?php echo e($page); ?></span></li>
|
||||||
|
<?php elseif($page >= $paginator->currentPage() - 2 && $page <= $paginator->currentPage() + 2): ?>
|
||||||
|
<li class="page-item"><a class="page-link" href="<?php echo e($url); ?>"><?php echo e($page); ?></a></li>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
|
||||||
|
|
||||||
|
<?php if($paginator->hasMorePages()): ?>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="<?php echo e($paginator->nextPageUrl()); ?>" rel="next" aria-label="<?php echo app('translator')->get('pagination.next'); ?>">›</a>
|
||||||
|
</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<li class="page-item disabled" aria-disabled="true" aria-label="<?php echo app('translator')->get('pagination.next'); ?>">
|
||||||
|
<span class="page-link" aria-hidden="true">›</span>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
|
</ul>
|
||||||
|
<?php endif; ?><?php /**PATH /var/www/html/glastree/resources/views/vendor/pagination/simple-bootstrap-4.blade.php ENDPATH**/ ?>
|
||||||
+1890
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
|||||||
|
<?php $__env->startSection('title', 'Gestione Ruoli'); ?>
|
||||||
|
<?php $__env->startSection('page_title', 'Gestione Ruoli'); ?>
|
||||||
|
|
||||||
|
<?php $__env->startSection('breadcrumbs'); ?>
|
||||||
|
<li class="breadcrumb-item active">Admin</li>
|
||||||
|
<li class="breadcrumb-item active">Ruoli</li>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
|
||||||
|
<?php $__env->startSection('content'); ?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Ruoli Predefiniti</h3>
|
||||||
|
<a href="/admin/ruoli/create" class="btn btn-success btn-sm float-right">
|
||||||
|
<i class="fas fa-plus"></i> Nuovo Ruolo
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nome</th>
|
||||||
|
<th>Descrizione</th>
|
||||||
|
<th>Utenti</th>
|
||||||
|
<th>Permessi</th>
|
||||||
|
<th style="width: 100px;">Azioni</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php $__currentLoopData = $ruoli; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $ruolo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
<tr>
|
||||||
|
<td><strong><?php echo e($ruolo->name); ?></strong></td>
|
||||||
|
<td><?php echo e($ruolo->description); ?></td>
|
||||||
|
<td><span class="badge badge-info"><?php echo e($ruolo->users_count); ?></span></td>
|
||||||
|
<td>
|
||||||
|
<?php $__currentLoopData = $ruolo->permissions; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $module => $level): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
<span class="badge badge-<?php echo e($level == 2 ? 'success' : ($level == 1 ? 'info' : 'secondary')); ?>">
|
||||||
|
<?php echo e(ucfirst($module)); ?>: <?php echo e($level == 2 ? 'Full' : ($level == 1 ? 'Read' : 'None')); ?>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="<?php echo e(url('/admin/ruoli/' . $ruolo->id . '/edit')); ?>" class="btn btn-xs btn-warning">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<?php if($ruolo->users_count == 0): ?>
|
||||||
|
<form method="POST" action="<?php echo e(url('/admin/ruoli/' . $ruolo->id)); ?>" style="display: inline;">
|
||||||
|
<?php echo csrf_field(); ?> <?php echo method_field('DELETE'); ?>
|
||||||
|
<button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('Eliminare questo ruolo?')">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<?php else: ?>
|
||||||
|
<button type="button" class="btn btn-xs btn-secondary" disabled title="Utenti associati: <?php echo e($ruolo->users_count); ?>">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
<?php echo $__env->make('admin.layout', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH /var/www/html/glastree/resources/views/admin/ruoli/index.blade.php ENDPATH**/ ?>
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,972 @@
|
|||||||
|
<?php $appName = \App\Models\AppSetting::getAppName() ?? 'Glastree'; ?>
|
||||||
|
<?php $__env->startSection('title', 'Guida - ' . $appName); ?>
|
||||||
|
<?php $__env->startSection('page_title', 'Guida alla Configurazione'); ?>
|
||||||
|
<?php $__env->startSection('breadcrumbs'); ?>
|
||||||
|
<li class="breadcrumb-item"><a href="/">Home</a></li>
|
||||||
|
<li class="breadcrumb-item active">Guida</li>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
|
||||||
|
<?php $__env->startSection('content'); ?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<div class="card card-outline card-primary">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Argomenti</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body p-0">
|
||||||
|
<ul class="nav nav-pills flex-column" id="helpTabs">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" href="#help-webdav" data-toggle="tab">
|
||||||
|
<i class="fas fa-cloud mr-2"></i> WebDAV / Nextcloud
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#help-googledrive" data-toggle="tab">
|
||||||
|
<i class="fab fa-google-drive mr-2"></i> Google Drive
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#help-tipologie" data-toggle="tab">
|
||||||
|
<i class="fas fa-tags mr-2"></i> Tipologie e Dati
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#help-email" data-toggle="tab">
|
||||||
|
<i class="fas fa-envelope mr-2"></i> Email / SMTP
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#help-installazione" data-toggle="tab">
|
||||||
|
<i class="fas fa-terminal mr-2"></i> Installazione
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#help-backup" data-toggle="tab">
|
||||||
|
<i class="fas fa-hdd mr-2"></i> Backup e Migrazione
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="#help-docker" data-toggle="tab">
|
||||||
|
<i class="fab fa-docker mr-2"></i> Docker
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<a href="<?php echo e(route('help.pdf.download')); ?>" class="btn btn-primary btn-block">
|
||||||
|
<i class="fas fa-file-pdf mr-2"></i> Scarica Guida PDF
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-9">
|
||||||
|
<div class="tab-content">
|
||||||
|
|
||||||
|
<div class="tab-pane active" id="help-webdav">
|
||||||
|
<div class="card card-outline card-info">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title"><i class="fas fa-cloud mr-2"></i> WebDAV / Nextcloud</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>Cos'è</h5>
|
||||||
|
<p>WebDAV è un protocollo che permette di accedere a file su server remoti. Nextcloud lo utilizza per la sincronizzazione dei file.</p>
|
||||||
|
|
||||||
|
<h5>Configurazione</h5>
|
||||||
|
<p>Vai in <strong>Impostazioni → Repository</strong> e crea un nuovo repository di tipo WebDAV.</p>
|
||||||
|
|
||||||
|
<div class="callout callout-info">
|
||||||
|
<h6>Campi obbligatori</h6>
|
||||||
|
<dl class="row mb-0">
|
||||||
|
<dt class="col-sm-3">Nome</dt>
|
||||||
|
<dd class="col-sm-9">Un nome descrittivo (es. "Nextcloud Lavoro")</dd>
|
||||||
|
<dt class="col-sm-3">Base URI</dt>
|
||||||
|
<dd class="col-sm-9">L'URL del tuo server WebDAV.
|
||||||
|
<br><em>Nextcloud:</em> <code>https://tuodominio.it/remote.php/dav/files/utente/</code>
|
||||||
|
<br><em>Altri:</em> <code>https://server.webdav.it/</code></dd>
|
||||||
|
<dt class="col-sm-3">Root</dt>
|
||||||
|
<dd class="col-sm-9">Percorso base all'interno del server (es. <code>/Documenti/</code>). Lascia <code>/</code> per usare la root.</dd>
|
||||||
|
<dt class="col-sm-3">Username</dt>
|
||||||
|
<dd class="col-sm-9">Il tuo nome utente</dd>
|
||||||
|
<dt class="col-sm-3">Password</dt>
|
||||||
|
<dd class="col-sm-9">La password dell'account</dd>
|
||||||
|
<dt class="col-sm-3">Auth Type</dt>
|
||||||
|
<dd class="col-sm-9"><code>Basic</code> per la maggior parte dei server (Nextcloud, ownCloud).</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="mt-4">⚠️ Nome utente con @ (chiocciola)</h5>
|
||||||
|
<p>Se il tuo nome utente contiene il carattere <code>@</code> (es. <code>mario.rossi@azienda.com</code>), segui queste regole:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Nel campo "Base URI":</strong> l'indirizzo email deve essere <strong>URL-encoded</strong>:
|
||||||
|
<br><code>https://server.it/remote.php/dav/files/mario.rossi%40azienda.com/</code>
|
||||||
|
<br><small>(il carattere <code>@</code> diventa <code>%40</code>)</small></li>
|
||||||
|
<li><strong>Nel campo "Username":</strong> inserisci l'indirizzo email <strong>normale</strong> con la <code>@</code> vera.</li>
|
||||||
|
</ul>
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
Il sistema gestisce automaticamente la differenza tra l'URI (che richiede <code>%40</code>) e l'autenticazione (che usa la <code>@</code> reale).
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Test connessione</h5>
|
||||||
|
<p>Dopo aver salvato, usa il pulsante <span class="badge badge-success"><i class="fas fa-plug"></i> Test</span> nella tabella dei repository per verificare che la connessione funzioni.</p>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Importare file</h5>
|
||||||
|
<p>Apri la sezione <strong>Documenti</strong>, clicca sul pulsante del repository nella toolbar per sfogliare i file remoti, poi clicca <span class="badge badge-success"><i class="fas fa-save"></i> Salva tra i documenti</span> su un file per importarlo come documento locale.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="tab-pane" id="help-googledrive">
|
||||||
|
<div class="card card-outline card-danger">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title"><i class="fab fa-google-drive mr-2"></i> Google Drive</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>Cos'è</h5>
|
||||||
|
<p>Integrazione con Google Drive per sfogliare e importare file direttamente dal tuo spazio Google Drive.</p>
|
||||||
|
|
||||||
|
<h5>Requisiti</h5>
|
||||||
|
<ol>
|
||||||
|
<li>Un account Google / Google Workspace</li>
|
||||||
|
<li>Un progetto sulla <strong>Google Cloud Console</strong> con l'API Google Drive abilitata</li>
|
||||||
|
<li>Credenziali OAuth 2.0 (Client ID e Client Secret)</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h5>Passo 1: Creare il progetto Google Cloud</h5>
|
||||||
|
<ol>
|
||||||
|
<li>Vai su <a href="https://console.developers.google.com/" target="_blank">Google Cloud Console</a></li>
|
||||||
|
<li>Crea un nuovo progetto o selezionane uno esistente</li>
|
||||||
|
<li>Vai a <strong>API e servizi → Libreria</strong></li>
|
||||||
|
<li>Cerca "<strong>Google Drive API</strong>" e <strong>abilitala</strong></li>
|
||||||
|
<li>Vai a <strong>API e servizi → Credenziali</strong></li>
|
||||||
|
<li>Clicca "<strong>Crea credenziali → ID client OAuth</strong>"</li>
|
||||||
|
<li>Tipo applicazione: "<strong>Applicazione Web</strong>"</li>
|
||||||
|
<li><strong>URI di reindirizzamento autorizzato:</strong> aggiungi <code><?php echo e(url('/auth/google-drive/callback')); ?></code></li>
|
||||||
|
<li>Completa la creazione e <strong>copia Client ID e Client Secret</strong></li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h5>Passo 2: Configurazione nell'app</h5>
|
||||||
|
<ol>
|
||||||
|
<li>Vai in <strong>Impostazioni → Repository</strong></li>
|
||||||
|
<li>Clicca "<strong>Nuovo Repository</strong>" e seleziona tipo <strong>Google Drive</strong></li>
|
||||||
|
<li>Inserisci un nome descrittivo (es. "Drive Lavoro")</li>
|
||||||
|
<li>Incolla <strong>Client ID</strong> e <strong>Client Secret</strong></li>
|
||||||
|
<li><strong>Folder ID (opzionale):</strong> se vuoi limitare l'accesso a una cartella specifica, inserisci il suo ID (lo trovi nell'URL quando apri la cartella in Google Drive: <code>https://drive.google.com/drive/folders/<strong>ID_QUI</strong></code>)</li>
|
||||||
|
<li>Clicca "<strong>Autorizza Google Drive</strong>" — verrai reindirizzato a Google per concedere i permessi</li>
|
||||||
|
<li>Dopo l'autorizzazione, il refresh token verrà salvato automaticamente</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h5>⚠️ Google Drive API non abilitata</h5>
|
||||||
|
<p>Se vedi l'errore <em>"Google Drive API non abilitata"</em> nel test connessione, significa che l'API Drive non è stata attivata nel tuo progetto Google Cloud.</p>
|
||||||
|
<div class="callout callout-danger">
|
||||||
|
<h6>Soluzione</h6>
|
||||||
|
<p>Vai su <a href="https://console.developers.google.com/apis/api/drive.googleapis.com/overview" target="_blank">
|
||||||
|
https://console.developers.google.com/apis/api/drive.googleapis.com/overview
|
||||||
|
</a></p>
|
||||||
|
<p>Seleziona il progetto corretto dall'header in alto, clicca <strong>"Enable"</strong> e attendi qualche minuto prima di riprovare.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5>Importare file</h5>
|
||||||
|
<p>Stessa procedura di WebDAV: apri <strong>Documenti</strong>, clicca sul repository Drive, sfoglia i file e usa <span class="badge badge-success"><i class="fas fa-save"></i> Salva tra i documenti</span>.</p>
|
||||||
|
|
||||||
|
<h5 class="mt-4">⚠️ File Google (Documenti, Fogli, Presentazioni)</h5>
|
||||||
|
<p>I file creati con Google Workspace (Documenti Google, Fogli Google, Presentazioni Google, Disegni Google) non possono essere scaricati direttamente perché non hanno un formato binario nativo.</p>
|
||||||
|
<p>Il sistema li converte automaticamente in formato Office Open XML durante l'import:</p>
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead><tr><th>File Google</th><th>Formato convertito</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>Documento Google</td><td><code>.docx</code> (Word)</td></tr>
|
||||||
|
<tr><td>Foglio Google</td><td><code>.xlsx</code> (Excel)</td></tr>
|
||||||
|
<tr><td>Presentazione Google</td><td><code>.pptx</code> (PowerPoint)</td></tr>
|
||||||
|
<tr><td>Disegno Google</td><td><code>.png</code> (Immagine)</td></tr>
|
||||||
|
<tr><td>Altri (Moduli, Script)</td><td><code>.pdf</code> (PDF)</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
Il nome del file viene automaticamente esteso con l'estensione corretta (es. "Relazione" → "Relazione.docx").
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="tab-pane" id="help-tipologie">
|
||||||
|
<div class="card card-outline card-success">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title"><i class="fas fa-tags mr-2"></i> Tipologie e Gestione Dati</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>Tipologie Documenti</h5>
|
||||||
|
<p>Le tipologie classificano i documenti (avatar, galleria, documento, statuto, altro).</p>
|
||||||
|
<p>Si gestiscono in <strong>Impostazioni → Tipologie Documenti</strong>. Puoi aggiungere, rinominare, riordinare ed eliminare tipologie (tranne quelle con documenti associati).</p>
|
||||||
|
|
||||||
|
<h5>Tipologie Individui</h5>
|
||||||
|
<p>Classificano gli individui (es. socio, volontario, dipendente). Si gestiscono in <strong>Impostazioni → Tipologie</strong>.</p>
|
||||||
|
|
||||||
|
<h5>Tipologie Eventi</h5>
|
||||||
|
<p>Classificano gli eventi (es. riunione, assemblea, formazione). Si gestiscono in <strong>Impostazioni → Tipologie Eventi</strong>.</p>
|
||||||
|
|
||||||
|
<h5>Ruoli Individui</h5>
|
||||||
|
<p>Definiscono il ruolo o la carica di un individuo (es. presidente, segretario, tesoriere). Si gestiscono in <strong>Impostazioni → Ruoli</strong>.</p>
|
||||||
|
|
||||||
|
<h5>Visibilità Documenti</h5>
|
||||||
|
<p>Ogni documento può avere diversi livelli di visibilità:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Pubblico</strong> — visibile a tutti gli utenti</li>
|
||||||
|
<li><strong>Individuo</strong> — visibile solo a uno specifico individuo</li>
|
||||||
|
<li><strong>Gruppo</strong> — visibile solo ai membri di un gruppo</li>
|
||||||
|
<li><strong>Evento</strong> — visibile solo ai partecipanti di un evento</li>
|
||||||
|
<li><strong>Mailing</strong> — visibile solo ai membri di una mailing list</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="tab-pane" id="help-email">
|
||||||
|
<div class="card card-outline card-warning">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title"><i class="fas fa-envelope mr-2"></i> Email / SMTP</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>Configurazione Email</h5>
|
||||||
|
<p>Vai in <strong>Impostazioni → Email</strong> per configurare la posta elettronica.</p>
|
||||||
|
|
||||||
|
<h5>Server IMAP (Ricezione)</h5>
|
||||||
|
<p>Usato per ricevere e leggere le email direttamente nell'app.</p>
|
||||||
|
<div class="callout callout-info">
|
||||||
|
<h6>Campi consigliati per provider comuni</h6>
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead><tr><th>Provider</th><th>Host</th><th>Porta</th><th>Crittografia</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>Gmail</td><td><code>imap.gmail.com</code></td><td><code>993</code></td><td>SSL</td></tr>
|
||||||
|
<tr><td>Outlook/Office 365</td><td><code>outlook.office365.com</code></td><td><code>993</code></td><td>SSL</td></tr>
|
||||||
|
<tr><td>Libero</td><td><code>imapmail.libero.it</code></td><td><code>993</code></td><td>SSL</td></tr>
|
||||||
|
<tr><td>Aruba</td><td><code>imap.aruba.it</code></td><td><code>993</code></td><td>SSL</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5>Server SMTP (Invio)</h5>
|
||||||
|
<p>Usato per inviare email dall'app. Supporta account multipli (mittenti).</p>
|
||||||
|
<div class="callout callout-info">
|
||||||
|
<h6>Campi consigliati per provider comuni</h6>
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead><tr><th>Provider</th><th>Host</th><th>Porta</th><th>Crittografia</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>Gmail</td><td><code>smtp.gmail.com</code></td><td><code>587</code></td><td>TLS</td></tr>
|
||||||
|
<tr><td>Outlook/Office 365</td><td><code>smtp.office365.com</code></td><td><code>587</code></td><td>TLS</td></tr>
|
||||||
|
<tr><td>Libero</td><td><code>smtp.libero.it</code></td><td><code>465</code></td><td>SSL</td></tr>
|
||||||
|
<tr><td>Aruba</td><td><code>smtp.aruba.it</code></td><td><code>465</code></td><td>SSL</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5>Gmail / Google Workspace</h5>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i>
|
||||||
|
Gmail richiede una <strong>Password per l'app</strong> (non la password normale) se usi la verifica in due passaggi. Puoi generarla su
|
||||||
|
<a href="https://myaccount.google.com/apppasswords" target="_blank">https://myaccount.google.com/apppasswords</a>.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5>Mailing</h5>
|
||||||
|
<p>Le <strong>Mailing List</strong> permettono di inviare email a gruppi predefiniti di destinatari.</p>
|
||||||
|
<ul>
|
||||||
|
<li>Crea una mailing list in <strong>Mailing List → Nuova</strong></li>
|
||||||
|
<li>Puoi popolare la lista da individui, gruppi o manualmente</li>
|
||||||
|
<li>Invia email alla lista da <strong>Email → Nuova Email</strong>, selezionando la mailing list come destinatario</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h5>Test connessione</h5>
|
||||||
|
<p>Dopo aver configurato i server, usa il pulsante <span class="badge badge-success"><i class="fas fa-vial"></i> Test Connessione</span> per verificare che IMAP e SMTP funzionino correttamente.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="tab-pane" id="help-backup">
|
||||||
|
<div class="card card-outline card-danger">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title"><i class="fas fa-hdd mr-2"></i> Backup e Migrazione Server</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>Cos'è</h5>
|
||||||
|
<p>Il sistema di backup crea un archivio ZIP contenente tutto il necessario per ripristinare l'applicazione su un nuovo server. Include database, file caricati e configurazione.</p>
|
||||||
|
|
||||||
|
<h5>Cosa include il backup</h5>
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead><tr><th>Componente</th><th>Incluso</th><th>Dettagli</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>Database (MySQL)</td><td><span class="badge badge-success">Sempre</span></td><td>Struttura, dati, stored procedure, eventi, trigger</td></tr>
|
||||||
|
<tr><td>File caricati</td><td><span class="badge badge-success">Opzionale</span></td><td>Documenti, avatar, gallerie</td></tr>
|
||||||
|
<tr><td>Configurazione .env</td><td><span class="badge badge-success">Opzionale</span></td><td>APP_KEY, credenziali DB, SMTP, token OAuth</td></tr>
|
||||||
|
<tr><td>Metadati</td><td><span class="badge badge-success">Sempre</span></td><td>Versione app, PHP, Laravel</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Come eseguire un backup</h5>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="callout callout-info">
|
||||||
|
<h6>Via Interfaccia Web</h6>
|
||||||
|
<ol class="mb-0">
|
||||||
|
<li>Vai su <strong>Admin → Backup</strong></li>
|
||||||
|
<li>Verifica le impostazioni (includi files/.env)</li>
|
||||||
|
<li>Clicca <span class="badge badge-primary"><i class="fas fa-play"></i> Esegui Backup Ora</span></li>
|
||||||
|
<li>Scarica il file ZIP generato</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="callout callout-success">
|
||||||
|
<h6>Via Comando</h6>
|
||||||
|
<pre class="mb-0"><code>php artisan backup:run</code></pre>
|
||||||
|
<p class="mb-0 mt-2 small">Il file viene creato in <code>storage/app/backups/</code></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Backup automatico</h5>
|
||||||
|
<p>Puoi abilitare il backup automatico dalla pagina <strong>Admin → Backup</strong>:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Frequenza:</strong> giornaliero, settimanale o mensile</li>
|
||||||
|
<li><strong>Ora:</strong> consigliata 03:00 (notte)</li>
|
||||||
|
<li><strong>Requisito:</strong> il cron di Laravel deve essere configurato sul server</li>
|
||||||
|
</ul>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<i class="fas fa-clock mr-2"></i>
|
||||||
|
Per il backup automatico, aggiungi questo cron:
|
||||||
|
<pre class="mt-2 mb-0"><code>* * * * * cd <?php echo e(base_path()); ?> && php artisan schedule:run >> /dev/null 2>&1</code></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-4">
|
||||||
|
|
||||||
|
<h4><i class="fas fa-truck mr-2"></i> Procedura di Migrazione Completa</h4>
|
||||||
|
<p>Segui questa procedura per migrare l'applicazione su un nuovo server LAMP (Linux, Apache, MySQL, PHP).</p>
|
||||||
|
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<i class="fas fa-exclamation-triangle mr-2"></i>
|
||||||
|
<strong>ATTENZIONE: APP_KEY</strong>
|
||||||
|
<p class="mb-0 mt-2">L'APP_KEY cripta i dati sensibili (password email SMTP, token OAuth Google Drive, ecc.).</p>
|
||||||
|
<ul class="mt-2">
|
||||||
|
<li><strong>Se hai il .env originale dal backup:</strong> NON rigenerare APP_KEY — mantieni i dati criptati accessibili.</li>
|
||||||
|
<li><strong>Se hai perso il .env:</strong> DEVI rigenerare APP_KEY, ma perderai l'accesso ai dati criptati esistenti. Dovrai riconfigurare SMTP e OAuth.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 1: Preparazione del server</h5>
|
||||||
|
<pre><code>sudo apt update && sudo apt upgrade -y</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 2: Installa LAMP + PHP 8.4</h5>
|
||||||
|
<pre><code>sudo apt install -y apache2 mariadb-server php8.4 php8.4-cli \
|
||||||
|
php8.4-mysql php8.4-xml php8.4-mbstring php8.4-curl \
|
||||||
|
php8.4-zip php8.4-bcmath php8.4-gd php8.4-intl \
|
||||||
|
composer git unzip
|
||||||
|
|
||||||
|
sudo a2enmod rewrite</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 3: Ottieni l'applicazione</h5>
|
||||||
|
<div class="callout callout-info py-2">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
Puoi clonare il repository con git oppure estrarre il file ZIP ricevuto nella cartella <code>/var/www/glastree</code>.
|
||||||
|
</div>
|
||||||
|
<pre><code>cd /var/www
|
||||||
|
|
||||||
|
# Opzione A — Git clone
|
||||||
|
git clone <URL_REPOSITORY> glastree
|
||||||
|
|
||||||
|
# Opzione B — ZIP (se non hai git)
|
||||||
|
# unzip /percorso/del/glastree.zip -d glastree
|
||||||
|
|
||||||
|
cd glastree
|
||||||
|
composer install --no-dev --optimize-autoloader
|
||||||
|
npm ci && npm run build</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 4: Carica il backup</h5>
|
||||||
|
<p>Copia il file <code>backup.zip</code> sul nuovo server e estrailo:</p>
|
||||||
|
<pre><code>mkdir -p /tmp/restore
|
||||||
|
unzip backup.zip -d /tmp/restore/
|
||||||
|
ls -la /tmp/restore/
|
||||||
|
# Dovresti vedere: database.sql .env files/ manifest.json</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 5: Crea database e importa</h5>
|
||||||
|
<pre><code>sudo mysql -u root <<EOF
|
||||||
|
CREATE DATABASE glastree CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
CREATE USER 'glastree'@'localhost' IDENTIFIED BY 'ScegliPasswordFortep4ss!';
|
||||||
|
GRANT ALL ON glastree.* TO 'glastree'@'localhost';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
EOF
|
||||||
|
|
||||||
|
mysql -u glastree -p glastree < /tmp/restore/database.sql</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 6: Configura .env</h5>
|
||||||
|
<pre><code>cp /tmp/restore/.env .env
|
||||||
|
# Modifica se necessario:
|
||||||
|
# APP_URL=https://nuovo-dominio.it
|
||||||
|
# DB_HOST=localhost
|
||||||
|
# DB_DATABASE=glastree
|
||||||
|
# DB_USERNAME=glastree
|
||||||
|
# DB_PASSWORD=ScegliPasswordFortep4ss!
|
||||||
|
|
||||||
|
# DECIDI SULL'APP_KEY (leggi avviso sopra!)
|
||||||
|
# php artisan key:generate ← SOLO se non hai il .env originale</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 7: Ripristina file e permessi</h5>
|
||||||
|
<pre><code>cp -r /tmp/restore/files/* storage/app/documenti/
|
||||||
|
|
||||||
|
sudo chown -R www-data:www-data storage bootstrap/cache
|
||||||
|
sudo chmod -R 755 storage bootstrap/cache
|
||||||
|
|
||||||
|
php artisan storage:link</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 8: Cache</h5>
|
||||||
|
<pre><code>php artisan optimize:clear
|
||||||
|
php artisan config:cache
|
||||||
|
php artisan route:cache
|
||||||
|
php artisan view:cache</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 9: Configura Apache</h5>
|
||||||
|
<pre><code>sudo tee /etc/apache2/sites-available/glastree.conf <<APACHE
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerName glastree.esempio.it
|
||||||
|
DocumentRoot /var/www/glastree/public
|
||||||
|
|
||||||
|
<Directory /var/www/glastree/public>
|
||||||
|
Options -Indexes +FollowSymLinks
|
||||||
|
AllowOverride All
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
ErrorLog \${APACHE_LOG_DIR}/glastree_error.log
|
||||||
|
CustomLog \${APACHE_LOG_DIR}/glastree_access.log combined
|
||||||
|
</VirtualHost>
|
||||||
|
APACHE
|
||||||
|
|
||||||
|
sudo a2dissite 000-default.conf
|
||||||
|
sudo a2ensite glastree.conf
|
||||||
|
sudo systemctl reload apache2</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 10: SSL Let's Encrypt</h5>
|
||||||
|
<pre><code>sudo apt install -y certbot python3-certbot-apache
|
||||||
|
sudo certbot --apache -d glastree.esempio.it</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 11: Cron per backup automatico</h5>
|
||||||
|
<pre><code>sudo crontab -u www-data -e
|
||||||
|
# Inserisci:
|
||||||
|
* * * * * cd /var/www/glastree && php artisan schedule:run >> /dev/null 2>&1</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Passo 12: Verifica finale</h5>
|
||||||
|
<ol>
|
||||||
|
<li>Apri https://glastree.esempio.it nel browser</li>
|
||||||
|
<li>Fai login con le credenziali esistenti</li>
|
||||||
|
<li>Verifica: Dashboard, Documenti, Impostazioni, Email</li>
|
||||||
|
<li>Se hai rigenerato APP_KEY: riconfigura SMTP e OAuth Google Drive</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<hr class="my-4">
|
||||||
|
|
||||||
|
<h5>PHP Web Installer</h5>
|
||||||
|
<p>L'applicazione include un <strong>wizard di installazione web</strong> nella cartella <code>installer/</code>. Questo wizard gestisce sia installazioni fresh che ripristino da backup.</p>
|
||||||
|
<p>Vedi la sezione <strong>Installazione</strong> per la guida completa.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="tab-pane" id="help-docker">
|
||||||
|
<div class="card card-outline card-primary">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title"><i class="fab fa-docker mr-2"></i> Docker</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>Creare un'immagine Docker con dati di base</h5>
|
||||||
|
<p>Puoi creare un'immagine Docker pronta all'uso che include l'applicazione e i dati di base (tipologie documenti, tipologie eventi, ruoli). Scegli la configurazione in base alle tue esigenze:</p>
|
||||||
|
|
||||||
|
<div class="callout callout-info">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
<strong>Ottenere il codice:</strong> puoi clonare il repository con <code>git clone <URL> glastree</code> oppure, se non hai git, estrarre il file ZIP ricevuto con <code>unzip glastree.zip -d glastree</code> e posizionarti nella cartella <code>glastree</code> prima di procedere.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="callout callout-info">
|
||||||
|
<h6><i class="fas fa-database"></i> SQLite (Leggero)</h6>
|
||||||
|
<p class="mb-0 small">Database embedded, nessun servizio aggiuntivo. Ideale per demo, test, sviluppo locale o ambienti con poca concorrenza.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="callout callout-success">
|
||||||
|
<h6><i class="fas fa-server"></i> MySQL (Standard)</h6>
|
||||||
|
<p class="mb-0 small">Database separato in un container MySQL. Configurazione standard, ideale per produzione, staging e ambienti con piu utenti.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="mt-4">1. Dockerfile (comune a entrambe le modalita)</h5>
|
||||||
|
<p>Crea un file <code>Dockerfile</code> nella root del progetto:</p>
|
||||||
|
<pre><code>FROM php:8.4-apache
|
||||||
|
|
||||||
|
# Abilita mod_rewrite
|
||||||
|
RUN docker-php-ext-enable opcache \
|
||||||
|
&& a2enmod rewrite
|
||||||
|
|
||||||
|
# Installa estensioni PHP (sia SQLite che MySQL)
|
||||||
|
RUN docker-php-ext-install pdo_mysql pdo_sqlite bcmath gd zip
|
||||||
|
|
||||||
|
# Installa Composer
|
||||||
|
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||||
|
|
||||||
|
# Configura DocumentRoot per Laravel
|
||||||
|
ENV APACHE_DOCUMENT_ROOT=/var/www/html/public
|
||||||
|
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf \
|
||||||
|
&& sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
|
||||||
|
|
||||||
|
# Copia l'applicazione
|
||||||
|
COPY . /var/www/html/
|
||||||
|
|
||||||
|
# Installa dipendenze e compila asset
|
||||||
|
RUN composer install --no-dev --optimize-autoloader \
|
||||||
|
&& mkdir -p storage/app/public \
|
||||||
|
&& mkdir -p storage/framework/cache/data \
|
||||||
|
&& mkdir -p storage/framework/sessions \
|
||||||
|
&& mkdir -p storage/framework/views \
|
||||||
|
&& mkdir -p storage/logs \
|
||||||
|
&& mkdir -p bootstrap/cache \
|
||||||
|
&& chown -R www-data:www-data storage bootstrap/cache
|
||||||
|
|
||||||
|
# Entrypoint per inizializzazione
|
||||||
|
COPY docker-entrypoint.sh /usr/local/bin/
|
||||||
|
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["docker-entrypoint.sh"]
|
||||||
|
CMD ["apache2-foreground"]</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">2. Entrypoint Script (comune)</h5>
|
||||||
|
<p>Crea <code>docker-entrypoint.sh</code>. Lo script rileva automaticamente la configurazione in base alle variabili d'ambiente:</p>
|
||||||
|
<pre><code>#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Se .env non esiste, lo genera dalle variabili d'ambiente
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
cp .env.example .env
|
||||||
|
|
||||||
|
if [ "$DB_CONNECTION" = "mysql" ]; then
|
||||||
|
# Configura MySQL
|
||||||
|
sed -i "s/DB_CONNECTION=mysql/DB_CONNECTION=mysql/" .env
|
||||||
|
sed -i "s/DB_HOST=.*/DB_HOST=${DB_HOST:-mysql}/" .env
|
||||||
|
sed -i "s/DB_PORT=.*/DB_PORT=${DB_PORT:-3306}/" .env
|
||||||
|
sed -i "s/DB_DATABASE=.*/DB_DATABASE=${DB_DATABASE:-glastree}/" .env
|
||||||
|
sed -i "s/DB_USERNAME=.*/DB_USERNAME=${DB_USERNAME:-glastree}/" .env
|
||||||
|
sed -i "s/DB_PASSWORD=.*/DB_PASSWORD=${DB_PASSWORD:-secret}/" .env
|
||||||
|
|
||||||
|
# Attende che MySQL sia pronto
|
||||||
|
echo "Attendo MySQL..."
|
||||||
|
until php -r "new PDO('mysql:host=${DB_HOST:-mysql};dbname=${DB_DATABASE:-glastree}', '${DB_USERNAME:-glastree}', '${DB_PASSWORD:-secret}');" 2>/dev/null; do
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "MySQL pronto."
|
||||||
|
else
|
||||||
|
# Configura SQLite
|
||||||
|
sed -i 's/DB_CONNECTION=mysql/DB_CONNECTION=sqlite/' .env
|
||||||
|
sed -i 's/DB_HOST=.*//' .env
|
||||||
|
sed -i 's/DB_PORT=.*//' .env
|
||||||
|
sed -i 's/DB_DATABASE=.*/DB_DATABASE=\/var\/www\/html\/database\/database.sqlite/' .env
|
||||||
|
sed -i 's/DB_USERNAME=.*//' .env
|
||||||
|
sed -i 's/DB_PASSWORD=.*//' .env
|
||||||
|
|
||||||
|
touch database/database.sqlite
|
||||||
|
chmod 664 database/database.sqlite
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Genera APP_KEY
|
||||||
|
php artisan key:generate --force
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Esegui migration e seed se il database e vuoto
|
||||||
|
if [ ! -f .db_initialized ]; then
|
||||||
|
php artisan migrate --force
|
||||||
|
php artisan db:seed --force
|
||||||
|
touch .db_initialized
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Configura storage link
|
||||||
|
php artisan storage:link --force 2>/dev/null || true
|
||||||
|
|
||||||
|
exec "$@"</code></pre>
|
||||||
|
<pre><code>chmod +x docker-entrypoint.sh</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">3. Seed Base Dati (comune)</h5>
|
||||||
|
<p>Per includere tipologie documenti, tipologie eventi e ruoli, crea un seeder dedicato:</p>
|
||||||
|
<pre><code>php artisan make:seeder DockerBaseDataSeeder</code></pre>
|
||||||
|
<p>Contenuto di <code>database/seeders/DockerBaseDataSeeder.php</code>:</p>
|
||||||
|
<pre><code><?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class DockerBaseDataSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
// Tipologie Documenti
|
||||||
|
$tipologieDoc = ['documento', 'avatar', 'galleria', 'statuto', 'programma', 'locandina', 'altro'];
|
||||||
|
foreach ($tipologieDoc as $ord => $nome) {
|
||||||
|
DB::table('tipologie_documenti')->updateOrInsert(
|
||||||
|
['nome' => $nome],
|
||||||
|
['descrizione' => ucfirst($nome), 'ordine' => $ord + 1, 'attiva' => true]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tipologie Eventi
|
||||||
|
$tipologieEventi = [
|
||||||
|
['nome' => 'catechesi', 'descrizione' => 'Catechesi'],
|
||||||
|
['nome' => 'liturgia', 'descrizione' => 'Liturgia'],
|
||||||
|
['nome' => 'animazione', 'descrizione' => 'Animazione'],
|
||||||
|
['nome' => 'formazione', 'descrizione' => 'Formazione'],
|
||||||
|
['nome' => 'incontro', 'descrizione' => 'Incontro'],
|
||||||
|
['nome' => 'riunione', 'descrizione' => 'Riunione'],
|
||||||
|
['nome' => 'festa', 'descrizione' => 'Festa'],
|
||||||
|
['nome' => 'altro', 'descrizione' => 'Altro'],
|
||||||
|
];
|
||||||
|
foreach ($tipologieEventi as $ord => $t) {
|
||||||
|
DB::table('tipologie_eventi')->updateOrInsert(
|
||||||
|
['nome' => $t['nome']],
|
||||||
|
['descrizione' => $t['descrizione'], 'ordine' => $ord + 1, 'attiva' => true]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ruoli
|
||||||
|
$ruoli = ['presidente', 'vicepresidente', 'segretario', 'tesoriere', 'consigliere', 'volontario', 'socio', 'altro'];
|
||||||
|
foreach ($ruoli as $ord => $nome) {
|
||||||
|
DB::table('ruoli')->updateOrInsert(
|
||||||
|
['nome' => $nome],
|
||||||
|
['descrizione' => ucfirst($nome), 'ordine' => $ord + 1, 'attiva' => true]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}</code></pre>
|
||||||
|
<p>Registralo in <code>database/seeders/DatabaseSeeder.php</code>:</p>
|
||||||
|
<pre><code>$this->call([
|
||||||
|
// ... altri seeder ...
|
||||||
|
DockerBaseDataSeeder::class,
|
||||||
|
]);</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">4. Docker Compose</h5>
|
||||||
|
|
||||||
|
<h6 class="text-info"><i class="fas fa-database mr-1"></i> Opzione A — SQLite (leggero)</h6>
|
||||||
|
<pre><code>services:
|
||||||
|
glastree:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
volumes:
|
||||||
|
- glastree_storage:/var/www/html/storage
|
||||||
|
- glastree_db:/var/www/html/database
|
||||||
|
environment:
|
||||||
|
- APP_ENV=production
|
||||||
|
- APP_DEBUG=false
|
||||||
|
- APP_URL=http://localhost:8080
|
||||||
|
- DB_CONNECTION=sqlite
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
glastree_storage:
|
||||||
|
glastree_db:</code></pre>
|
||||||
|
|
||||||
|
<h6 class="mt-3 text-success"><i class="fas fa-server mr-1"></i> Opzione B — MySQL (standard)</h6>
|
||||||
|
<pre><code>services:
|
||||||
|
glastree:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
volumes:
|
||||||
|
- glastree_storage:/var/www/html/storage
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
- APP_ENV=production
|
||||||
|
- APP_DEBUG=false
|
||||||
|
- APP_URL=http://localhost:8080
|
||||||
|
- DB_CONNECTION=mysql
|
||||||
|
- DB_HOST=mysql
|
||||||
|
- DB_PORT=3306
|
||||||
|
- DB_DATABASE=glastree
|
||||||
|
- DB_USERNAME=glastree
|
||||||
|
- DB_PASSWORD=secret
|
||||||
|
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
volumes:
|
||||||
|
- mysql_data:/var/lib/mysql
|
||||||
|
environment:
|
||||||
|
- MYSQL_DATABASE=glastree
|
||||||
|
- MYSQL_USER=glastree
|
||||||
|
- MYSQL_PASSWORD=secret
|
||||||
|
- MYSQL_ROOT_PASSWORD=root_secret
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 3s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
glastree_storage:
|
||||||
|
mysql_data:</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">5. Build e avvio</h5>
|
||||||
|
<p>Assicurati di essere nella cartella del progetto (ottenuta via <code>git clone</code> o estraendo il ZIP), poi:</p>
|
||||||
|
<pre><code># Costruisci l'immagine (comune)
|
||||||
|
docker build -t glastree:latest .
|
||||||
|
|
||||||
|
# Avvia con SQLite
|
||||||
|
docker compose -f docker-compose.yml up -d
|
||||||
|
|
||||||
|
# Oppure avvia con MySQL
|
||||||
|
# docker compose -f docker-compose.mysql.yml up -d
|
||||||
|
|
||||||
|
# Apri nel browser
|
||||||
|
open http://localhost:8080</code></pre>
|
||||||
|
|
||||||
|
<h5 class="mt-4">6. Primo accesso</h5>
|
||||||
|
<p>Al primo avvio, l'entrypoint esegue automaticamente migration e seed. Troverai gia popolati:</p>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Tipologie Documenti:</strong> documento, avatar, galleria, statuto, programma, locandina, altro</li>
|
||||||
|
<li><strong>Tipologie Eventi:</strong> catechesi, liturgia, animazione, formazione, incontro, riunione, festa, altro</li>
|
||||||
|
<li><strong>Ruoli:</strong> presidente, vicepresidente, segretario, tesoriere, consigliere, volontario, socio, altro</li>
|
||||||
|
</ul>
|
||||||
|
<p>Dovrai creare il primo utente amministratore via CLI:</p>
|
||||||
|
<pre><code>docker exec -it glastree php artisan tinker --execute="
|
||||||
|
\$u = new \App\Models\User;
|
||||||
|
\$u->name = 'Amministratore';
|
||||||
|
\$u->email = 'admin@esempio.it';
|
||||||
|
\$u->password = bcrypt('password-forte');
|
||||||
|
\$u->is_admin = true;
|
||||||
|
\$u->permissions = ['individui' => 2, 'gruppi' => 2, 'eventi' => 2, 'documenti' => 2, 'mailing' => 2, 'viste' => 2, 'report' => 2, 'settings' => 2];
|
||||||
|
\$u->save();
|
||||||
|
echo 'Utente creato con successo!';
|
||||||
|
"</code></pre>
|
||||||
|
|
||||||
|
<div class="callout callout-warning mt-4">
|
||||||
|
<h6><i class="fas fa-exclamation-triangle"></i> Note importanti</h6>
|
||||||
|
<ul class="mb-0">
|
||||||
|
<li><strong>Persistenza:</strong> i volumi Docker preservano storage e database tra i riavvii</li>
|
||||||
|
<li><strong>APP_KEY:</strong> viene generata al primo avvio — se elimini i volumi, la perdi e i dati criptati diventano inaccessibili</li>
|
||||||
|
<li><strong>MySQL in produzione:</strong> imposta password sicure per <code>MYSQL_PASSWORD</code> e <code>MYSQL_ROOT_PASSWORD</code></li>
|
||||||
|
<li><strong>File compose separati:</strong> puoi mantenere entrambi i file (<code>docker-compose.yml</code> per SQLite, <code>docker-compose.mysql.yml</code> per MySQL) e scegliere con <code>-f</code></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="tab-pane" id="help-installazione">
|
||||||
|
<div class="card card-outline card-dark">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title"><i class="fas fa-terminal mr-2"></i> Guida all'Installazione</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>Panoramica</h5>
|
||||||
|
<p>l'applicazione include un <strong>wizard di installazione web</strong> che guida passo-passo nella configurazione su un nuovo server LAMP. Supporta due modalita:</p>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="callout callout-info">
|
||||||
|
<h6><i class="fas fa-rocket"></i> Fresh Install</h6>
|
||||||
|
<p class="mb-0">Installa l'applicazione da zero su un nuovo server: crea il database, esegue le migration, popola i dati di base e crea l'amministratore.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="callout callout-success">
|
||||||
|
<h6><i class="fas fa-upload"></i> Restore da Backup</h6>
|
||||||
|
<p class="mb-0">Ripristina un'installazione esistente da un file ZIP di backup: importa il database, ripristina i documenti e la configurazione.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Requisiti del Server</h5>
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead><tr><th>Componente</th><th>Versione Minima</th><th>Note</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>Web Server</td><td>Apache 2.4+</td><td>Con mod_rewrite abilitato</td></tr>
|
||||||
|
<tr><td>PHP</td><td>8.2+ (consigliato 8.4)</td><td>Estensioni: pdo_mysql, mbstring, xml, curl, zip, gd, fileinfo</td></tr>
|
||||||
|
<tr><td>MySQL / MariaDB</td><td>MySQL 8.0+ / MariaDB 10.5+</td><td>Supporto utf8mb4</td></tr>
|
||||||
|
<tr><td>Composer</td><td>2.x</td><td>Per gestione dipendenze PHP</td></tr>
|
||||||
|
<tr><td>Node.js / npm</td><td>Node 20+ / npm 10+</td><td>Per compilazione asset frontend (opzionale se precompilati)</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Installazione Passo-Passo</h5>
|
||||||
|
|
||||||
|
<h6>Passo 1: Preparare il server LAMP</h6>
|
||||||
|
<pre><code>sudo apt update && sudo apt upgrade -y
|
||||||
|
|
||||||
|
sudo apt install -y apache2 mariadb-server php8.4 php8.4-cli \
|
||||||
|
php8.4-mysql php8.4-xml php8.4-mbstring php8.4-curl \
|
||||||
|
php8.4-zip php8.4-bcmath php8.4-gd php8.4-intl \
|
||||||
|
composer git unzip
|
||||||
|
|
||||||
|
sudo a2enmod rewrite
|
||||||
|
sudo systemctl restart apache2</code></pre>
|
||||||
|
|
||||||
|
<h6>Passo 2: Ottenere l'applicazione</h6>
|
||||||
|
<div class="callout callout-info py-2">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
Puoi clonare il repository con git oppure estrarre il file ZIP ricevuto nella cartella <code>/var/www/glastree</code>.
|
||||||
|
</div>
|
||||||
|
<pre><code>cd /var/www
|
||||||
|
|
||||||
|
# Opzione A — Git clone
|
||||||
|
git clone <URL_REPOSITORY> glastree
|
||||||
|
|
||||||
|
# Opzione B — ZIP (se non hai git)
|
||||||
|
# unzip /percorso/del/glastree.zip -d glastree
|
||||||
|
|
||||||
|
cd glastree
|
||||||
|
composer install --no-dev --optimize-autoloader
|
||||||
|
npm ci && npm run build</code></pre>
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<i class="fas fa-info-circle"></i>
|
||||||
|
Se non hai accesso a npm, puoi saltare il build. L'interfaccia usera comunque AdminLTE via CDN.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h6>Passo 3: Permessi cartelle</h6>
|
||||||
|
<pre><code>sudo chown -R www-data:www-data storage bootstrap/cache
|
||||||
|
sudo chmod -R 775 storage bootstrap/cache</code></pre>
|
||||||
|
|
||||||
|
<h6>Passo 4: Configurare Apache</h6>
|
||||||
|
<pre><code>sudo tee /etc/apache2/sites-available/glastree.conf <<APACHE
|
||||||
|
<VirtualHost *:80>
|
||||||
|
ServerName glastree.esempio.it
|
||||||
|
DocumentRoot /var/www/glastree/public
|
||||||
|
|
||||||
|
<Directory /var/www/glastree/public>
|
||||||
|
Options -Indexes +FollowSymLinks
|
||||||
|
AllowOverride All
|
||||||
|
Require all granted
|
||||||
|
</Directory>
|
||||||
|
|
||||||
|
ErrorLog \${APACHE_LOG_DIR}/glastree_error.log
|
||||||
|
CustomLog \${APACHE_LOG_DIR}/glastree_access.log combined
|
||||||
|
</VirtualHost>
|
||||||
|
APACHE
|
||||||
|
|
||||||
|
sudo a2dissite 000-default.conf
|
||||||
|
sudo a2ensite glastree.conf
|
||||||
|
sudo systemctl reload apache2</code></pre>
|
||||||
|
|
||||||
|
<h6>Passo 5: Avviare il wizard di installazione</h6>
|
||||||
|
<p>Apri il browser e visita l'indirizzo del tuo server:</p>
|
||||||
|
<pre><code>http://glastree.esempio.it/installer/</code></pre>
|
||||||
|
|
||||||
|
<p>Il wizard ti guidera attraverso 6 passi:</p>
|
||||||
|
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead><tr><th>Passo</th><th>Descrizione</th></tr></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr><td>1. Benvenuto</td><td>Scegli Fresh Install o Restore da Backup</td></tr>
|
||||||
|
<tr><td>2. Requisiti</td><td>Verifica PHP, estensioni e permessi</td></tr>
|
||||||
|
<tr><td>3. Database</td><td>Configura MySQL (crea nuovo o usa esistente)</td></tr>
|
||||||
|
<tr><td>4. Installazione</td><td>Fresh: migration e seed. Backup: upload ZIP</td></tr>
|
||||||
|
<tr><td>5. Amministratore</td><td>Fresh: crea super-admin. Backup: verifica utenti</td></tr>
|
||||||
|
<tr><td>6. Finalizzazione</td><td>Cache, storage link, auto-eliminazione installer</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<i class="fas fa-exclamation-triangle"></i>
|
||||||
|
<strong>Attenzione:</strong> Al termine dell'installazione, la cartella <code>installer/</code> viene <strong>automaticamente eliminata</strong>. Non puoi rieseguire l'installazione se non ricreando manualmente la cartella.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Modalita Fresh Install</h5>
|
||||||
|
<p>Seleziona questa modalita quando installi l'applicazione per la prima volta su un server.</p>
|
||||||
|
<p>Cosa succede durante l'installazione:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Genera <code>APP_KEY</code> per la crittografia</li>
|
||||||
|
<li>Esegue tutte le migration per creare le tabelle del database</li>
|
||||||
|
<li>Popola i dati di base (diocesi, comuni, ruoli, preset)</li>
|
||||||
|
<li>Crea il collegamento <code>storage → public/storage</code></li>
|
||||||
|
<li>Crea l'utente amministratore con i permessi completi</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Modalita Restore da Backup</h5>
|
||||||
|
<p>Seleziona questa modalita quando vuoi migrare un'installazione esistente su un nuovo server.</p>
|
||||||
|
<p>Cosa serve:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Un file ZIP generato dalla pagina <strong>Admin → Backup</strong> del server originale</li>
|
||||||
|
<li>Il wizard accetta upload diretto del file o un percorso sul server</li>
|
||||||
|
</ul>
|
||||||
|
<p>Cosa succede durante il restore:</p>
|
||||||
|
<ol>
|
||||||
|
<li>Estrae il file ZIP in una cartella temporanea</li>
|
||||||
|
<li>Importa <code>database.sql</code> nel database MySQL configurato</li>
|
||||||
|
<li>Copia i file documenti in <code>storage/app/documenti/</code></li>
|
||||||
|
<li>Ripristina il file <code>.env</code> dal backup (preservando le credenziali DB del nuovo server)</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Dopo l'Installazione</h5>
|
||||||
|
<ol>
|
||||||
|
<li><strong>Configura SSL</strong> con Let's Encrypt:
|
||||||
|
<pre><code>sudo apt install -y certbot python3-certbot-apache
|
||||||
|
sudo certbot --apache -d glastree.esempio.it</code></pre>
|
||||||
|
</li>
|
||||||
|
<li><strong>Accedi</strong> con le credenziali amministratore create durante l'installazione</li>
|
||||||
|
<li><strong>Configura l'applicazione</strong> in Impostazioni:
|
||||||
|
<ul>
|
||||||
|
<li>Nome applicazione e logo</li>
|
||||||
|
<li>Email (SMTP per invio, IMAP per ricezione)</li>
|
||||||
|
<li>Repository remoti (Google Drive, Nextcloud)</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><strong>Crea utenti</strong> dal pannello Admin → Utenti</li>
|
||||||
|
<li><strong>Configura il cron</strong> per backup automatico e sync email:
|
||||||
|
<pre><code>sudo crontab -u www-data -e
|
||||||
|
# Inserisci:
|
||||||
|
* * * * * cd /var/www/glastree && php artisan schedule:run >> /dev/null 2>&1</code></pre>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<h5 class="mt-4">Risoluzione Problemi</h5>
|
||||||
|
<div class="callout callout-danger">
|
||||||
|
<h6>Errore "500 | Server Error" dopo l'installazione</h6>
|
||||||
|
<p>Probabilmente mancano permessi sulle cartelle <code>storage</code> o <code>bootstrap/cache</code>:</p>
|
||||||
|
<pre><code>sudo chown -R www-data:www-data storage bootstrap/cache
|
||||||
|
sudo chmod -R 775 storage bootstrap/cache</code></pre>
|
||||||
|
</div>
|
||||||
|
<div class="callout callout-danger">
|
||||||
|
<h6>Errore "No application encryption key"</h6>
|
||||||
|
<p>APP_KEY non generata. Nella cartella dell'app:</p>
|
||||||
|
<pre><code>php artisan key:generate</code></pre>
|
||||||
|
</div>
|
||||||
|
<div class="callout callout-warning">
|
||||||
|
<h6>mod_rewrite non funziona</h6>
|
||||||
|
<p>Se le rotte restituiscono 404, verifica che Apache abbia AllowOverride:</p>
|
||||||
|
<pre><code>sudo a2enmod rewrite
|
||||||
|
# Nel VirtualHost: AllowOverride All
|
||||||
|
sudo systemctl reload apache2</code></pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.nav-pills .nav-link { border-radius: 0; }
|
||||||
|
.nav-pills .nav-link.active { background-color: #007bff; }
|
||||||
|
.callout { border-left: 3px solid; padding: 12px 16px; margin: 16px 0; background: #f8f9fa; }
|
||||||
|
.callout-info { border-color: #17a2b8; }
|
||||||
|
.callout-danger { border-color: #dc3545; }
|
||||||
|
.callout-warning { border-color: #ffc107; }
|
||||||
|
</style>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
|
||||||
|
<?php echo $__env->make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH /var/www/html/glastree/resources/views/help/index.blade.php ENDPATH**/ ?>
|
||||||
@@ -0,0 +1,349 @@
|
|||||||
|
<?php $__env->startSection('title', 'Eventi'); ?>
|
||||||
|
<?php $__env->startSection('page_title', 'Eventi'); ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
$canWriteEventi = Auth::user()->canManage('eventi');
|
||||||
|
$canDeleteEventi = Auth::user()->canDelete('eventi');
|
||||||
|
?>
|
||||||
|
|
||||||
|
<?php $__env->startSection('content'); ?>
|
||||||
|
|
||||||
|
<?php if(session('success')): ?>
|
||||||
|
<div class="alert alert-success alert-dismissible">
|
||||||
|
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||||
|
<?php echo e(session('success')); ?>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Tutti gli Eventi</h3>
|
||||||
|
<div class="card-tools">
|
||||||
|
<a href="/eventi/calendar" class="btn btn-sm btn-outline-primary mr-2">
|
||||||
|
<i class="fas fa-calendar-alt mr-1"></i> Calendario
|
||||||
|
</a>
|
||||||
|
<button type="button" class="btn btn-sm btn-success mr-2" onclick="exportSelectedIcs()">
|
||||||
|
<i class="fas fa-calendar-plus mr-1"></i> Esporta ICS
|
||||||
|
</button>
|
||||||
|
<?php if($canDeleteEventi): ?>
|
||||||
|
<div class="btn-group mr-2">
|
||||||
|
<button type="button" class="btn btn-sm btn-danger" onclick="deleteSelected()">
|
||||||
|
<i class="fas fa-trash mr-1"></i> Elimina Selezionati
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if($canWriteEventi): ?>
|
||||||
|
<a href="/eventi/create" class="btn btn-xs btn-success">
|
||||||
|
<i class="fas fa-plus mr-1"></i> Nuovo Evento
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="GET" class="mb-3">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<input type="text" name="search" class="form-control" placeholder="Cerca evento..." value="<?php echo e(request('search')); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<select name="gruppo_id" class="form-control" onchange="this.form.submit()">
|
||||||
|
<option value="">Tutti i gruppi</option>
|
||||||
|
<?php $__currentLoopData = $gruppi; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $g): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
<option value="<?php echo e($g->id); ?>" <?php echo e(request('gruppo_id') == $g->id ? 'selected' : ''); ?>><?php echo e($g->full_path); ?></option>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<select name="tipo" class="form-control" onchange="this.form.submit()">
|
||||||
|
<option value="">Tutte le ricorrenze</option>
|
||||||
|
<option value="singolo" <?php echo e(request('tipo') == 'singolo' ? 'selected' : ''); ?>>Singolo</option>
|
||||||
|
<option value="settimanale" <?php echo e(request('tipo') == 'settimanale' ? 'selected' : ''); ?>>Settimanale</option>
|
||||||
|
<option value="mensile" <?php echo e(request('tipo') == 'mensile' ? 'selected' : ''); ?>>Mensile</option>
|
||||||
|
<option value="annuale" <?php echo e(request('tipo') == 'annuale' ? 'selected' : ''); ?>>Annuale</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="fas fa-search mr-1"></i> Cerca</button>
|
||||||
|
<a href="/eventi" class="btn btn-secondary"><i class="fas fa-times"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-hover">
|
||||||
|
<thead class="thead-light">
|
||||||
|
<tr>
|
||||||
|
<th style="width: 40px;">
|
||||||
|
<?php if($canDeleteEventi): ?>
|
||||||
|
<div class="custom-control custom-checkbox">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="select-all" onchange="toggleSelectAll(this)">
|
||||||
|
<label class="custom-control-label" for="select-all"></label>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'nome_evento', 'direction' => request('sort') === 'nome_evento' && request('direction') === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark">
|
||||||
|
Nome Evento
|
||||||
|
<?php if(request('sort') === 'nome_evento'): ?>
|
||||||
|
<i class="fas fa-sort-<?php echo e(request('direction') === 'asc' ? 'up' : 'down'); ?> ml-1"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-sort ml-1 text-muted"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'descrizione_evento', 'direction' => request('sort') === 'descrizione_evento' && request('direction') === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark">
|
||||||
|
Descrizione
|
||||||
|
<?php if(request('sort') === 'descrizione_evento'): ?>
|
||||||
|
<i class="fas fa-sort-<?php echo e(request('direction') === 'asc' ? 'up' : 'down'); ?> ml-1"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-sort ml-1 text-muted"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'tipo_evento', 'direction' => request('sort') === 'tipo_evento' && request('direction') === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark">
|
||||||
|
Tipologia
|
||||||
|
<?php if(request('sort') === 'tipo_evento'): ?>
|
||||||
|
<i class="fas fa-sort-<?php echo e(request('direction') === 'asc' ? 'up' : 'down'); ?> ml-1"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-sort ml-1 text-muted"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'tipo_recorrenza', 'direction' => request('sort') === 'tipo_recorrenza' && request('direction') === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark">
|
||||||
|
Ricorrenza
|
||||||
|
<?php if(request('sort') === 'tipo_recorrenza'): ?>
|
||||||
|
<i class="fas fa-sort-<?php echo e(request('direction') === 'asc' ? 'up' : 'down'); ?> ml-1"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-sort ml-1 text-muted"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'gruppi', 'direction' => request('sort') === 'gruppi' && request('direction') === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark">
|
||||||
|
Gruppi
|
||||||
|
<?php if(request('sort') === 'gruppi'): ?>
|
||||||
|
<i class="fas fa-sort-<?php echo e(request('direction') === 'asc' ? 'up' : 'down'); ?> ml-1"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-sort ml-1 text-muted"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'responsabili', 'direction' => request('sort') === 'responsabili' && request('direction') === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark">
|
||||||
|
Responsabili
|
||||||
|
<?php if(request('sort') === 'responsabili'): ?>
|
||||||
|
<i class="fas fa-sort-<?php echo e(request('direction') === 'asc' ? 'up' : 'down'); ?> ml-1"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-sort ml-1 text-muted"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th style="width: 120px;">
|
||||||
|
<a href="<?php echo e(request()->fullUrlWithQuery(['sort' => 'created_at', 'direction' => request('sort') === 'created_at' && request('direction') === 'asc' ? 'desc' : 'asc'])); ?>" class="text-dark">
|
||||||
|
Creato
|
||||||
|
<?php if(request('sort') === 'created_at'): ?>
|
||||||
|
<i class="fas fa-sort-<?php echo e(request('direction') === 'asc' ? 'up' : 'down'); ?> ml-1"></i>
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-sort ml-1 text-muted"></i>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
<th style="width: 120px;">Azioni</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php $__empty_1 = true; $__currentLoopData = $eventi; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $evento): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||||||
|
<tr data-id="<?php echo e($evento->id); ?>">
|
||||||
|
<td>
|
||||||
|
<?php if($canDeleteEventi): ?>
|
||||||
|
<div class="custom-control custom-checkbox">
|
||||||
|
<input type="checkbox" class="custom-control-input row-checkbox" id="row-checkbox-<?php echo e($evento->id); ?>" value="<?php echo e($evento->id); ?>">
|
||||||
|
<label class="custom-control-label" for="row-checkbox-<?php echo e($evento->id); ?>"></label>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="/eventi/<?php echo e($evento->id); ?>">
|
||||||
|
<i class="fas fa-calendar mr-1 text-primary"></i>
|
||||||
|
<?php echo e($evento->nome_evento); ?>
|
||||||
|
|
||||||
|
</a>
|
||||||
|
<?php if($evento->is_incontro_gruppo): ?>
|
||||||
|
<span class="badge badge-success ml-1">Incluso</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?php echo e(Str::limit($evento->descrizione_evento, 50) ?: '-'); ?></td>
|
||||||
|
<td>
|
||||||
|
<?php if($evento->tipo_evento): ?>
|
||||||
|
<?php
|
||||||
|
$tipologiaEvento = \App\Models\TipologiaEvento::where('nome', $evento->tipo_evento)->first();
|
||||||
|
?>
|
||||||
|
<?php if($tipologiaEvento): ?>
|
||||||
|
<span class="badge badge-primary"><?php echo e($tipologiaEvento->descrizione ?: $tipologiaEvento->nome); ?></span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-secondary"><?php echo e($evento->tipo_evento); ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="text-muted">-</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php if($evento->tipo_recorrenza && $evento->tipo_recorrenza !== 'singolo'): ?>
|
||||||
|
<span class="badge badge-info"><?php echo e($evento->periodicita_label); ?></span>
|
||||||
|
<?php else: ?>
|
||||||
|
<span class="badge badge-secondary">Singolo</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php $__empty_2 = true; $__currentLoopData = $evento->gruppi->take(2); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $gruppo): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_2 = false; ?>
|
||||||
|
<a href="/gruppi/<?php echo e($gruppo->id); ?>">
|
||||||
|
<span class="badge badge-warning"><?php echo e($gruppo->nome); ?></span>
|
||||||
|
</a>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_2): ?>
|
||||||
|
<span class="text-muted">-</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if($evento->gruppi->count() > 2): ?>
|
||||||
|
<small class="text-muted">+<?php echo e($evento->gruppi->count() - 2); ?></small>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php $__empty_2 = true; $__currentLoopData = $evento->responsabili->take(2); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $resp): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_2 = false; ?>
|
||||||
|
<small><?php echo e($resp->nome_completo); ?></small><br>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_2): ?>
|
||||||
|
<span class="text-muted">-</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if($evento->responsabili->count() > 2): ?>
|
||||||
|
<small class="text-muted">+<?php echo e($evento->responsabili->count() - 2); ?> altri</small>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><small class="text-muted"><?php echo e($evento->created_at->format('d/m/Y')); ?></small></td>
|
||||||
|
<td>
|
||||||
|
<a href="<?php echo e(url('/eventi/' . $evento->id)); ?>" class="btn btn-xs btn-info" title="Visualizza">
|
||||||
|
<i class="fas fa-eye"></i>
|
||||||
|
</a>
|
||||||
|
<?php if($canWriteEventi): ?>
|
||||||
|
<a href="<?php echo e(url('/eventi/' . $evento->id . '/edit')); ?>" class="btn btn-xs btn-warning" title="Modifica">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<form action="<?php echo e(url('/eventi/' . $evento->id)); ?>" method="POST" class="d-inline">
|
||||||
|
<?php echo csrf_field(); ?> <?php echo method_field('DELETE'); ?>
|
||||||
|
<button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('Confermi l\'eliminazione?')" title="Elimina">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||||||
|
<tr>
|
||||||
|
<td colspan="9" class="text-center text-muted py-4">
|
||||||
|
<i class="fas fa-calendar fa-2x mb-2"></i>
|
||||||
|
<p class="mb-0">Nessun evento trovato</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<?php echo e($eventi->withQueryString()->links()); ?>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog">
|
||||||
|
<?php if($canDeleteEventi): ?>
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-danger">
|
||||||
|
<h5 class="modal-title text-white"><i class="fas fa-trash-alt mr-2"></i>Conferma Eliminazione</h5>
|
||||||
|
<button type="button" class="close text-white" data-dismiss="modal">
|
||||||
|
<span>×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Stai per eliminare <strong id="delete-count">0</strong> eventi selezionati.</p>
|
||||||
|
<p class="text-muted small">Verranno eliminati anche i collegamenti con gruppi e responsabili.</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annulla</button>
|
||||||
|
<button type="button" class="btn btn-danger" onclick="confirmDelete()">Elimina</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
|
||||||
|
<?php $__env->startSection('scripts'); ?>
|
||||||
|
<script>
|
||||||
|
function toggleSelectAll(source) {
|
||||||
|
document.querySelectorAll('.row-checkbox').forEach(cb => cb.checked = source.checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectedIds() {
|
||||||
|
return Array.from(document.querySelectorAll('.row-checkbox:checked')).map(cb => cb.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteSelected() {
|
||||||
|
const selectedIds = getSelectedIds();
|
||||||
|
if (selectedIds.length === 0) {
|
||||||
|
alert('Seleziona almeno un evento');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('delete-count').textContent = selectedIds.length;
|
||||||
|
|
||||||
|
document.querySelector('#deleteModal .btn-danger').onclick = function() {
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.method = 'POST';
|
||||||
|
form.action = '/eventi/mass-elimina';
|
||||||
|
|
||||||
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '<?php echo e(csrf_token()); ?>';
|
||||||
|
|
||||||
|
let html = `<input type="hidden" name="_token" value="${csrfToken}">`;
|
||||||
|
selectedIds.forEach(function(id) {
|
||||||
|
html += `<input type="hidden" name="ids[]" value="${id}">`;
|
||||||
|
});
|
||||||
|
|
||||||
|
form.innerHTML = html;
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
};
|
||||||
|
|
||||||
|
$('#deleteModal').modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportSelectedIcs() {
|
||||||
|
const selectedIds = getSelectedIds();
|
||||||
|
const form = document.createElement('form');
|
||||||
|
form.method = 'POST';
|
||||||
|
form.action = '/eventi/export-ics';
|
||||||
|
|
||||||
|
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content || '<?php echo e(csrf_token()); ?>';
|
||||||
|
|
||||||
|
let html = `<input type="hidden" name="_token" value="${csrfToken}">`;
|
||||||
|
|
||||||
|
if (selectedIds.length > 0) {
|
||||||
|
selectedIds.forEach(function(id) {
|
||||||
|
html += `<input type="hidden" name="ids[]" value="${id}">`;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
params.forEach(function(value, key) {
|
||||||
|
if (key === 'search') html += `<input type="hidden" name="search" value="${value}">`;
|
||||||
|
if (key === 'gruppo_id') html += `<input type="hidden" name="gruppo_id" value="${value}">`;
|
||||||
|
if (key === 'tipo') html += `<input type="hidden" name="tipo" value="${value}">`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
form.innerHTML = html;
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
<?php echo $__env->make('layouts.adminlte', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH /var/www/html/glastree/resources/views/eventi/index.blade.php ENDPATH**/ ?>
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
use App\Models\AppSetting;
|
||||||
|
$appLogo = AppSetting::getLogoUrl();
|
||||||
|
$appName = AppSetting::getAppName() ?? 'Glastree';
|
||||||
|
$appOrgName = AppSetting::getOrgName() ?? '';
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="it">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Accedi - <?php echo e(e($appName)); ?></title>
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/admin-lte@3.2/dist/css/adminlte.min.css">
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
</head>
|
||||||
|
<body class="hold-transition login-page">
|
||||||
|
<div class="login-box">
|
||||||
|
<div class="login-logo">
|
||||||
|
<a href="/">
|
||||||
|
<?php if($appLogo): ?>
|
||||||
|
<img src="<?php echo e($appLogo); ?>" alt="Logo" style="max-height: 80px; max-width: 200px;">
|
||||||
|
<?php else: ?>
|
||||||
|
<i class="fas fa-tree text-success"></i> <b><?php echo e(e($appName)); ?></b>
|
||||||
|
<?php endif; ?>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<?php if($appOrgName): ?>
|
||||||
|
<div class="text-center mb-3">
|
||||||
|
<small class="text-muted"><?php echo e(e($appOrgName)); ?></small>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body login-card-body">
|
||||||
|
<p class="login-box-msg">Accedi per continuare</p>
|
||||||
|
<form action="<?php echo e(route('login')); ?>" method="POST">
|
||||||
|
<?php echo csrf_field(); ?>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="email" name="email" class="form-control <?php $__errorArgs = ['email'];
|
||||||
|
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
|
||||||
|
if ($__bag->has($__errorArgs[0])) :
|
||||||
|
if (isset($message)) { $__messageOriginal = $message; }
|
||||||
|
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
|
||||||
|
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
|
||||||
|
endif;
|
||||||
|
unset($__errorArgs, $__bag); ?>" placeholder="Email" required>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<div class="input-group-text">
|
||||||
|
<span class="fas fa-envelope"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php $__errorArgs = ['email'];
|
||||||
|
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
|
||||||
|
if ($__bag->has($__errorArgs[0])) :
|
||||||
|
if (isset($message)) { $__messageOriginal = $message; }
|
||||||
|
$message = $__bag->first($__errorArgs[0]); ?>
|
||||||
|
<span class="invalid-feedback"><?php echo e($message); ?></span>
|
||||||
|
<?php unset($message);
|
||||||
|
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
|
||||||
|
endif;
|
||||||
|
unset($__errorArgs, $__bag); ?>
|
||||||
|
</div>
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="password" name="password" class="form-control <?php $__errorArgs = ['password'];
|
||||||
|
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
|
||||||
|
if ($__bag->has($__errorArgs[0])) :
|
||||||
|
if (isset($message)) { $__messageOriginal = $message; }
|
||||||
|
$message = $__bag->first($__errorArgs[0]); ?> is-invalid <?php unset($message);
|
||||||
|
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
|
||||||
|
endif;
|
||||||
|
unset($__errorArgs, $__bag); ?>" placeholder="Password" required>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<div class="input-group-text">
|
||||||
|
<span class="fas fa-lock"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php $__errorArgs = ['password'];
|
||||||
|
$__bag = $errors->getBag($__errorArgs[1] ?? 'default');
|
||||||
|
if ($__bag->has($__errorArgs[0])) :
|
||||||
|
if (isset($message)) { $__messageOriginal = $message; }
|
||||||
|
$message = $__bag->first($__errorArgs[0]); ?>
|
||||||
|
<span class="invalid-feedback"><?php echo e($message); ?></span>
|
||||||
|
<?php unset($message);
|
||||||
|
if (isset($__messageOriginal)) { $message = $__messageOriginal; }
|
||||||
|
endif;
|
||||||
|
unset($__errorArgs, $__bag); ?>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-8">
|
||||||
|
<div class="icheck-primary">
|
||||||
|
<input type="checkbox" id="remember">
|
||||||
|
<label for="remember">Ricordami</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
<button type="submit" class="btn btn-success btn-block">Accedi</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<p class="mb-0 text-center mt-3">
|
||||||
|
<a href="<?php echo e(route('password.request')); ?>" class="text-center">Password dimenticata?</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html><?php /**PATH /var/www/html/glastree/resources/views/auth/login.blade.php ENDPATH**/ ?>
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<?php $__env->startSection('title', 'Gestione Utenti'); ?>
|
||||||
|
<?php $__env->startSection('page_title', 'Gestione Utenti'); ?>
|
||||||
|
|
||||||
|
<?php $__env->startSection('breadcrumbs'); ?>
|
||||||
|
<li class="breadcrumb-item active">Admin</li>
|
||||||
|
<li class="breadcrumb-item active">Utenti</li>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
|
||||||
|
<?php $__env->startSection('content'); ?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title">Utenti Registrati</h3>
|
||||||
|
<a href="/admin/utenti/create" class="btn btn-success btn-sm float-right">
|
||||||
|
<i class="fas fa-plus"></i> Nuovo Utente
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="GET" class="mb-3">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<input type="text" name="search" class="form-control" placeholder="Cerca nome o email..." value="<?php echo e(request('search')); ?>">
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<select name="status" class="form-control">
|
||||||
|
<option value="">Tutti gli stati</option>
|
||||||
|
<option value="active" <?php echo e(request('status') == 'active' ? 'selected' : ''); ?>>Attivo</option>
|
||||||
|
<option value="suspended" <?php echo e(request('status') == 'suspended' ? 'selected' : ''); ?>>Sospeso</option>
|
||||||
|
<option value="pending" <?php echo e(request('status') == 'pending' ? 'selected' : ''); ?>>In attesa</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<button type="submit" class="btn btn-primary">Filtra</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table class="table table-bordered table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nome</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Stato</th>
|
||||||
|
<th>Permessi</th>
|
||||||
|
<th>Creato</th>
|
||||||
|
<th style="width: 150px;">Azioni</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php $__currentLoopData = $utenti; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $utente): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<strong><?php echo e($utente->name); ?></strong>
|
||||||
|
<?php if($utente->isSuperAdmin()): ?>
|
||||||
|
<span class="badge badge-danger ml-1">Admin</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td><?php echo e($utente->email); ?></td>
|
||||||
|
<td>
|
||||||
|
<?php switch($utente->status):
|
||||||
|
case ('active'): ?>
|
||||||
|
<span class="badge badge-success">Attivo</span>
|
||||||
|
<?php break; ?>
|
||||||
|
<?php case ('suspended'): ?>
|
||||||
|
<span class="badge badge-secondary">Sospeso</span>
|
||||||
|
<?php break; ?>
|
||||||
|
<?php case ('pending'): ?>
|
||||||
|
<span class="badge badge-warning">In attesa</span>
|
||||||
|
<?php break; ?>
|
||||||
|
<?php endswitch; ?>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<?php $summary = $utente->getPermissionsSummary(); ?>
|
||||||
|
<small>
|
||||||
|
<?php $__currentLoopData = $summary; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $module => $level): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
<?php if($level !== 'Nessuno'): ?>
|
||||||
|
<span class="text-<?php echo e($level === 'Completo' ? 'success' : 'info'); ?>"><?php echo e(ucfirst($module)); ?>: <?php echo e($level); ?></span><br>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
</small>
|
||||||
|
</td>
|
||||||
|
<td><?php echo e($utente->created_at->format('d/m/Y')); ?></td>
|
||||||
|
<td>
|
||||||
|
<a href="<?php echo e(url('/admin/utenti/' . $utente->id . '/edit')); ?>" class="btn btn-xs btn-warning">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</a>
|
||||||
|
<?php if($utente->id !== auth()->id()): ?>
|
||||||
|
<form method="POST" action="<?php echo e(url('/admin/utenti/' . $utente->id)); ?>" style="display: inline;">
|
||||||
|
<?php echo csrf_field(); ?> <?php echo method_field('DELETE'); ?>
|
||||||
|
<button type="submit" class="btn btn-xs btn-danger" onclick="return confirm('Eliminare questo utente?')">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php echo e($utenti->links()); ?>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php $__env->stopSection(); ?>
|
||||||
|
<?php echo $__env->make('admin.layout', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH /var/www/html/glastree/resources/views/admin/utenti/index.blade.php ENDPATH**/ ?>
|
||||||
Reference in New Issue
Block a user