A community based topic aggregation platform built on atproto
1package users
2
3import (
4 "fmt"
5 "strings"
6)
7
8type UserService struct {
9 userRepo UserRepository
10}
11
12func NewUserService(userRepo UserRepository) *UserService {
13 return &UserService{
14 userRepo: userRepo,
15 }
16}
17
18func (s *UserService) CreateUser(req CreateUserRequest) (*User, error) {
19 if err := s.validateCreateRequest(req); err != nil {
20 return nil, err
21 }
22
23 req.Email = strings.TrimSpace(strings.ToLower(req.Email))
24 req.Username = strings.TrimSpace(req.Username)
25
26 existingUser, _ := s.userRepo.GetByEmail(req.Email)
27 if existingUser != nil {
28 return nil, fmt.Errorf("service: email already exists")
29 }
30
31 existingUser, _ = s.userRepo.GetByUsername(req.Username)
32 if existingUser != nil {
33 return nil, fmt.Errorf("service: username already exists")
34 }
35
36 user := &User{
37 Email: req.Email,
38 Username: req.Username,
39 }
40
41 return s.userRepo.Create(user)
42}
43
44func (s *UserService) GetUserByID(id int) (*User, error) {
45 if id <= 0 {
46 return nil, fmt.Errorf("service: invalid user ID")
47 }
48
49 user, err := s.userRepo.GetByID(id)
50 if err != nil {
51 if strings.Contains(err.Error(), "not found") {
52 return nil, fmt.Errorf("service: user not found")
53 }
54 return nil, fmt.Errorf("service: %w", err)
55 }
56
57 return user, nil
58}
59
60func (s *UserService) GetUserByEmail(email string) (*User, error) {
61 email = strings.TrimSpace(strings.ToLower(email))
62 if email == "" {
63 return nil, fmt.Errorf("service: email is required")
64 }
65
66 user, err := s.userRepo.GetByEmail(email)
67 if err != nil {
68 if strings.Contains(err.Error(), "not found") {
69 return nil, fmt.Errorf("service: user not found")
70 }
71 return nil, fmt.Errorf("service: %w", err)
72 }
73
74 return user, nil
75}
76
77func (s *UserService) GetUserByUsername(username string) (*User, error) {
78 username = strings.TrimSpace(username)
79 if username == "" {
80 return nil, fmt.Errorf("service: username is required")
81 }
82
83 user, err := s.userRepo.GetByUsername(username)
84 if err != nil {
85 if strings.Contains(err.Error(), "not found") {
86 return nil, fmt.Errorf("service: user not found")
87 }
88 return nil, fmt.Errorf("service: %w", err)
89 }
90
91 return user, nil
92}
93
94func (s *UserService) UpdateUser(id int, req UpdateUserRequest) (*User, error) {
95 user, err := s.GetUserByID(id)
96 if err != nil {
97 return nil, err
98 }
99
100 if req.Email != "" {
101 req.Email = strings.TrimSpace(strings.ToLower(req.Email))
102 if req.Email != user.Email {
103 existingUser, _ := s.userRepo.GetByEmail(req.Email)
104 if existingUser != nil && existingUser.ID != id {
105 return nil, fmt.Errorf("service: email already exists")
106 }
107 }
108 user.Email = req.Email
109 }
110
111 if req.Username != "" {
112 req.Username = strings.TrimSpace(req.Username)
113 if req.Username != user.Username {
114 existingUser, _ := s.userRepo.GetByUsername(req.Username)
115 if existingUser != nil && existingUser.ID != id {
116 return nil, fmt.Errorf("service: username already exists")
117 }
118 }
119 user.Username = req.Username
120 }
121
122 return s.userRepo.Update(user)
123}
124
125func (s *UserService) DeleteUser(id int) error {
126 if id <= 0 {
127 return fmt.Errorf("service: invalid user ID")
128 }
129
130 err := s.userRepo.Delete(id)
131 if err != nil {
132 if strings.Contains(err.Error(), "not found") {
133 return fmt.Errorf("service: user not found")
134 }
135 return fmt.Errorf("service: %w", err)
136 }
137
138 return nil
139}
140
141func (s *UserService) validateCreateRequest(req CreateUserRequest) error {
142 if strings.TrimSpace(req.Email) == "" {
143 return fmt.Errorf("service: email is required")
144 }
145
146 if strings.TrimSpace(req.Username) == "" {
147 return fmt.Errorf("service: username is required")
148 }
149
150 if !strings.Contains(req.Email, "@") {
151 return fmt.Errorf("service: invalid email format")
152 }
153
154 if len(req.Username) < 3 {
155 return fmt.Errorf("service: username must be at least 3 characters")
156 }
157
158 return nil
159}
160
161type UpdateUserRequest struct {
162 Email string `json:"email,omitempty"`
163 Username string `json:"username,omitempty"`
164}