Files
PriceForge/web/templates/db_users.html
Mikhail Chusavitin 47b260dad4 Add QFS DB user management page
Create/edit/delete MariaDB users for the QFS child application via
the PriceForge admin UI. On creation the full standard QFS grant set
(14 table-level GRANTs) is applied automatically. Page shows a
privilege warning when the PriceForge DB user lacks CREATE USER rights.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 18:14:07 +03:00

112 lines
6.7 KiB
HTML

{{define "title"}}Пользователи QFS - PriceForge{{end}}
{{define "content"}}
<div class="space-y-4">
<div class="flex justify-between items-center">
<h1 class="text-2xl font-bold">Пользователи QFS</h1>
<button id="add-user-btn" onclick="openCreateModal()"
class="hidden px-4 py-2 bg-orange-600 text-white rounded hover:bg-orange-700 text-sm">
+ Добавить пользователя
</button>
</div>
<div id="no-privileges-banner" class="hidden p-4 bg-yellow-50 border border-yellow-200 rounded-lg text-sm text-yellow-800">
<strong>Недостаточно прав.</strong>
<span id="no-privileges-reason"></span>
Для управления пользователями текущий DB-пользователь должен иметь привилегию
<code class="bg-yellow-100 px-1 rounded">CREATE USER</code> или
<code class="bg-yellow-100 px-1 rounded">SELECT ON mysql.*</code>.
</div>
<div class="bg-white rounded-lg shadow overflow-hidden">
<table class="min-w-full divide-y divide-gray-200 text-sm">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-3 text-left font-medium text-gray-500">Пользователь</th>
<th class="px-4 py-3 text-left font-medium text-gray-500">Хост</th>
<th class="px-4 py-3 text-left font-medium text-gray-500">Пароль</th>
<th class="px-4 py-3 text-right font-medium text-gray-500">Действия</th>
</tr>
</thead>
<tbody id="users-body" class="divide-y divide-gray-100">
<tr><td colspan="4" class="px-4 py-6 text-center text-gray-400">Загрузка...</td></tr>
</tbody>
</table>
</div>
</div>
<!-- Create user modal -->
<div id="create-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
<div class="bg-white rounded-lg p-6 max-w-md w-full mx-4">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold">Добавить пользователя</h2>
<button onclick="closeCreateModal()" class="text-gray-400 hover:text-gray-600 text-xl">&times;</button>
</div>
<div id="create-error" class="hidden mb-3 p-2 rounded bg-red-50 text-red-700 text-sm"></div>
<form id="create-form" class="space-y-4" onsubmit="createUser(event)">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Имя пользователя <span class="text-red-500">*</span></label>
<input id="create-username" type="text" required pattern="[a-zA-Z0-9_]{1,32}"
placeholder="qfs_user"
class="w-full px-3 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-orange-500">
<p class="mt-1 text-xs text-gray-400">Только буквы, цифры, _ (макс. 32 символа)</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Хост</label>
<input id="create-host" type="text" value="%"
placeholder="%"
class="w-full px-3 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-orange-500">
<p class="mt-1 text-xs text-gray-400">% = любой хост, или конкретный IP / hostname</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Пароль <span class="text-red-500">*</span></label>
<input id="create-password" type="password" required minlength="8"
class="w-full px-3 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-orange-500">
<p class="mt-1 text-xs text-gray-400">Минимум 8 символов</p>
</div>
<div class="pt-1 p-3 bg-gray-50 rounded text-xs text-gray-500 leading-relaxed">
При создании будут применены стандартные права QFS:<br>
READ: qt_categories, qt_lot_metadata, qt_pricelists, qt_pricelist_items, stock_log, stock_ignore_rules, qt_partnumber_books, qt_partnumber_book_items, lot<br>
READ+WRITE: qt_projects, qt_configurations, qt_client_schema_state, qt_pricelist_sync_status, qt_vendor_partnumber_seen
</div>
<div class="flex justify-end gap-2 pt-1">
<button type="button" onclick="closeCreateModal()" class="px-4 py-2 border rounded hover:bg-gray-50">Отмена</button>
<button type="submit" id="create-save-btn" class="px-4 py-2 bg-orange-600 text-white rounded hover:bg-orange-700">Создать</button>
</div>
</form>
</div>
</div>
<!-- Edit password modal -->
<div id="edit-modal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
<div class="bg-white rounded-lg p-6 max-w-sm w-full mx-4">
<div class="flex justify-between items-center mb-4">
<h2 class="text-xl font-bold">Сменить пароль</h2>
<button onclick="closeEditModal()" class="text-gray-400 hover:text-gray-600 text-xl">&times;</button>
</div>
<div id="edit-error" class="hidden mb-3 p-2 rounded bg-red-50 text-red-700 text-sm"></div>
<form id="edit-form" class="space-y-4" onsubmit="updatePassword(event)">
<input type="hidden" id="edit-username" value="">
<input type="hidden" id="edit-host" value="">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Пользователь</label>
<p id="edit-user-label" class="text-sm text-gray-600 font-mono"></p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Новый пароль <span class="text-red-500">*</span></label>
<input id="edit-password" type="password" required minlength="8"
class="w-full px-3 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-orange-500">
</div>
<div class="flex justify-end gap-2 pt-1">
<button type="button" onclick="closeEditModal()" class="px-4 py-2 border rounded hover:bg-gray-50">Отмена</button>
<button type="submit" id="edit-save-btn" class="px-4 py-2 bg-orange-600 text-white rounded hover:bg-orange-700">Сохранить</button>
</div>
</form>
</div>
</div>
<script src="/static/js/db_users.js"></script>
{{end}}
{{template "base" .}}