users.html 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. {% extends "layout.html" %}
  2. {% block content %}
  3. <div class="flex justify-between items-center mb-10">
  4. <div>
  5. <h2 class="text-4xl font-black text-white tracking-tighter italic">User Management</h2>
  6. <p class="text-gray-500 font-bold uppercase text-[10px] tracking-widest mt-2">Manage access and RBAC roles</p>
  7. </div>
  8. <button onclick="openAddUser()" class="bg-blue-600 hover:bg-blue-500 px-8 py-3 rounded-xl font-black shadow-2xl transition transform hover:scale-105 text-white uppercase text-xs tracking-widest">+ Create User</button>
  9. </div>
  10. <div class="bg-[#12161f] border border-gray-800 rounded-3xl overflow-hidden shadow-2xl">
  11. <table class="w-full text-left">
  12. <thead class="bg-black/20 text-[10px] font-black text-gray-500 uppercase tracking-widest border-b border-gray-800">
  13. <tr>
  14. <th class="p-6">Username</th>
  15. <th class="p-6">Role</th>
  16. <th class="p-6">Templates</th>
  17. <th class="p-6 text-right">Actions</th>
  18. </tr>
  19. </thead>
  20. <tbody class="divide-y divide-gray-800">
  21. {% for u, data in users.items() %}
  22. <tr class="hover:bg-white/[0.02] transition">
  23. <td class="p-6 font-bold text-white">{{ u }}</td>
  24. <td class="p-6">
  25. <span class="px-3 py-1 rounded-full text-[9px] font-black uppercase border {% if data.role=='admin' %}border-red-500/30 text-red-400 bg-red-500/10{% else %}border-blue-500/30 text-blue-400 bg-blue-500/10{% endif %}">
  26. {{ data.role }}
  27. </span>
  28. </td>
  29. <td class="p-6 text-xs text-gray-500">{{ data.assigned_templates|join(', ') or 'None' }}</td>
  30. <td class="p-6 text-right">
  31. <button type="button"
  32. onclick="editUser('{{ u|e }}', '{{ data.role|e }}', '{{ data.assigned_templates|join(',') if data.assigned_templates else '' }}')"
  33. class="text-blue-500 hover:text-blue-400 text-[10px] font-black uppercase mr-4">
  34. Edit
  35. </button>
  36. {% if u != 'admin' %}
  37. <a href="/users/delete/{{ u|urlencode }}" onclick="return confirm('Are you sure you want to delete this user?')" class="text-red-500 hover:text-red-400 text-[10px] font-black uppercase">Delete</a>
  38. {% endif %}
  39. </td>
  40. </tr>
  41. {% endfor %}
  42. </tbody>
  43. </table>
  44. </div>
  45. <div id="userModal" class="hidden fixed inset-0 bg-black/90 backdrop-blur-md flex items-center justify-center z-50 p-4">
  46. <div class="bg-[#12161f] border border-gray-800 w-full max-w-md rounded-3xl p-8 shadow-2xl">
  47. <h3 id="modalTitle" class="text-xl font-black text-white mb-6 uppercase">Add User</h3>
  48. <form action="/users/save" method="POST" class="space-y-4">
  49. <input type="hidden" name="action" id="userAction" value="add">
  50. <input type="hidden" name="old_username" id="oldUsername">
  51. <input type="text" name="username" id="userName" placeholder="Username" required class="w-full bg-[#0b0e14] border border-gray-800 rounded-xl p-3 text-sm font-bold text-white outline-none">
  52. <input type="password" name="password" id="userPass" placeholder="Password (Leave blank to keep current)" class="w-full bg-[#0b0e14] border border-gray-800 rounded-xl p-3 text-sm font-bold text-white outline-none">
  53. <select name="role" id="userRole" class="w-full bg-[#0b0e14] border border-gray-800 rounded-xl p-3 text-sm font-bold text-white outline-none">
  54. <option value="user">User (Restricted)</option>
  55. <option value="admin">Administrator</option>
  56. </select>
  57. <div class="bg-black/20 p-4 rounded-xl border border-gray-800">
  58. <label class="text-[10px] font-black text-gray-500 uppercase block mb-3">Assigned Templates</label>
  59. <div class="grid grid-cols-2 gap-2 max-h-48 overflow-y-auto pr-2">
  60. {% for t in all_templates %}
  61. <label class="flex items-center gap-2 text-xs text-gray-400 cursor-pointer hover:text-white">
  62. <input type="checkbox" name="assigned_templates[]" value="{{ t }}" class="template-check rounded border-gray-700 bg-gray-900 text-blue-600">
  63. {{ t }}
  64. </label>
  65. {% endfor %}
  66. </div>
  67. </div>
  68. <div class="flex gap-4 pt-4">
  69. <button type="button" onclick="closeUserModal()" class="flex-1 bg-gray-800 text-gray-400 font-bold py-3 rounded-xl uppercase text-xs hover:text-white transition">Cancel</button>
  70. <button type="submit" class="flex-1 bg-blue-600 text-white font-black py-3 rounded-xl uppercase text-xs hover:bg-blue-500 transition">Save</button>
  71. </div>
  72. </form>
  73. </div>
  74. </div>
  75. <script>
  76. function openAddUser() {
  77. document.getElementById('userModal').classList.remove('hidden');
  78. document.getElementById('userAction').value = 'add';
  79. document.getElementById('modalTitle').innerText = 'Add User';
  80. document.getElementById('userName').value = '';
  81. document.getElementById('userPass').value = '';
  82. document.getElementById('userPass').placeholder = 'Password (Required)';
  83. document.getElementById('userPass').required = true;
  84. var checkboxes = document.querySelectorAll('.template-check');
  85. for (var i = 0; i < checkboxes.length; i++) {
  86. checkboxes[i].checked = false;
  87. }
  88. }
  89. function editUser(u, role, rawTemplates) {
  90. // Παίρνουμε το απλό κείμενο "AWMN,LOCAL" και το κόβουμε εκεί που έχει κόμμα,
  91. // φτιάχνοντας μια σωστή λίστα. Αν είναι άδειο, φτιάχνουμε κενή λίστα.
  92. var templates = rawTemplates ? rawTemplates.split(',') : [];
  93. // Εμφάνιση Modal
  94. document.getElementById('userModal').classList.remove('hidden');
  95. // Συμπλήρωση πεδίων
  96. document.getElementById('userAction').value = 'edit';
  97. document.getElementById('oldUsername').value = u;
  98. document.getElementById('userName').value = u;
  99. document.getElementById('userRole').value = role;
  100. document.getElementById('modalTitle').innerText = 'Edit User';
  101. // Ο κωδικός στο Edit δεν είναι υποχρεωτικός
  102. document.getElementById('userPass').value = '';
  103. document.getElementById('userPass').placeholder = 'Password (Leave blank to keep current)';
  104. document.getElementById('userPass').required = false;
  105. // Τσεκάρισμα των σωστών Templates
  106. var checkboxes = document.querySelectorAll('.template-check');
  107. for (var i = 0; i < checkboxes.length; i++) {
  108. checkboxes[i].checked = templates.includes(checkboxes[i].value);
  109. }
  110. }
  111. function closeUserModal() {
  112. document.getElementById('userModal').classList.add('hidden');
  113. }
  114. </script>
  115. {% endblock %}