• 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

78.38
/internal/api/plugins/uninstall/handler.go
1
package uninstall
2

3
import (
4
        "context"
5
        "net/http"
6
        "path"
7
        "strconv"
8

9
        "github.com/gameap/gameap/internal/api/base"
10
        "github.com/gameap/gameap/internal/audit"
11
        "github.com/gameap/gameap/internal/domain"
12
        "github.com/gameap/gameap/internal/files"
13
        "github.com/gameap/gameap/internal/filters"
14
        "github.com/gameap/gameap/internal/repositories"
15
        "github.com/gameap/gameap/pkg/api"
16
        pkgplugin "github.com/gameap/gameap/pkg/plugin"
17
        "github.com/pkg/errors"
18
)
19

20
type PluginManager interface {
21
        GetPlugin(pluginID string) (*pkgplugin.LoadedPlugin, bool)
22
        Unload(ctx context.Context, pluginID string) error
23
}
24

25
type Handler struct {
26
        pluginRepo  repositories.PluginRepository
27
        fileManager files.FileManager
28
        manager     PluginManager
29
        pluginsDir  string
30
        responder   base.Responder
31
        audit       audit.Logger
32
}
33

34
func NewHandler(
35
        pluginRepo repositories.PluginRepository,
36
        fileManager files.FileManager,
37
        manager PluginManager,
38
        pluginsDir string,
39
        responder base.Responder,
40
        auditLogger audit.Logger,
41
) *Handler {
7✔
42
        if auditLogger == nil {
12✔
43
                auditLogger = audit.NopLogger{}
5✔
44
        }
5✔
45

46
        return &Handler{
7✔
47
                pluginRepo:  pluginRepo,
7✔
48
                fileManager: fileManager,
7✔
49
                manager:     manager,
7✔
50
                pluginsDir:  pluginsDir,
7✔
51
                responder:   responder,
7✔
52
                audit:       auditLogger,
7✔
53
        }
7✔
54
}
55

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

7✔
59
        storePluginID, err := api.NewInputReader(r).ReadString("id")
7✔
60
        if err != nil {
7✔
61
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to read plugin ID"))
×
62

×
63
                return
×
64
        }
×
65

66
        dbID := pkgplugin.ParsePluginID(storePluginID)
7✔
67

7✔
68
        installedPlugins, err := h.pluginRepo.Find(ctx, filters.FindPluginByIDs(dbID), nil, nil)
7✔
69
        if err != nil {
7✔
70
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to find installed plugin"))
×
71

×
72
                return
×
73
        }
×
74

75
        if len(installedPlugins) == 0 {
9✔
76
                h.responder.WriteError(ctx, rw, api.WrapHTTPError(
2✔
77
                        errors.New("plugin not installed"),
2✔
78
                        http.StatusNotFound,
2✔
79
                ))
2✔
80

2✔
81
                return
2✔
82
        }
2✔
83

84
        pluginRecord := &installedPlugins[0]
5✔
85

5✔
86
        if err := h.unloadPlugin(ctx, dbID); err != nil {
6✔
87
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to unload plugin"))
1✔
88

1✔
89
                return
1✔
90
        }
1✔
91

92
        filename := storePluginID + ".wasm"
4✔
93
        if pluginRecord.Filename != nil && *pluginRecord.Filename != "" {
8✔
94
                filename = *pluginRecord.Filename
4✔
95
        }
4✔
96

97
        pluginPath := path.Join(h.pluginsDir, filename)
4✔
98

4✔
99
        if h.fileManager.Exists(ctx, pluginPath) {
8✔
100
                if err := h.fileManager.Delete(ctx, pluginPath); err != nil {
4✔
101
                        h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to delete plugin file"))
×
102

×
103
                        return
×
104
                }
×
105
        }
106

107
        if err := h.pluginRepo.Delete(ctx, dbID); err != nil {
4✔
108
                h.responder.WriteError(ctx, rw, errors.WithMessage(err, "failed to delete plugin record"))
×
109

×
110
                return
×
111
        }
×
112

113
        audit.SensitiveOp(ctx, h.audit, audit.EventPluginUninstall, audit.CategoryPluginOp,
4✔
114
                "plugin", strconv.FormatUint(uint64(dbID), 10), "uninstall")
4✔
115

4✔
116
        rw.WriteHeader(http.StatusNoContent)
4✔
117
}
118

119
func (h *Handler) unloadPlugin(ctx context.Context, dbID domain.Uint64ID) error {
5✔
120
        if h.manager == nil {
7✔
121
                return nil
2✔
122
        }
2✔
123

124
        managerID := pkgplugin.CompactPluginID(dbID)
3✔
125
        if _, exists := h.manager.GetPlugin(managerID); !exists {
4✔
126
                return nil
1✔
127
        }
1✔
128

129
        return h.manager.Unload(ctx, managerID)
2✔
130
}
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