A small IT asset inventory system built around a nested folder tree, matching the project brief: Go + html/template + Bootstrap 5 + vanilla JS, SQLite storage (WAL, FKs, migrations), embedded templates/static assets, single compiled binary. - AJAX-driven inventory tree: lazy-loaded folder expansion with per-user persisted expand state, drag-and-drop move for folders/assets, safe delete-with-relocate-or-cascade confirmation, search with breadcrumbs. - Assets: CRUD, duplicate, move, auto-generated IT-000001-style IDs, CSV import (with optional folder auto-create) and export. - Admin-defined item types with custom fields (text/long_text/number/date/ boolean/dropdown/url/ip_address). - Configurable statuses, session-based auth (bcrypt, secure cookies), admin/user roles, user management. - CLI: serve, version, database migrate, database backup; /healthz; graceful shutdown; Dockerfile/docker-compose/systemd unit; Go test suite.
128 lines
3.5 KiB
Go
128 lines
3.5 KiB
Go
package web
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"inventree/internal/models"
|
|
)
|
|
|
|
type usersListData struct {
|
|
User *models.User
|
|
Users []models.User
|
|
}
|
|
|
|
func (a *App) handleUsersList(w http.ResponseWriter, r *http.Request) {
|
|
list, err := a.Users.List(r.Context())
|
|
if err != nil {
|
|
writeErr(w, http.StatusInternalServerError, err.Error())
|
|
return
|
|
}
|
|
a.Render(w, http.StatusOK, "users_list", usersListData{User: currentUser(r), Users: list})
|
|
}
|
|
|
|
type userFormData struct {
|
|
User *models.User
|
|
EditUser *models.User
|
|
Error string
|
|
}
|
|
|
|
func (a *App) handleUserNewForm(w http.ResponseWriter, r *http.Request) {
|
|
a.Render(w, http.StatusOK, "users_form", userFormData{User: currentUser(r)})
|
|
}
|
|
|
|
func (a *App) handleUserCreate(w http.ResponseWriter, r *http.Request) {
|
|
if err := r.ParseForm(); err != nil {
|
|
writeErr(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
role := models.RoleUser
|
|
if r.FormValue("role") == "admin" {
|
|
role = models.RoleAdmin
|
|
}
|
|
u := &models.User{Username: r.FormValue("username"), Role: role, Enabled: r.FormValue("enabled") == "on"}
|
|
password := r.FormValue("password")
|
|
if password == "" {
|
|
a.Render(w, http.StatusBadRequest, "users_form", userFormData{User: currentUser(r), EditUser: u, Error: "Password is required."})
|
|
return
|
|
}
|
|
if err := a.Users.Create(r.Context(), u, password); err != nil {
|
|
a.Render(w, http.StatusBadRequest, "users_form", userFormData{User: currentUser(r), EditUser: u, Error: err.Error()})
|
|
return
|
|
}
|
|
http.Redirect(w, r, "/users", http.StatusSeeOther)
|
|
}
|
|
|
|
func (a *App) handleUserEditForm(w http.ResponseWriter, r *http.Request) {
|
|
id, err := pathID(r, "id")
|
|
if err != nil {
|
|
writeErr(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
u, err := a.Users.Get(r.Context(), id)
|
|
if err != nil {
|
|
writeErr(w, http.StatusNotFound, err.Error())
|
|
return
|
|
}
|
|
a.Render(w, http.StatusOK, "users_form", userFormData{User: currentUser(r), EditUser: u})
|
|
}
|
|
|
|
func (a *App) handleUserUpdate(w http.ResponseWriter, r *http.Request) {
|
|
id, err := pathID(r, "id")
|
|
if err != nil {
|
|
writeErr(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
if err := r.ParseForm(); err != nil {
|
|
writeErr(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
u, err := a.Users.Get(r.Context(), id)
|
|
if err != nil {
|
|
writeErr(w, http.StatusNotFound, err.Error())
|
|
return
|
|
}
|
|
u.Username = r.FormValue("username")
|
|
u.Role = models.RoleUser
|
|
if r.FormValue("role") == "admin" {
|
|
u.Role = models.RoleAdmin
|
|
}
|
|
u.Enabled = r.FormValue("enabled") == "on"
|
|
if err := a.Users.Update(r.Context(), u); err != nil {
|
|
a.Render(w, http.StatusBadRequest, "users_form", userFormData{User: currentUser(r), EditUser: u, Error: err.Error()})
|
|
return
|
|
}
|
|
http.Redirect(w, r, "/users", http.StatusSeeOther)
|
|
}
|
|
|
|
func (a *App) handleUserPassword(w http.ResponseWriter, r *http.Request) {
|
|
id, err := pathID(r, "id")
|
|
if err != nil {
|
|
writeErr(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
if err := r.ParseForm(); err != nil {
|
|
writeErr(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
password := r.FormValue("password")
|
|
if password != "" {
|
|
if err := a.Users.SetPassword(r.Context(), id, password); err != nil {
|
|
a.Log.Warn("set password failed", "error", err)
|
|
}
|
|
}
|
|
http.Redirect(w, r, "/users/"+strconv.FormatInt(id, 10)+"/edit", http.StatusSeeOther)
|
|
}
|
|
|
|
func (a *App) handleUserDelete(w http.ResponseWriter, r *http.Request) {
|
|
id, err := pathID(r, "id")
|
|
if err != nil {
|
|
writeErr(w, http.StatusBadRequest, err.Error())
|
|
return
|
|
}
|
|
if err := a.Users.Delete(r.Context(), id); err != nil {
|
|
a.Log.Warn("delete user failed", "error", err)
|
|
}
|
|
http.Redirect(w, r, "/users", http.StatusSeeOther)
|
|
}
|