/
attachment.go
195 lines (146 loc) · 6.24 KB
/
attachment.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package service
import (
"github.com/EmissarySocial/emissary/model"
"github.com/benpate/data"
"github.com/benpate/data/option"
"github.com/benpate/derp"
"github.com/benpate/exp"
"github.com/benpate/mediaserver"
"github.com/benpate/rosetta/schema"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// Attachment manages all interactions with the Attachment collection
type Attachment struct {
collection data.Collection
mediaServer mediaserver.MediaServer
host string
}
// NewAttachment returns a fully populated Attachment service
func NewAttachment() Attachment {
return Attachment{}
}
/******************************************
* Lifecycle Methods
******************************************/
// Refresh updates any stateful data that is cached inside this service.
func (service *Attachment) Refresh(collection data.Collection, mediaServer mediaserver.MediaServer, host string) {
service.collection = collection
service.mediaServer = mediaServer
service.host = host
}
// Close stops any background processes controlled by this service
func (service *Attachment) Close() {
}
/******************************************
* Common Data Methods
******************************************/
// New creates a newly initialized Attachment that is ready to use
func (service *Attachment) New() model.Attachment {
return model.NewAttachment("", primitive.NilObjectID)
}
// List returns an iterator containing all of the Attachments who match the provided criteria
func (service *Attachment) List(criteria exp.Expression, options ...option.Option) (data.Iterator, error) {
return service.collection.Iterator(notDeleted(criteria), options...)
}
func (service *Attachment) Query(criteria exp.Expression, options ...option.Option) ([]model.Attachment, error) {
result := make([]model.Attachment, 0)
if err := service.collection.Query(&result, notDeleted(criteria), options...); err != nil {
return result, derp.Wrap(err, "service.Attachment", "Error querying Attachments", criteria, options)
}
return result, nil
}
// Load retrieves an Attachment from the database
func (service *Attachment) Load(criteria exp.Expression, result *model.Attachment) error {
if err := service.collection.Load(notDeleted(criteria), result); err != nil {
return derp.Wrap(err, "service.Attachment", "Error loading Attachment", criteria)
}
return nil
}
// Save adds/updates an Attachment in the database
func (service *Attachment) Save(attachment *model.Attachment, note string) error {
// Clean the value before saving
if err := service.Schema().Clean(attachment); err != nil {
return derp.Wrap(err, "service.Attachment.Save", "Error cleaning Attachment", attachment)
}
// Calculate the URL
attachment.SetURL(service.host)
// Save the record to the database
if err := service.collection.Save(attachment, note); err != nil {
return derp.Wrap(err, "service.Attachment", "Error saving Attachment", attachment, note)
}
return nil
}
// Delete removes an Attachment from the database (virtual delete)
func (service *Attachment) Delete(attachment *model.Attachment, note string) error {
// Delete uploaded files from MediaServer
if err := service.mediaServer.Delete(attachment.AttachmentID.Hex()); err != nil {
derp.Report(derp.Wrap(err, "service.Attachment", "Error deleting attached files", attachment))
// Fail loudly, but do not stop.
}
// Delete Attachment record last.
if err := service.collection.Delete(attachment, note); err != nil {
return derp.Wrap(err, "service.Attachment", "Error deleting Attachment", attachment, note)
}
return nil
}
func (service *Attachment) Schema() schema.Schema {
return schema.New(model.AttachmentSchema())
}
/******************************************
* Custom Queries
******************************************/
func (service *Attachment) QueryByObjectID(objectType string, objectID primitive.ObjectID) ([]model.Attachment, error) {
return service.Query(
exp.Equal("objectType", objectType).
AndEqual("objectId", objectID),
option.SortAsc("rank"))
}
func (service *Attachment) LoadFirstByObjectID(objectType string, objectID primitive.ObjectID) (model.Attachment, error) {
attachments, err := service.Query(
exp.Equal("objectType", objectType).
AndEqual("objectId", objectID),
option.SortAsc("rank"), option.FirstRow())
if err != nil {
return model.Attachment{}, derp.Wrap(err, "service.Attachment.LoadFirstByObjectID", "Error loading first attachment", objectType, objectID)
}
for _, attachment := range attachments {
return attachment, err
}
return model.Attachment{}, derp.Wrap(err, "service.Attachment", "No attachments found", objectType, objectID)
}
func (service *Attachment) LoadByID(objectType string, objectID primitive.ObjectID, attachmentID primitive.ObjectID, result *model.Attachment) error {
criteria := exp.Equal("_id", attachmentID).
AndEqual("objectType", objectType).
AndEqual("objectId", objectID)
if err := service.Load(criteria, result); err != nil {
return derp.Wrap(err, "service.Attachment.LoadByID", "Error loading attachment", objectType, objectID, attachmentID)
}
return nil
}
func (service *Attachment) DeleteByID(objectType string, objectID primitive.ObjectID, attachmentID primitive.ObjectID, note string) error {
const location = "service.Attachment.DeleteByID"
// Load the Attachment from the database
attachment := model.NewAttachment(objectType, objectID)
if err := service.LoadByID(objectType, objectID, attachmentID, &attachment); err != nil {
return derp.Wrap(err, location, "Error loading attachment")
}
// Delete the attachment
if err := service.Delete(&attachment, note); err != nil {
return derp.Wrap(err, location, "Error deleting attachment")
}
// Success.
return nil
}
// DeleteByStream removes all attachments from the provided stream (virtual delete)
func (service *Attachment) DeleteAll(objectType string, objectID primitive.ObjectID, note string) error {
attachments, err := service.QueryByObjectID(objectType, objectID)
if err != nil {
return derp.Wrap(err, "service.Attachment.DeleteByStream", "Error listing attachments", objectID)
}
for _, attachment := range attachments {
if err := service.Delete(&attachment, note); err != nil {
derp.Report(derp.Wrap(err, "service.Attachment.DeleteByStream", "Error deleting child stream", attachment))
}
}
return nil
}