167 lines
4.7 KiB
Go
167 lines
4.7 KiB
Go
package httpserver
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/tim/cairnquire/apps/server/internal/docs"
|
|
)
|
|
|
|
type adminUserInput struct {
|
|
Email string `json:"email"`
|
|
DisplayName string `json:"displayName"`
|
|
Role string `json:"role"`
|
|
}
|
|
|
|
type adminSettingsInput struct {
|
|
SignupsEnabled bool `json:"signupsEnabled"`
|
|
}
|
|
|
|
func (s *Server) handleAdminLogin(w http.ResponseWriter, r *http.Request) {
|
|
var input adminUserInput
|
|
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
|
writeJSONWithStatus(w, http.StatusBadRequest, map[string]string{"error": "invalid json"})
|
|
return
|
|
}
|
|
|
|
user, ok := s.normalizeAdminUserInput(input)
|
|
if !ok {
|
|
writeJSONWithStatus(w, http.StatusBadRequest, map[string]string{"error": "email is required"})
|
|
return
|
|
}
|
|
if user.Role == "viewer" {
|
|
user.Role = "admin"
|
|
}
|
|
|
|
created, err := s.repository.UpsertUser(r.Context(), user)
|
|
if err != nil {
|
|
writeJSONWithStatus(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"user": created,
|
|
"session": map[string]any{
|
|
"mode": "foundation",
|
|
"createdAt": time.Now().UTC(),
|
|
},
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminUsers(w http.ResponseWriter, r *http.Request) {
|
|
users, err := s.repository.ListUsers(r.Context())
|
|
if err != nil {
|
|
writeJSONWithStatus(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"users": users})
|
|
}
|
|
|
|
func (s *Server) handleAdminCreateUser(w http.ResponseWriter, r *http.Request) {
|
|
var input adminUserInput
|
|
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
|
writeJSONWithStatus(w, http.StatusBadRequest, map[string]string{"error": "invalid json"})
|
|
return
|
|
}
|
|
|
|
user, ok := s.normalizeAdminUserInput(input)
|
|
if !ok {
|
|
writeJSONWithStatus(w, http.StatusBadRequest, map[string]string{"error": "email is required"})
|
|
return
|
|
}
|
|
|
|
created, err := s.repository.UpsertUser(r.Context(), user)
|
|
if err != nil {
|
|
writeJSONWithStatus(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSONWithStatus(w, http.StatusCreated, map[string]any{"user": created})
|
|
}
|
|
|
|
func (s *Server) handleAdminWorkspace(w http.ResponseWriter, r *http.Request) {
|
|
documents, err := s.documents.ListDocuments(r.Context())
|
|
if err != nil {
|
|
writeJSONWithStatus(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
users, err := s.repository.ListUsers(r.Context())
|
|
if err != nil {
|
|
writeJSONWithStatus(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"workspace": map[string]any{
|
|
"sourceDir": s.config.Content.SourceDir,
|
|
"storeDir": s.config.Content.StoreDir,
|
|
"databasePath": s.config.Database.Path,
|
|
"documentCount": len(documents),
|
|
"userCount": len(users),
|
|
},
|
|
"documents": documents,
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminWorkspaceSync(w http.ResponseWriter, r *http.Request) {
|
|
changes, err := s.documents.SyncSourceDir(r.Context())
|
|
if err != nil {
|
|
writeJSONWithStatus(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"changes": changes,
|
|
"syncedAt": time.Now().UTC(),
|
|
})
|
|
}
|
|
|
|
func (s *Server) handleAdminSettings(w http.ResponseWriter, r *http.Request) {
|
|
settings, err := s.auth.GetInstanceSettings(r.Context())
|
|
if err != nil {
|
|
writeJSONWithStatus(w, http.StatusInternalServerError, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"settings": settings})
|
|
}
|
|
|
|
func (s *Server) handleAdminSettingsUpdate(w http.ResponseWriter, r *http.Request) {
|
|
principal, _ := requirePrincipal(r)
|
|
var input adminSettingsInput
|
|
if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
|
|
writeJSONWithStatus(w, http.StatusBadRequest, map[string]string{"error": "invalid json"})
|
|
return
|
|
}
|
|
settings, err := s.auth.UpdateSignupsEnabled(r.Context(), principal, input.SignupsEnabled)
|
|
if err != nil {
|
|
writeJSONWithStatus(w, http.StatusBadRequest, map[string]string{"error": err.Error()})
|
|
return
|
|
}
|
|
writeJSON(w, http.StatusOK, map[string]any{"settings": settings})
|
|
}
|
|
|
|
func (s *Server) normalizeAdminUserInput(input adminUserInput) (docs.UserRecord, bool) {
|
|
email := strings.TrimSpace(strings.ToLower(input.Email))
|
|
if email == "" {
|
|
return docs.UserRecord{}, false
|
|
}
|
|
|
|
role := strings.TrimSpace(strings.ToLower(input.Role))
|
|
switch role {
|
|
case "admin", "editor", "viewer":
|
|
default:
|
|
role = "viewer"
|
|
}
|
|
|
|
displayName := strings.TrimSpace(input.DisplayName)
|
|
if displayName == "" {
|
|
displayName = email
|
|
}
|
|
|
|
return docs.UserRecord{
|
|
Email: email,
|
|
DisplayName: displayName,
|
|
Role: role,
|
|
}, true
|
|
}
|