• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gameap / gameap / 28878367588

07 Jul 2026 03:30PM UTC coverage: 82.185% (+5.7%) from 76.45%
28878367588

Pull #22

github

et-nik
e2e fixes
Pull Request #22: Develop into master

47018 of 57210 relevant lines covered (82.18%)

34985.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.17
/internal/api/users/putuser/handler.go
1
package putuser
2

3
import (
4
        "context"
5
        "encoding/json"
6
        "log/slog"
7
        "net/http"
8
        "strconv"
9
        "strings"
10

11
        "github.com/gameap/gameap/internal/api/base"
12
        "github.com/gameap/gameap/internal/audit"
13
        "github.com/gameap/gameap/internal/filters"
14
        "github.com/gameap/gameap/internal/rbac"
15
        "github.com/gameap/gameap/internal/repositories"
16
        "github.com/gameap/gameap/pkg/api"
17
        "github.com/gameap/gameap/pkg/auth"
18
        "github.com/pkg/errors"
19
)
20

21
type Handler struct {
22
        usersRepo   repositories.UserRepository
23
        serversRepo repositories.ServerRepository
24
        rbac        base.RBAC
25
        tm          base.TransactionManager
26
        responder   base.Responder
27
        audit       audit.Logger
28
}
29

30
func NewHandler(
31
        usersRepo repositories.UserRepository,
32
        serversRepo repositories.ServerRepository,
33
        rbac base.RBAC,
34
        tm base.TransactionManager,
35
        responder base.Responder,
36
        auditLogger audit.Logger,
37
) *Handler {
14✔
38
        if auditLogger == nil {
26✔
39
                auditLogger = audit.NopLogger{}
12✔
40
        }
12✔
41

42
        return &Handler{
14✔
43
                usersRepo:   usersRepo,
14✔
44
                serversRepo: serversRepo,
14✔
45
                rbac:        rbac,
14✔
46
                tm:          tm,
14✔
47
                responder:   responder,
14✔
48
                audit:       auditLogger,
14✔
49
        }
14✔
50
}
51

52
//nolint:funlen
53
func (h *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
14✔
54
        ctx := r.Context()
14✔
55

14✔
56
        session := auth.SessionFromContext(ctx)
14✔
57
        if !session.IsAuthenticated() {
15✔
58
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
59
                        errors.New("user not authenticated"),
1✔
60
                        http.StatusUnauthorized,
1✔
61
                ))
1✔
62

1✔
63
                return
1✔
64
        }
1✔
65

66
        input := api.NewInputReader(r)
13✔
67

13✔
68
        userID, err := input.ReadUint("id")
13✔
69
        if err != nil {
14✔
70
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
1✔
71
                        errors.WithMessage(err, "invalid user id"),
1✔
72
                        http.StatusBadRequest,
1✔
73
                ))
1✔
74

1✔
75
                return
1✔
76
        }
1✔
77

78
        updateInput := &updateUserInput{}
12✔
79

12✔
80
        err = json.NewDecoder(r.Body).Decode(&updateInput)
12✔
81
        if err != nil {
12✔
82
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
×
83
                        errors.WithMessage(err, "invalid request"),
×
84
                        http.StatusBadRequest,
×
85
                ))
×
86

×
87
                return
×
88
        }
×
89

90
        err = updateInput.Validate()
12✔
91
        if err != nil {
15✔
92
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
3✔
93
                        errors.WithMessage(err, "invalid input"),
3✔
94
                        http.StatusBadRequest,
3✔
95
                ))
3✔
96

3✔
97
                return
3✔
98
        }
3✔
99

100
        users, err := h.usersRepo.Find(ctx, &filters.FindUser{
9✔
101
                IDs: []uint{userID},
9✔
102
        }, nil, &filters.Pagination{
9✔
103
                Limit: 1,
9✔
104
        })
9✔
105
        if err != nil {
9✔
106
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to find user"))
×
107

×
108
                return
×
109
        }
×
110

111
        if len(users) == 0 {
10✔
112
                h.responder.WriteError(ctx, rw, api.NewNotFoundError("user not found"))
1✔
113

1✔
114
                return
1✔
115
        }
1✔
116

117
        user := &users[0]
8✔
118

8✔
119
        err = updateInput.Apply(user)
8✔
120
        if err != nil {
8✔
121
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to apply input"))
×
122

×
123
                return
×
124
        }
×
125

126
        err = h.tm.Do(ctx, func(ctx context.Context) error {
16✔
127
                err = h.usersRepo.Save(ctx, user)
8✔
128
                if err != nil {
8✔
129
                        return errors.WithMessage(err, "failed to save user")
×
130
                }
×
131

132
                err = h.serversRepo.SetUserServers(ctx, user.ID, updateInput.ServerIDs())
8✔
133
                if err != nil {
8✔
134
                        return errors.WithMessage(err, "failed to assign servers to user")
×
135
                }
×
136

137
                err = h.rbac.SetRolesToUser(ctx, user.ID, updateInput.Roles)
8✔
138
                if err != nil {
8✔
139
                        var errInvalidRole rbac.InvalidRoleNameError
×
140
                        if errors.As(err, &errInvalidRole) {
×
141
                                return api.WrapHTTPError(err, http.StatusUnprocessableEntity)
×
142
                        }
×
143

144
                        return errors.WithMessage(err, "failed to assign roles to user")
×
145
                }
146

147
                return nil
8✔
148
        })
149
        if err != nil {
8✔
150
                h.responder.WriteError(ctx, rw, err)
×
151

×
152
                return
×
153
        }
×
154

155
        userResID := strconv.FormatUint(uint64(user.ID), 10)
8✔
156
        audit.SensitiveOp(ctx, h.audit, audit.EventUserUpdate, audit.CategoryAdminOp,
8✔
157
                "user", userResID, "update")
8✔
158
        if len(updateInput.Roles) > 0 {
12✔
159
                audit.SensitiveOp(ctx, h.audit, audit.EventUserRolesAssign, audit.CategoryAdminOp,
4✔
160
                        "user", userResID, "role_assign",
4✔
161
                        slog.String("roles", strings.Join(updateInput.Roles, ",")))
4✔
162
        }
4✔
163

164
        roleNames, err := h.rbac.GetRoles(ctx, user.ID)
8✔
165
        if err != nil {
8✔
166
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to get user roles"))
×
167

×
168
                return
×
169
        }
×
170

171
        h.responder.Write(ctx, rw, newUserResponseFromUser(user, roleNames))
8✔
172
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc