Compare commits

..

7 Commits

Author SHA1 Message Date
563808ecdf add user getter by id 2026-01-18 22:02:06 +02:00
376ce4ca62 add user service to router 2026-01-18 21:54:41 +02:00
7fd02119b8 fix pointer error 2026-01-18 21:50:04 +02:00
0388df48f5 add method GetUsers, and array type Users -> []User 2026-01-08 20:49:28 +02:00
4f2c213bc6 add type Users [[]User] 2026-01-08 20:37:10 +02:00
2a6380f0a5 fix createUser name 2026-01-07 21:18:18 +02:00
d0f54513d1 add api/user MustRoute method 2026-01-07 21:03:03 +02:00
7 changed files with 135 additions and 1 deletions

View File

@@ -11,11 +11,13 @@ import (
api_acladmin "git.oblat.lv/alex/triggerssmith/api/acl_admin"
api_auth "git.oblat.lv/alex/triggerssmith/api/auth"
api_block "git.oblat.lv/alex/triggerssmith/api/block"
api_user "git.oblat.lv/alex/triggerssmith/api/user"
_ "git.oblat.lv/alex/triggerssmith/docs"
"git.oblat.lv/alex/triggerssmith/internal/acl"
"git.oblat.lv/alex/triggerssmith/internal/auth"
"git.oblat.lv/alex/triggerssmith/internal/config"
"git.oblat.lv/alex/triggerssmith/internal/server"
"git.oblat.lv/alex/triggerssmith/internal/user"
"git.oblat.lv/alex/triggerssmith/internal/vars"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
@@ -30,12 +32,15 @@ type Router struct {
authService *auth.Service
aclService *acl.Service
userService *user.Service
}
type RouterDependencies struct {
AuthService *auth.Service
Configuration *config.Config
ACLService *acl.Service
UserService *user.Service
}
func NewRouter(deps RouterDependencies) *Router {
@@ -48,12 +53,16 @@ func NewRouter(deps RouterDependencies) *Router {
if deps.ACLService == nil {
panic("ACLService is required")
}
if deps.UserService == nil {
panic("UserService is required")
}
r := chi.NewRouter()
return &Router{
r: r,
cfg: deps.Configuration,
authService: deps.AuthService,
aclService: deps.ACLService,
userService: deps.UserService,
}
}
@@ -92,7 +101,8 @@ func (r *Router) MustRoute() chi.Router {
api.Route("/block", api_block.MustRoute(r.cfg))
authRoute := api_auth.MustRoute(r.cfg, r.authService)
api.Route("/auth", authRoute)
//api.Route("/users", authRoute) // legacy support
usersRoute := api_user.MustRoute(r.cfg, r.userService)
api.Route("/users", usersRoute)
aclAdminRoute := api_acladmin.MustRoute(r.cfg, r.aclService, r.authService)
api.Route("/acl", aclAdminRoute)
api.Route("/acl-admin", aclAdminRoute) // legacy support

103
api/user/handle.go Normal file
View File

@@ -0,0 +1,103 @@
package api_user
import (
"encoding/json"
"log/slog"
"net/http"
"strconv"
"git.oblat.lv/alex/triggerssmith/internal/config"
"git.oblat.lv/alex/triggerssmith/internal/server"
"git.oblat.lv/alex/triggerssmith/internal/user"
"github.com/go-chi/chi/v5"
)
type userHandler struct {
cfg *config.Config
u *user.Service
}
func MustRoute(config *config.Config, userService *user.Service) func(chi.Router) {
if config == nil {
panic("config is nil")
}
if userService == nil {
panic("userService is nil")
}
h := &userHandler{
cfg: config,
u: userService,
}
return func(r chi.Router) {
r.Get("/", h.getUsers) // /users
r.Get("/{userId}", h.GetUser) // /users/{userId}
//r.Post("/", h.createUser) // /users
//r.Patch("/{userId}", h.updateUser) // /users/{userId}
//r.Delete("/{userId}", h.deleteUser) // /users/{userId}
}
}
type getUserResponseUnit struct {
UserId uint `json:"userId"`
UserName string `json:"name"`
}
type getUsersResponse []getUserResponseUnit
// @Summary Get all user list
// @Tags users
// @Produce json
// @Success 200 {object} getUsersResponse
// @Failure 500 {object} server.ProblemDetails
// @Router /api/users [get]
func (h *userHandler) getUsers(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
users, err := h.u.GetUsers()
if err != nil {
slog.Error("failed get users", "err", err.Error())
server.WriteProblem(w, http.StatusInternalServerError, "/errors/internal-server-error", "Internal Server Error", "Failed to get all user list", r)
}
var resp_users getUsersResponse
for _, user := range users {
resp_users = append(resp_users, getUserResponseUnit{
UserId: user.ID,
UserName: user.Username,
})
}
json.NewEncoder(w).Encode(resp_users)
}
// @Summary Get user by ID
// @Tags users
// @Produce json
// @Param userId path int true "User ID"
// @Success 200 {object} getUserResponseUnit
// @Failure 400 {object} server.ProblemDetails
// @Failure 404 {object} server.ProblemDetails
// @Failure 500 {object} server.ProblemDetails
// @Router /api/users/{userId} [get]
func (h *userHandler) GetUser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
userIdStr := chi.URLParam(r, "userId")
userId, err := strconv.Atoi(userIdStr)
if err != nil || userId < 0 {
server.WriteProblem(w, http.StatusBadRequest, "/errors/acl/invalid-user-id", "Invalid user ID", "User ID must be positive integer", r)
return
}
user, err := h.u.GetBy("id", userIdStr)
if err != nil {
slog.Error("failed get user by id", "err", err.Error())
server.WriteProblem(w, http.StatusInternalServerError, "/errors/internal-server-error", "Internal Server Error", "Failed to get user by ID, may not found", r)
return
}
if user == nil {
server.WriteProblem(w, http.StatusNotFound, "/errors/not-found", "Not Found", "User not found", r)
return
}
resp_user := getUserResponseUnit{
UserId: user.ID,
UserName: user.Username,
}
json.NewEncoder(w).Encode(resp_user)
}

View File

@@ -254,6 +254,7 @@ var serveCmd = &cobra.Command{
AuthService: authService,
Configuration: cfg,
ACLService: aclService,
UserService: userService,
})
srv.SetHandler(router.MustRoute())

View File

@@ -41,6 +41,15 @@ func (s *GormUserStore) GetBy(by, value string) (*User, error) {
return &user, nil
}
func (s *GormUserStore) GetUsers() (*Users, error) {
var users Users
err := s.db.Omit("password").Find(&users).Error
if err != nil {
return nil, err
}
return &users, nil
}
func (s *GormUserStore) Update(user *User) error {
return s.db.Save(user).Error
}

View File

@@ -11,3 +11,5 @@ type User struct {
Password string `gorm:"not null"`
DeletedAt gorm.DeletedAt `gorm:"index"`
}
type Users []User

View File

@@ -42,6 +42,14 @@ func (s *Service) Create(user *User) error {
return s.store.Create(user)
}
func (s *Service) GetUsers() (Users, error) {
if !s.isInitialized() {
return nil, fmt.Errorf("user service is not initialized")
}
users, err := s.store.GetUsers()
return *users, err
}
func (s *Service) GetBy(by, value string) (*User, error) {
if !s.isInitialized() {
return nil, fmt.Errorf("user service is not initialized")

View File

@@ -3,6 +3,7 @@ package user
type UserCRUD interface {
Create(user *User) error
GetBy(by, value string) (*User, error)
GetUsers() (*Users, error)
Update(user *User) error
Delete(id int64) error