Files
QRForge-selfhosted/src/forms/table_dynamic.php
T
dillard a1ab16d54c Fase 2: read-only user role with per-category view toggles
Adds a third account type 'user' alongside super/admin: no create/edit/delete
rights on qr codes, view access to dynamic/static lists gated per-account by
two admin-controlled toggles (can_view_static, can_view_dynamic), and always
full visibility into the dashboard/reports regardless of those toggles.

- New columns can_view_static/can_view_dynamic on users (migrations/003)
- Users class + form_users.php: 'user' type option with the two toggles
- Access control: dynamic_qrcode.php/static_qrcode.php/bulk_action.php reject
  all mutations for type=user; dynamic_qrcodes.php/static_qrcodes.php enforce
  the view toggle and show all codes (no owner scoping, since 'user' owns none)
- Sidebar and list tables hide add/edit/delete/bulk UI for the read-only role
- index.php dashboard stats are unscoped for both 'super' and 'user'

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 16:37:25 +02:00

163 lines
6.7 KiB
PHP

<?php $is_readonly_user = $_SESSION['type'] === 'user'; ?>
<div class="row">
<?php if (!$is_readonly_user): ?>
<div class="col-12" id="bulk-action-div" style="display: none;">
<div id="err-msg"></div>
<div class="bulk-action-wrapper">
<form id="bulk-action" action="bulk_action.php" method="POST">
<?php echo csrf_field(); ?>
<div class="col-sm-12 mb-2" style="margin-left: 10px">
<div class="row">
<div class="col-5 col-md-2">
<div class="input-group">
<select name="action" class="form-control">
<option value="download" selected >Download</option>
<option value="delete">Delete</option>
</select>
<input type="hidden" name="type" value="dynamic">
<button type="submit" class="btn btn-primary">Apply</button>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
<?php endif; ?>
<div class="col-12">
<div class="card">
<div class="card-body table-responsive p-0">
<table class="table table-striped table-bordered">
<thead>
<tr>
<?php if (!$is_readonly_user): ?>
<th><input type="checkbox" name="bulk-select" value="1"></th>
<?php endif; ?>
<th>ID</th>
<th>Owner</th>
<th>Filename</th>
<th>Unique redirect identifier</th>
<th>URL</th>
<th>Qr code</th>
<th>Scan</th>
<th>Status</th>
<th>Operations</th>
</tr>
</thead>
<tbody>
<?php foreach ($rows as $row): ?>
<tr>
<?php if (!$is_readonly_user): ?>
<td><input type="checkbox" name="action[]" value="<?=$row['id']?>" onchange="updateBulkActionVisibility()"></td>
<?php endif; ?>
<td><?php echo $row['id']; ?></td>
<td>
<?php
if(!isset($row['id_owner']))
echo "";
else {
require_once BASE_PATH . '/lib/Users/Users.php';
$users = new Users();
$user = $users->getUser($row['id_owner']);
if($user !== NULL)
echo $user["username"];
else
echo "";
}
?>
</td>
<td><?php echo htmlspecialchars($row['filename']); ?></td>
<td><?php echo htmlspecialchars($row['identifier']); ?></td>
<td><?php echo htmlspecialchars($row['link']); ?></td>
<td>
<?php echo '<img src="'.SAVED_QRCODE_FOLDER.htmlspecialchars($row['qrcode']).'" width="100" height="100">'; ?>
</td>
<td><?php echo htmlspecialchars($row['scan']); ?></td>
<td><?php echo htmlspecialchars($row['state']); ?></td>
<td>
<?php if (!$is_readonly_user): ?>
<!-- EDIT -->
<a href="dynamic_qrcode.php?edit=true&id=<?php echo $row['id']; ?>" class="btn btn-primary"><i class="fas fa-edit"></i></a>
<!-- DELETE -->
<a
class="btn btn-danger delete_btn"
data-toggle="modal"
data-target="#delete-modal"
data-del_id="<?php echo $row["id"];?>"
><i class="fas fa-trash"></i></a>
<?php endif; ?>
<!-- DOWNLOAD -->
<a href="<?php echo SAVED_QRCODE_FOLDER.htmlspecialchars($row['qrcode']); ?>" class="btn btn-primary" download><i class="fa fa-download"></i></a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div><!-- /.Card body -->
<div class="card-footer clearfix">
<?php echo paginationLinks($page, $total_pages, 'dynamic_qrcodes.php'); ?>
</div><!-- /.Card footer -->
</div><!-- /.Card -->
</div><!-- /.col -->
</div><!-- /.row -->
<?php if (!$is_readonly_user): ?>
<!-- Delete Confirmation Modal -->
<div class="modal fade" id="delete-modal" role="dialog">
<div class="modal-dialog">
<form action="dynamic_qrcode.php" method="POST">
<?php echo csrf_field(); ?>
<!-- Modal content -->
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Confirm</h4>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
</div>
<div class="modal-body">
<input type="hidden" name="del_id" id="del_id" value="">
<p>Are you sure you want to delete this row? Proceeding with the cancellation it will no longer be possible to recover the unique identifier and you will delete the created QR code from the server</p>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</form>
</div>
</div>
<!-- /.Delete Confirmation Modal -->
<?php endif; ?>
<script>
const deleteButtons = document.querySelectorAll('.delete_btn');
deleteButtons.forEach(button => {
button.addEventListener('click', function () {
document.getElementById('del_id').value = button.getAttribute('data-del_id');
const deleteModal = document.querySelector('#delete-modal');
deleteModal.style.display = 'block';
});
});
</script>
<script>
function updateBulkActionVisibility() {
const checkboxes = document.querySelectorAll('input[name="action[]"]');
const bulkActionDiv = document.getElementById('bulk-action-div');
const selectedCheckboxes = Array.from(checkboxes).filter(checkbox => checkbox.checked);
if (selectedCheckboxes.length > 0) {
bulkActionDiv.style.display = 'block';
} else {
bulkActionDiv.style.display = 'none';
}
}
updateBulkActionVisibility();
</script>