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

gameap / gameap / 25960901307

16 May 2026 11:29AM UTC coverage: 76.887% (+0.2%) from 76.64%
25960901307

push

github

et-nik
audit logs tests

45395 of 59041 relevant lines covered (76.89%)

33895.16 hits per line

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

79.8
/internal/api/nodes/putnode/handler.go
1
package putnode
2

3
import (
4
        "context"
5
        "encoding/json"
6
        "net/http"
7
        "path/filepath"
8
        "strconv"
9
        "time"
10

11
        "github.com/gameap/gameap/internal/api/base"
12
        "github.com/gameap/gameap/internal/audit"
13
        "github.com/gameap/gameap/internal/domain"
14
        "github.com/gameap/gameap/internal/files"
15
        "github.com/gameap/gameap/internal/filters"
16
        "github.com/gameap/gameap/internal/repositories"
17
        "github.com/gameap/gameap/pkg/api"
18
        "github.com/pkg/errors"
19
        "github.com/rs/xid"
20
)
21

22
const certificatesPath = "certs"
23

24
var (
25
        ErrFailedToSaveCertificate = errors.New("failed to save certificate")
26
        ErrFailedToUpdateNode      = errors.New("failed to update node")
27
        ErrNodeNotFound            = errors.New("node not found")
28
)
29

30
type Handler struct {
31
        repo        repositories.NodeRepository
32
        fileManager files.FileManager
33
        responder   base.Responder
34
        audit       audit.Logger
35
}
36

37
func NewHandler(
38
        repo repositories.NodeRepository,
39
        fileManager files.FileManager,
40
        responder base.Responder,
41
        auditLogger audit.Logger,
42
) *Handler {
16✔
43
        if auditLogger == nil {
30✔
44
                auditLogger = audit.NopLogger{}
14✔
45
        }
14✔
46

47
        return &Handler{
16✔
48
                repo:        repo,
16✔
49
                fileManager: fileManager,
16✔
50
                responder:   responder,
16✔
51
                audit:       auditLogger,
16✔
52
        }
16✔
53
}
54

55
func (h *Handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
16✔
56
        ctx := r.Context()
16✔
57

16✔
58
        input := api.NewInputReader(r)
16✔
59

16✔
60
        nodeID, err := input.ReadUint("id")
16✔
61
        if err != nil {
16✔
62
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
×
63
                        errors.WithMessage(err, "invalid node id"),
×
64
                        http.StatusBadRequest,
×
65
                ))
×
66

×
67
                return
×
68
        }
×
69

70
        node, err := h.findNode(ctx, nodeID)
16✔
71
        if err != nil {
19✔
72
                h.responder.WriteError(ctx, rw, err)
3✔
73

3✔
74
                return
3✔
75
        }
3✔
76

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

×
85
                return
×
86
        }
×
87

88
        err = updateInput.Validate()
13✔
89
        if err != nil {
17✔
90
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
4✔
91
                        errors.WithMessage(err, "validation failed"),
4✔
92
                        http.StatusUnprocessableEntity,
4✔
93
                ))
4✔
94

4✔
95
                return
4✔
96
        }
4✔
97

98
        updatedNode, err := h.updateNode(ctx, node, &updateInput)
9✔
99
        if err != nil {
10✔
100
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to update node"))
1✔
101

1✔
102
                return
1✔
103
        }
1✔
104

105
        audit.SensitiveOp(ctx, h.audit, audit.EventNodeUpdate, audit.CategoryNodeOp,
8✔
106
                "node", strconv.FormatUint(uint64(nodeID), 10), "update")
8✔
107

8✔
108
        response := newNodeResponse(updatedNode)
8✔
109
        h.responder.Write(ctx, rw, response)
8✔
110
}
111

112
func (h *Handler) findNode(ctx context.Context, nodeID uint) (*domain.Node, error) {
16✔
113
        nodes, err := h.repo.Find(ctx, &filters.FindNode{
16✔
114
                IDs: []uint{nodeID},
16✔
115
        }, nil, &filters.Pagination{
16✔
116
                Limit:  1,
16✔
117
                Offset: 0,
16✔
118
        })
16✔
119
        if err != nil {
16✔
120
                return nil, errors.WithMessage(err, "failed to find node")
×
121
        }
×
122

123
        if len(nodes) == 0 {
19✔
124
                return nil, api.WrapHTTPError(ErrNodeNotFound, http.StatusNotFound)
3✔
125
        }
3✔
126

127
        return &nodes[0], nil
13✔
128
}
129

130
func (h *Handler) updateNode(ctx context.Context, node *domain.Node, input *updateNodeInput) (*domain.Node, error) {
9✔
131
        oldCertPath := node.GdaemonServerCert
9✔
132

9✔
133
        if input.GdaemonServerCert != nil && *input.GdaemonServerCert != "" {
13✔
134
                certXID := xid.New().String()
4✔
135
                certPath := filepath.Join(certificatesPath, certXID+".crt")
4✔
136

4✔
137
                if err := h.fileManager.Write(ctx, certPath, []byte(*input.GdaemonServerCert)); err != nil {
5✔
138
                        return nil, errors.WithMessage(ErrFailedToSaveCertificate, err.Error())
1✔
139
                }
1✔
140

141
                node.GdaemonServerCert = certPath
3✔
142
        }
143

144
        input.ApplyToNode(node)
8✔
145

8✔
146
        now := time.Now()
8✔
147
        node.UpdatedAt = &now
8✔
148

8✔
149
        if err := h.repo.Save(ctx, node); err != nil {
8✔
150
                if input.GdaemonServerCert != nil && *input.GdaemonServerCert != "" {
×
151
                        _ = h.fileManager.Delete(ctx, node.GdaemonServerCert)
×
152
                }
×
153

154
                return nil, errors.WithMessage(ErrFailedToUpdateNode, err.Error())
×
155
        }
156

157
        if input.GdaemonServerCert != nil && *input.GdaemonServerCert != "" && oldCertPath != "" {
11✔
158
                _ = h.fileManager.Delete(ctx, oldCertPath)
3✔
159
        }
3✔
160

161
        return node, nil
8✔
162
}
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