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

DigitalTolk / wireguard-ui / 24858999372

23 Apr 2026 09:09PM UTC coverage: 90.095% (-0.01%) from 90.107%
24858999372

Pull #20

github

web-flow
Merge 69a28cdcb into cae3dabf1
Pull Request #20: Fix admin

535 of 600 branches covered (89.17%)

Branch coverage included in aggregate %.

23 of 25 new or added lines in 4 files covered. (92.0%)

22 existing lines in 1 file now uncovered.

3276 of 3630 relevant lines covered (90.25%)

44.13 hits per line

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

96.77
/handler/api_v1_users.go
1
package handler
2

3
import (
4
        "net/http"
5
        "time"
6

7
        "github.com/labstack/echo/v4"
8
        "github.com/labstack/gommon/log"
9

10
        "github.com/DigitalTolk/wireguard-ui/store"
11
)
12

13
// APIListUsers returns all users (read-only, managed via SSO)
14
func APIListUsers(db store.IStore) echo.HandlerFunc {
3✔
15
        return func(c echo.Context) error {
6✔
16
                users, err := db.GetUsers()
3✔
17
                if err != nil {
4✔
18
                        return apiInternalError(c, "Cannot get user list")
1✔
19
                }
1✔
20
                return c.JSON(http.StatusOK, users)
2✔
21
        }
22
}
23

24
// APIPatchUserAdmin toggles admin status for a user
25
func APIPatchUserAdmin(db store.IStore) echo.HandlerFunc {
11✔
26
        return func(c echo.Context) error {
22✔
27
                username := c.Param("username")
11✔
28
                if !usernameRegexp.MatchString(username) {
12✔
29
                        return apiBadRequest(c, "Invalid username")
1✔
30
                }
1✔
31

32
                var body struct {
10✔
33
                        Admin bool `json:"admin"`
10✔
34
                }
10✔
35
                if err := c.Bind(&body); err != nil {
11✔
36
                        return apiBadRequest(c, "Invalid request body")
1✔
37
                }
1✔
38

39
                user, err := db.GetUserByName(username)
9✔
40
                if err != nil {
11✔
41
                        return apiNotFound(c, "User not found")
2✔
42
                }
2✔
43

44
                // prevent demoting yourself
45
                if !body.Admin && username == currentUser(c) {
8✔
46
                        return apiBadRequest(c, "Cannot remove your own admin role")
1✔
47
                }
1✔
48

49
                // prevent removing the last admin
50
                if !body.Admin && user.Admin {
9✔
51
                        users, err := db.GetUsers()
3✔
52
                        if err != nil {
3✔
NEW
53
                                return apiInternalError(c, "Cannot verify admin count")
×
NEW
54
                        }
×
55
                        adminCount := 0
3✔
56
                        for _, u := range users {
8✔
57
                                if u.Admin {
10✔
58
                                        adminCount++
5✔
59
                                }
5✔
60
                        }
61
                        if adminCount <= 1 {
4✔
62
                                return apiBadRequest(c, "Cannot remove the last admin")
1✔
63
                        }
1✔
64
                }
65

66
                user.Admin = body.Admin
5✔
67
                user.UpdatedAt = time.Now().UTC()
5✔
68
                if err := db.SaveUser(user); err != nil {
6✔
69
                        return apiInternalError(c, "Cannot update user")
1✔
70
                }
1✔
71

72
                action := "user.demote"
4✔
73
                if body.Admin {
6✔
74
                        action = "user.promote"
2✔
75
                }
2✔
76
                log.Infof("Changed admin status for %s to %v", username, body.Admin)
4✔
77
                auditLogEvent(c, action, "user", username, nil)
4✔
78
                return c.JSON(http.StatusOK, user)
4✔
79
        }
80
}
81

82
// APIGetUser returns a single user by username
83
func APIGetUser(db store.IStore) echo.HandlerFunc {
4✔
84
        return func(c echo.Context) error {
8✔
85
                username := c.Param("username")
4✔
86
                if !usernameRegexp.MatchString(username) {
5✔
87
                        return apiBadRequest(c, "Invalid username")
1✔
88
                }
1✔
89

90
                user, err := db.GetUserByName(username)
3✔
91
                if err != nil {
4✔
92
                        return apiNotFound(c, "User not found")
1✔
93
                }
1✔
94
                return c.JSON(http.StatusOK, user)
2✔
95
        }
96
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc