161 lines
5.4 KiB
Go
161 lines
5.4 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"wucher/internal/domain/user"
|
|
)
|
|
|
|
type UserWriteError struct {
|
|
Status int
|
|
Title string
|
|
Detail string
|
|
Pointer string
|
|
}
|
|
|
|
func (e *UserWriteError) Error() string {
|
|
if e == nil {
|
|
return ""
|
|
}
|
|
return e.Detail
|
|
}
|
|
|
|
type UserWriteResult struct {
|
|
Row *user.User
|
|
PreviousProfileAttachmentID []byte
|
|
}
|
|
|
|
type UserCreateInput struct {
|
|
ID []byte
|
|
Email string
|
|
Username string
|
|
FirstName string
|
|
LastName string
|
|
MobilePhone string
|
|
Timezone string
|
|
RoleID []byte
|
|
RoleIDs [][]byte
|
|
ProfileAttachmentID []byte
|
|
CreatedBy []byte
|
|
UpdatedBy []byte
|
|
}
|
|
|
|
type UserUpdateInput struct {
|
|
ID []byte
|
|
Email *string
|
|
FirstName *string
|
|
LastName *string
|
|
MobilePhone *string
|
|
Timezone *string
|
|
ProfileAttachmentSet bool
|
|
ProfileAttachmentID []byte
|
|
ActorUserID []byte
|
|
}
|
|
|
|
func (s *UserService) CreateDetailed(ctx context.Context, in UserCreateInput) (*UserWriteResult, error) {
|
|
if s == nil || s.repo == nil {
|
|
return nil, &UserWriteError{Status: http.StatusInternalServerError, Title: "Create failed", Detail: "user service is not configured"}
|
|
}
|
|
email := strings.TrimSpace(in.Email)
|
|
username := strings.TrimSpace(in.Username)
|
|
firstName := strings.TrimSpace(in.FirstName)
|
|
lastName := strings.TrimSpace(in.LastName)
|
|
if email == "" || username == "" || firstName == "" || lastName == "" {
|
|
return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "email, username, first_name, and last_name are required", Pointer: "/data/attributes"}
|
|
}
|
|
row := &user.User{
|
|
ID: append([]byte(nil), in.ID...),
|
|
Email: email,
|
|
Username: username,
|
|
FirstName: firstName,
|
|
LastName: lastName,
|
|
MobilePhone: strings.TrimSpace(in.MobilePhone),
|
|
Timezone: strings.TrimSpace(in.Timezone),
|
|
RoleID: append([]byte(nil), in.RoleID...),
|
|
RoleIDs: appendUniqueIDs(in.RoleIDs),
|
|
ProfileAttachmentID: append([]byte(nil), in.ProfileAttachmentID...),
|
|
ImageAttachmentID: append([]byte(nil), in.ProfileAttachmentID...),
|
|
CreatedBy: append([]byte(nil), in.CreatedBy...),
|
|
UpdatedBy: append([]byte(nil), in.UpdatedBy...),
|
|
}
|
|
if err := s.Create(ctx, row); err != nil {
|
|
return nil, &UserWriteError{Status: http.StatusBadRequest, Title: "Create failed", Detail: err.Error()}
|
|
}
|
|
created, err := s.GetByID(ctx, row.ID)
|
|
if err != nil {
|
|
return nil, &UserWriteError{Status: http.StatusBadRequest, Title: "Create failed", Detail: err.Error()}
|
|
}
|
|
if created == nil {
|
|
created = row
|
|
}
|
|
return &UserWriteResult{Row: created}, nil
|
|
}
|
|
|
|
func (s *UserService) UpdateDetailed(ctx context.Context, in UserUpdateInput) (*UserWriteResult, error) {
|
|
if s == nil || s.repo == nil {
|
|
return nil, &UserWriteError{Status: http.StatusInternalServerError, Title: "Update failed", Detail: "user service is not configured"}
|
|
}
|
|
if len(in.ID) != 16 {
|
|
return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "uuid is invalid UUID", Pointer: "/path/uuid"}
|
|
}
|
|
|
|
existing, err := s.GetByID(ctx, in.ID)
|
|
if err != nil || existing == nil {
|
|
return nil, &UserWriteError{Status: http.StatusNotFound, Title: "Not found", Detail: "user not found"}
|
|
}
|
|
prevProfileAttachmentID := append([]byte(nil), existing.ProfileAttachmentID...)
|
|
|
|
if in.Email != nil {
|
|
email := strings.TrimSpace(*in.Email)
|
|
if email == "" {
|
|
return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "email cannot be empty", Pointer: "/data/attributes/email"}
|
|
}
|
|
existing.Email = email
|
|
}
|
|
if in.FirstName != nil {
|
|
firstName := strings.TrimSpace(*in.FirstName)
|
|
if firstName == "" {
|
|
return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "first_name cannot be empty", Pointer: "/data/attributes/first_name"}
|
|
}
|
|
existing.FirstName = firstName
|
|
}
|
|
if in.LastName != nil {
|
|
lastName := strings.TrimSpace(*in.LastName)
|
|
if lastName == "" {
|
|
return nil, &UserWriteError{Status: http.StatusUnprocessableEntity, Title: "Validation error", Detail: "last_name cannot be empty", Pointer: "/data/attributes/last_name"}
|
|
}
|
|
existing.LastName = lastName
|
|
}
|
|
if in.MobilePhone != nil {
|
|
existing.MobilePhone = strings.TrimSpace(*in.MobilePhone)
|
|
}
|
|
if in.Timezone != nil {
|
|
existing.Timezone = strings.TrimSpace(*in.Timezone)
|
|
}
|
|
if in.ProfileAttachmentSet {
|
|
if len(in.ProfileAttachmentID) == 0 {
|
|
existing.ProfileAttachmentID = nil
|
|
existing.ImageAttachmentID = nil
|
|
} else {
|
|
existing.ProfileAttachmentID = append([]byte(nil), in.ProfileAttachmentID...)
|
|
existing.ImageAttachmentID = append([]byte(nil), in.ProfileAttachmentID...)
|
|
}
|
|
existing.ProfileAttachmentPatchSet = true
|
|
}
|
|
existing.UpdatedBy = append([]byte(nil), in.ActorUserID...)
|
|
|
|
if err := s.Update(ctx, existing); err != nil {
|
|
return nil, &UserWriteError{Status: http.StatusBadRequest, Title: "Update failed", Detail: err.Error()}
|
|
}
|
|
updated, err := s.GetByID(ctx, existing.ID)
|
|
if err != nil {
|
|
return nil, &UserWriteError{Status: http.StatusBadRequest, Title: "Update failed", Detail: err.Error()}
|
|
}
|
|
if updated == nil {
|
|
updated = existing
|
|
}
|
|
return &UserWriteResult{Row: updated, PreviousProfileAttachmentID: prevProfileAttachmentID}, nil
|
|
}
|