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

vocdoni / saas-backend / 17557469823

08 Sep 2025 04:25PM UTC coverage: 58.777% (-0.06%) from 58.841%
17557469823

Pull #213

github

altergui
fix
Pull Request #213: api: standardize parameters ProcessID, CensusID, GroupID, JobID, UserID, BundleID

254 of 345 new or added lines in 22 files covered. (73.62%)

19 existing lines in 7 files now uncovered.

5652 of 9616 relevant lines covered (58.78%)

32.01 hits per line

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

70.83
/db/process_bundles.go
1
package db
2

3
import (
4
        "bytes"
5
        "context"
6
        "fmt"
7

8
        "github.com/ethereum/go-ethereum/common"
9
        "github.com/vocdoni/saas-backend/internal"
10
        "go.mongodb.org/mongo-driver/bson"
11
        "go.mongodb.org/mongo-driver/mongo/options"
12
)
13

14
// SetProcessBundle creates a new process bundle or updates an existing one.
15
// It validates that the organization and census exist before creating or updating the bundle.
16
// Returns the bundle ID as a hex string on success.
17
func (ms *MongoStorage) SetProcessBundle(bundle *ProcessesBundle) (internal.ObjectID, error) {
16✔
18
        if bundle.ID.IsZero() {
25✔
19
                bundle.ID = internal.NewObjectID()
9✔
20
        }
9✔
21

22
        // Check that the org exists
23
        if _, err := ms.Organization(bundle.OrgAddress); err != nil {
17✔
24
                return internal.NilObjectID, fmt.Errorf("failed to get organization: %w", err)
1✔
25
        }
1✔
26

27
        // check that the census exists
28
        _, err := ms.Census(bundle.Census.ID)
15✔
29
        if err != nil {
15✔
NEW
30
                return internal.NilObjectID, fmt.Errorf("failed to get census: %w", err)
×
31
        }
×
32

33
        ms.keysLock.Lock()
15✔
34
        defer ms.keysLock.Unlock()
15✔
35
        // Create a context with a timeout
15✔
36
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
15✔
37
        defer cancel()
15✔
38

15✔
39
        // If the bundle has an ID, update it, otherwise create a new one
15✔
40
        filter := bson.M{"_id": bundle.ID}
15✔
41
        update := bson.M{"$set": bundle}
15✔
42
        opts := &options.UpdateOptions{}
15✔
43
        opts.SetUpsert(true)
15✔
44

15✔
45
        if _, err := ms.processBundles.UpdateOne(ctx, filter, update, opts); err != nil {
15✔
NEW
46
                return internal.NilObjectID, fmt.Errorf("failed to update process bundle: %w", err)
×
47
        }
×
48

49
        return bundle.ID, nil
15✔
50
}
51

52
// DelProcessBundle removes a process bundle by ID.
53
// Returns ErrInvalidData if the bundleID is zero, or ErrNotFound if no bundle with the given ID exists.
54
func (ms *MongoStorage) DelProcessBundle(bundleID internal.ObjectID) error {
3✔
55
        if bundleID.IsZero() {
4✔
56
                return ErrInvalidData
1✔
57
        }
1✔
58

59
        ms.keysLock.Lock()
2✔
60
        defer ms.keysLock.Unlock()
2✔
61
        // Create a context with a timeout
2✔
62
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
2✔
63
        defer cancel()
2✔
64

2✔
65
        // Delete the process bundle from the database using the ID
2✔
66
        filter := bson.M{"_id": bundleID}
2✔
67
        result, err := ms.processBundles.DeleteOne(ctx, filter)
2✔
68
        if err != nil {
2✔
69
                return fmt.Errorf("failed to delete process bundle: %w", err)
×
70
        }
×
71

72
        if result.DeletedCount == 0 {
3✔
73
                return ErrNotFound
1✔
74
        }
1✔
75

76
        return nil
1✔
77
}
78

79
// ProcessBundle retrieves a process bundle from the database based on its ID.
80
// Returns the bundle with all its associated data including census information and processes.
81
func (ms *MongoStorage) ProcessBundle(bundleID internal.ObjectID) (*ProcessesBundle, error) {
37✔
82
        if bundleID.IsZero() {
37✔
83
                return nil, ErrInvalidData
×
84
        }
×
85

86
        // Create a context with a timeout
87
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
37✔
88
        defer cancel()
37✔
89

37✔
90
        bundle := &ProcessesBundle{}
37✔
91
        if err := ms.processBundles.FindOne(ctx, bson.M{"_id": bundleID}).Decode(bundle); err != nil {
38✔
92
                return nil, fmt.Errorf("failed to get process bundle: %w", err)
1✔
93
        }
1✔
94

95
        return bundle, nil
36✔
96
}
97

98
// ProcessBundles retrieves all process bundles from the database.
99
// Returns a slice of all process bundles with their complete information.
100
func (ms *MongoStorage) ProcessBundles() ([]*ProcessesBundle, error) {
2✔
101
        // Create a context with a timeout
2✔
102
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
2✔
103
        defer cancel()
2✔
104

2✔
105
        cursor, err := ms.processBundles.Find(ctx, bson.M{})
2✔
106
        if err != nil {
2✔
107
                return nil, fmt.Errorf("failed to find process bundles: %w", err)
×
108
        }
×
109
        defer func() {
4✔
110
                err := cursor.Close(ctx)
2✔
111
                if err != nil {
2✔
112
                        fmt.Println("failed to close cursor")
×
113
                }
×
114
        }()
115

116
        var bundles []*ProcessesBundle
2✔
117
        if err := cursor.All(ctx, &bundles); err != nil {
2✔
118
                return nil, fmt.Errorf("failed to decode process bundles: %w", err)
×
119
        }
×
120

121
        return bundles, nil
2✔
122
}
123

124
// ProcessBundlesByProcess retrieves process bundles that contain a specific process ID.
125
// This allows finding all bundles that include a particular process.
126
func (ms *MongoStorage) ProcessBundlesByProcess(processID internal.HexBytes) ([]*ProcessesBundle, error) {
4✔
127
        if len(processID) == 0 {
5✔
128
                return nil, ErrInvalidData
1✔
129
        }
1✔
130

131
        // Create a context with a timeout
132
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
3✔
133
        defer cancel()
3✔
134

3✔
135
        // Find bundles where the processes array contains a process with the given ID
3✔
136
        filter := bson.M{"processes": processID}
3✔
137
        cursor, err := ms.processBundles.Find(ctx, filter)
3✔
138
        if err != nil {
3✔
139
                return nil, fmt.Errorf("failed to find process bundles by process ID: %w", err)
×
140
        }
×
141
        defer func() {
6✔
142
                err := cursor.Close(ctx)
3✔
143
                if err != nil {
3✔
144
                        fmt.Println("failed to close cursor")
×
145
                }
×
146
        }()
147

148
        var bundles []*ProcessesBundle
3✔
149
        if err := cursor.All(ctx, &bundles); err != nil {
3✔
150
                return nil, fmt.Errorf("failed to decode process bundles: %w", err)
×
151
        }
×
152

153
        return bundles, nil
3✔
154
}
155

156
// ProcessBundlesByOrg retrieves process bundles that belong to a specific organization.
157
// This allows finding all bundles created by a particular organization.
158
func (ms *MongoStorage) ProcessBundlesByOrg(orgAddress common.Address) ([]*ProcessesBundle, error) {
×
159
        if orgAddress.Cmp(common.Address{}) == 0 {
×
160
                return nil, ErrInvalidData
×
161
        }
×
162

163
        // Create a context with a timeout
164
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
×
165
        defer cancel()
×
166

×
167
        // Find bundles where the orgAddress matches the given address
×
168
        filter := bson.M{"orgAddress": orgAddress}
×
169
        cursor, err := ms.processBundles.Find(ctx, filter)
×
170
        if err != nil {
×
171
                return nil, fmt.Errorf("failed to find process bundles by organization: %w", err)
×
172
        }
×
173
        defer func() {
×
174
                err := cursor.Close(ctx)
×
175
                if err != nil {
×
176
                        fmt.Println("failed to close cursor")
×
177
                }
×
178
        }()
179

180
        var bundles []*ProcessesBundle
×
181
        if err := cursor.All(ctx, &bundles); err != nil {
×
182
                return nil, fmt.Errorf("failed to decode process bundles: %w", err)
×
183
        }
×
184

185
        return bundles, nil
×
186
}
187

188
// AddProcessesToBundle adds processes to an existing bundle if they don't already exist.
189
// It checks each process to avoid duplicates and only updates the database if new processes were added.
190
func (ms *MongoStorage) AddProcessesToBundle(bundleID internal.ObjectID, processes []internal.HexBytes) error {
5✔
191
        if bundleID.IsZero() {
6✔
192
                return ErrInvalidData
1✔
193
        }
1✔
194
        if len(processes) == 0 {
5✔
195
                return ErrInvalidData
1✔
196
        }
1✔
197

198
        bundle, err := ms.ProcessBundle(bundleID)
3✔
199
        if err != nil {
3✔
200
                return fmt.Errorf("failed to get process bundle: %w", err)
×
201
        }
×
202

203
        if bundle.ID.IsZero() {
3✔
NEW
204
                bundle.ID = internal.NewObjectID()
×
205
        }
×
206

207
        ms.keysLock.Lock()
3✔
208
        defer ms.keysLock.Unlock()
3✔
209
        // Create a context with a timeout
3✔
210
        ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
3✔
211
        defer cancel()
3✔
212

3✔
213
        // Check each process and add it if it doesn't already exist in the bundle
3✔
214
        processesAdded := false
3✔
215
        for _, newProcess := range processes {
7✔
216
                exists := false
4✔
217
                for _, existingProcess := range bundle.Processes {
13✔
218
                        if bytes.Equal(existingProcess, newProcess) {
10✔
219
                                exists = true
1✔
220
                                break
1✔
221
                        }
222
                }
223
                if !exists {
7✔
224
                        bundle.Processes = append(bundle.Processes, newProcess)
3✔
225
                        processesAdded = true
3✔
226
                }
3✔
227
        }
228

229
        // If no processes were added, return early
230
        if !processesAdded {
4✔
231
                return nil
1✔
232
        }
1✔
233

234
        // Update the bundle in the database
235
        filter := bson.M{"_id": bundleID}
2✔
236
        update := bson.M{"$set": bson.M{"processes": bundle.Processes}}
2✔
237
        if _, err := ms.processBundles.UpdateOne(ctx, filter, update); err != nil {
2✔
238
                return fmt.Errorf("failed to update process bundle: %w", err)
×
239
        }
×
240

241
        return nil
2✔
242
}
243

244
// NewBundleID generates a new unique ObjectID for a process bundle.
245
// This is used when creating a new bundle to ensure it has a unique identifier.
246
func (*MongoStorage) NewBundleID() internal.ObjectID {
6✔
247
        return internal.NewObjectID()
6✔
248
}
6✔
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

© 2025 Coveralls, Inc