- Add SchemaVerifier class for automatic database schema verification and repair - Implement warehouse_manager (Level 75) and warehouse_worker (Level 35) roles - Add zone-based access control for warehouse workers - Implement worker-manager binding system with zone filtering - Add comprehensive database auto-repair on Docker initialization - Remove Module Access section from user form (role-based access only) - Add autocomplete attributes to password fields for better UX - Include detailed documentation for warehouse implementation - Update initialize_db.py with schema verification as Step 0
255 lines
15 KiB
HTML
255 lines
15 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}{% if user %}Edit User{% else %}Create User{% endif %}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid py-5">
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<h1 class="mb-2">
|
|
<i class="fas fa-user-plus"></i> {% if user %}Edit User{% else %}Create New User{% endif %}
|
|
</h1>
|
|
<p class="text-muted mb-0">Manage user account details and permissions</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<div class="list-group">
|
|
<a href="{{ url_for('settings.general_settings') }}" class="list-group-item list-group-item-action">
|
|
<i class="fas fa-sliders-h"></i> General Settings
|
|
</a>
|
|
<a href="{{ url_for('settings.user_management') }}" class="list-group-item list-group-item-action active">
|
|
<i class="fas fa-users"></i> User Management
|
|
</a>
|
|
<a href="{{ url_for('settings.database_settings') }}" class="list-group-item list-group-item-action">
|
|
<i class="fas fa-database"></i> Database
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="card shadow-sm">
|
|
<div class="card-header bg-light">
|
|
<h5 class="mb-0">{% if user %}Edit User Account{% else %}New User Account{% endif %}</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if error %}
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
<i class="fas fa-exclamation-circle"></i> {{ error }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if success %}
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
<i class="fas fa-check-circle"></i> {{ success }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<form method="POST" action="{% if user %}{{ url_for('settings.edit_user', user_id=user.id) }}{% else %}{{ url_for('settings.create_user') }}{% endif %}" novalidate>
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="username" class="form-label">Username <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control" id="username" name="username"
|
|
value="{{ user.username if user else '' }}"
|
|
{% if user %}readonly{% endif %}
|
|
required>
|
|
<small class="form-text text-muted">{% if user %}Username cannot be changed{% else %}Unique username for login{% endif %}</small>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="email" class="form-label">Email</label>
|
|
<input type="email" class="form-control" id="email" name="email"
|
|
value="{{ user.email if user else '' }}">
|
|
<small class="form-text text-muted">User's email address</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="full_name" class="form-label">Full Name <span class="text-danger">*</span></label>
|
|
<input type="text" class="form-control" id="full_name" name="full_name"
|
|
value="{{ user.full_name if user else '' }}"
|
|
required>
|
|
<small class="form-text text-muted">User's display name</small>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="role" class="form-label">Role <span class="text-danger">*</span></label>
|
|
<select class="form-select" id="role" name="role" required>
|
|
<option value="">-- Select a role --</option>
|
|
<optgroup label="System Roles">
|
|
<option value="superadmin"
|
|
{% if user and user.role == 'superadmin' %}selected{% endif %}>
|
|
Super Admin (Level 100)
|
|
</option>
|
|
<option value="admin"
|
|
{% if user and user.role == 'admin' %}selected{% endif %}>
|
|
Admin (Level 90)
|
|
</option>
|
|
</optgroup>
|
|
<optgroup label="Quality Module">
|
|
<option value="manager"
|
|
{% if user and user.role == 'manager' %}selected{% endif %}>
|
|
Manager - Quality (Level 70)
|
|
</option>
|
|
<option value="worker"
|
|
{% if user and user.role == 'worker' %}selected{% endif %}>
|
|
Worker - Quality (Level 50)
|
|
</option>
|
|
</optgroup>
|
|
<optgroup label="Warehouse Module">
|
|
<option value="warehouse_manager"
|
|
{% if user and user.role == 'warehouse_manager' %}selected{% endif %}>
|
|
Manager - Warehouse (Level 75)
|
|
</option>
|
|
<option value="warehouse_worker"
|
|
{% if user and user.role == 'warehouse_worker' %}selected{% endif %}>
|
|
Worker - Warehouse (Level 35)
|
|
</option>
|
|
</optgroup>
|
|
</select>
|
|
<small class="form-text text-muted">
|
|
User's access level and role. See role descriptions below.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12 mb-3">
|
|
<label class="form-label"><i class="fas fa-info-circle"></i> Role Reference Matrix</label>
|
|
<div class="table-responsive" style="font-size: 0.9rem;">
|
|
<table class="table table-sm table-bordered">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th style="width: 15%;">Role</th>
|
|
<th style="width: 8%;">Level</th>
|
|
<th style="width: 20%;">Modules</th>
|
|
<th style="width: 57%;">Permissions & Description</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td><strong>Super Admin</strong></td>
|
|
<td><span class="badge bg-danger">100</span></td>
|
|
<td>All</td>
|
|
<td>Unrestricted access to entire system. Can manage all users and configuration.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Admin</strong></td>
|
|
<td><span class="badge bg-danger">90</span></td>
|
|
<td>All</td>
|
|
<td>Full system administration. Can manage users, settings, database, backups.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Manager - Quality</strong></td>
|
|
<td><span class="badge bg-success">70</span></td>
|
|
<td>Quality</td>
|
|
<td>Create, edit, delete quality inspections. Can export and download quality reports.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Manager - Warehouse</strong></td>
|
|
<td><span class="badge bg-success">75</span></td>
|
|
<td>Warehouse</td>
|
|
<td>Full warehouse input and analytics access. Can manage assigned warehouse workers and zones.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Worker - Quality</strong></td>
|
|
<td><span class="badge bg-warning text-dark">50</span></td>
|
|
<td>Quality</td>
|
|
<td>Create and view quality inspections only. Cannot edit, delete, or view reports.</td>
|
|
</tr>
|
|
<tr>
|
|
<td><strong>Worker - Warehouse</strong></td>
|
|
<td><span class="badge bg-warning text-dark">35</span></td>
|
|
<td>Warehouse</td>
|
|
<td>Input pages only (set locations, create entries). <strong>No access to reports or analytics.</strong> Must be assigned to a Manager.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<small class="form-text text-muted d-block mt-2">
|
|
<strong>Important:</strong> Warehouse workers are assigned to a manager for supervision.
|
|
Quality and Warehouse modules are separate - users can have one or both module access.
|
|
</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 mb-3">
|
|
<label for="password" class="form-label">
|
|
Password
|
|
{% if not user %}<span class="text-danger">*</span>{% endif %}
|
|
</label>
|
|
<input type="password" class="form-control" id="password" name="password" autocomplete="new-password"
|
|
{% if not user %}required{% else %}placeholder="Leave blank to keep current password"{% endif %}>
|
|
<small class="form-text text-muted">
|
|
{% if user %}Leave blank to keep current password{% else %}Minimum 8 characters{% endif %}
|
|
</small>
|
|
</div>
|
|
<div class="col-md-6 mb-3">
|
|
<label for="confirm_password" class="form-label">
|
|
Confirm Password
|
|
{% if not user %}<span class="text-danger">*</span>{% endif %}
|
|
</label>
|
|
<input type="password" class="form-control" id="confirm_password" name="confirm_password" autocomplete="new-password"
|
|
{% if not user %}required{% endif %}>
|
|
<small class="form-text text-muted">Re-enter password to confirm</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12 mb-3">
|
|
<label for="is_active" class="form-check-label">
|
|
<input type="checkbox" class="form-check-input" id="is_active" name="is_active"
|
|
{% if not user or user.is_active %}checked{% endif %}>
|
|
<span class="ms-2">Active Account</span>
|
|
</label>
|
|
<small class="form-text text-muted d-block">Disabled accounts cannot log in</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row mt-4">
|
|
<div class="col-12">
|
|
<div class="d-flex gap-2">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="fas fa-save"></i> {% if user %}Update User{% else %}Create User{% endif %}
|
|
</button>
|
|
<a href="{{ url_for('settings.user_management') }}" class="btn btn-secondary">
|
|
<i class="fas fa-times"></i> Cancel
|
|
</a>
|
|
{% if user %}
|
|
<button type="button" class="btn btn-danger ms-auto" onclick="confirmDelete()">
|
|
<i class="fas fa-trash"></i> Delete User
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% if user %}
|
|
<script>
|
|
function confirmDelete() {
|
|
if (confirm('Are you sure you want to delete this user? This action cannot be undone.')) {
|
|
const form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = '{{ url_for("settings.delete_user", user_id=user.id) }}';
|
|
const input = document.createElement('input');
|
|
input.type = 'hidden';
|
|
input.name = '_method';
|
|
input.value = 'DELETE';
|
|
form.appendChild(input);
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
}
|
|
}
|
|
</script>
|
|
{% endif %}
|
|
|
|
{% endblock %}
|