Кабинет: веб-установщик и управление пользователями в ядре
- установщик в самом кабинете: до настройки любая страница ведёт в /install; три шага — проверка сервера (каталог данных, https), связь с ядром (режим, адрес, ключ; связь проверяется до сохранения, в режиме ожидания страница ждёт подключения ядра), администратор кабинета (заводится в ядре через /api/lk/admin/bootstrap, только пока администраторов нет); настройки в data/lk.json 0600, окружение перекрывает файл; после установки установщик закрыт - настройки кабинета можно менять на ходу: Server за мьютексом, один mux на всё время - ключ модуля больше не кладётся в архив: его вводят в установщике; на странице настроек ключ показан целиком 10 минут после создания, потом маска - ядро: карточка «Пользователи кабинета» в настройках — список, заведение, смена пароля (гасит сессии), блокировка, права сотрудника, разрешение поручений, удаление; письма не отправляются - инструкция /admin/help/lk дополнена шагами установщика и разделом о подходящем хостинге - тесты: TestInstaller, TestNotConfigured, TestSetupPageLKUsersAndLink; установщик проверен вживую вторым экземпляром против боевого ядра Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ package lkgateway
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -24,6 +25,7 @@ import (
|
||||
func registerLKAPI(mux *http.ServeMux, rc *RuntimeConfig, svc *Service) {
|
||||
sess := newLKSessions()
|
||||
sess.bindNetwork = func() bool { return rc.Snapshot().LK.BindNetwork }
|
||||
globalLKSessions = sess
|
||||
|
||||
// проверка ключа модуля
|
||||
auth := func(w http.ResponseWriter, r *http.Request) bool {
|
||||
@@ -117,6 +119,40 @@ func registerLKAPI(mux *http.ServeMux, rc *RuntimeConfig, svc *Service) {
|
||||
})
|
||||
})
|
||||
|
||||
// Первый администратор кабинета из веб-установщика. Только по ключу модуля и только
|
||||
// пока администраторов нет: потом учётные записи заводит администратор в настройках.
|
||||
mux.HandleFunc("/api/lk/admin/bootstrap", func(w http.ResponseWriter, r *http.Request) {
|
||||
if !auth(w, r) {
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodPost {
|
||||
lkJSON(w, http.StatusMethodNotAllowed, map[string]string{"error": "нужен POST"})
|
||||
return
|
||||
}
|
||||
has, err := lkHasAdmin(r.Context(), rc)
|
||||
if err != nil {
|
||||
lkJSON(w, http.StatusBadGateway, map[string]string{"error": "база кабинета недоступна: " + err.Error()})
|
||||
return
|
||||
}
|
||||
if has {
|
||||
lkJSON(w, http.StatusConflict, map[string]string{"error": "администратор кабинета уже создан — войдите под ним или пропустите шаг"})
|
||||
return
|
||||
}
|
||||
var in struct{ Login, Password, FullName, Email string }
|
||||
if json.NewDecoder(io.LimitReader(r.Body, 8<<10)).Decode(&in) != nil {
|
||||
lkJSON(w, http.StatusBadRequest, map[string]string{"error": "некорректный JSON"})
|
||||
return
|
||||
}
|
||||
u := LKUser{Login: strings.TrimSpace(in.Login), Contract: "ADMIN", FullName: strings.TrimSpace(in.FullName),
|
||||
Email: strings.TrimSpace(in.Email), Active: true, IsAdmin: true}
|
||||
if err := lkCreateUser(r.Context(), rc, u, in.Password); err != nil {
|
||||
lkJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
raiseSystemAlert(rc, "Кабинет: создан администратор", fmt.Sprintf("Из установщика кабинета создан администратор «%s».", u.Login))
|
||||
lkJSON(w, http.StatusOK, map[string]any{"ok": true, "message": "администратор создан"})
|
||||
})
|
||||
|
||||
mux.HandleFunc("/api/lk/logout", func(w http.ResponseWriter, r *http.Request) {
|
||||
if !auth(w, r) {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user