mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-06-17 04:18:53 -04:00
* adds creating addressbooks, calendars, mailboxes * adds deleting mailbox, event, identity * adds modifying an email * introduce template functions for the Groupware API in templates.go, and use those in route function implementations whenever possible * add capability checking for mail, quota, blobs * adds Changes interface * adds JmapResponse interface
116 lines
3.1 KiB
Go
116 lines
3.1 KiB
Go
package groupware
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/opencloud-eu/opencloud/pkg/jmap"
|
|
"github.com/opencloud-eu/opencloud/pkg/log"
|
|
)
|
|
|
|
const (
|
|
DefaultBlobDownloadType = "application/octet-stream"
|
|
)
|
|
|
|
func (g *Groupware) GetBlobMeta(w http.ResponseWriter, r *http.Request) {
|
|
get(Blob, w, r, g, g.jmap.GetBlobMetadata)
|
|
}
|
|
|
|
func (g *Groupware) UploadBlob(w http.ResponseWriter, r *http.Request) {
|
|
g.respond(w, r, func(req Request) Response {
|
|
contentType := r.Header.Get("Content-Type")
|
|
body := r.Body
|
|
if body != nil {
|
|
defer func(Body io.ReadCloser) {
|
|
err := Body.Close()
|
|
if err != nil {
|
|
req.logger.Error().Err(err).Msg("failed to close response body")
|
|
}
|
|
}(body)
|
|
}
|
|
|
|
accountId, err := req.GetAccountIdForBlob()
|
|
if err != nil {
|
|
return req.error(accountId, err)
|
|
}
|
|
logger := log.From(req.logger.With().Str(logAccountId, accountId))
|
|
ctx := req.ctx.WithLogger(logger)
|
|
resp, lang, jerr := g.jmap.UploadBlobStream(accountId, contentType, body, ctx)
|
|
if jerr != nil {
|
|
return req.jmapError(accountId, jerr, req.session.State, lang)
|
|
}
|
|
|
|
return req.respondWithoutStatus(accountId, resp)
|
|
})
|
|
}
|
|
|
|
// Download a BLOB by its identifier.
|
|
func (g *Groupware) DownloadBlob(w http.ResponseWriter, r *http.Request) {
|
|
g.stream(w, r, func(req Request, w http.ResponseWriter) *Error {
|
|
blobId, err := req.PathParam(UriParamBlobId) // the unique identifier of the blob to download
|
|
if err != nil {
|
|
return err
|
|
}
|
|
name, err := req.PathParam(UriParamBlobName) // the filename of the blob to download, which is then used in the response and may be arbitrary if unknown
|
|
if err != nil {
|
|
return err
|
|
}
|
|
typ, _ := req.getStringParam(QueryParamBlobType, "") // optionally, the Content-Type of the blob, which is then used in the response
|
|
|
|
accountId, gwerr := req.GetAccountIdForBlob()
|
|
if gwerr != nil {
|
|
return gwerr
|
|
}
|
|
logger := log.From(req.logger.With().Str(logAccountId, accountId).Str(UriParamBlobId, blobId))
|
|
ctx := req.ctx.WithLogger(logger)
|
|
|
|
return req.serveBlob(blobId, name, typ, ctx, accountId, w)
|
|
})
|
|
}
|
|
|
|
func (r *Request) serveBlob(blobId string, name string, typ string, ctx jmap.Context, accountId string, w http.ResponseWriter) *Error {
|
|
if typ == "" {
|
|
typ = DefaultBlobDownloadType
|
|
}
|
|
blob, lang, jerr := r.g.jmap.DownloadBlobStream(accountId, blobId, name, typ, ctx)
|
|
if blob != nil && blob.Body != nil {
|
|
defer func(Body io.ReadCloser) {
|
|
err := Body.Close()
|
|
if err != nil {
|
|
ctx.Logger.Error().Err(err).Msg("failed to close response body")
|
|
}
|
|
}(blob.Body)
|
|
}
|
|
if jerr != nil {
|
|
return r.apiErrorFromJmap(jerr)
|
|
}
|
|
if blob == nil {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return nil
|
|
}
|
|
|
|
if blob.Type != "" {
|
|
w.Header().Add("Content-Type", blob.Type)
|
|
}
|
|
if blob.CacheControl != "" {
|
|
w.Header().Add("Cache-Control", blob.CacheControl)
|
|
}
|
|
if blob.ContentDisposition != "" {
|
|
w.Header().Add("Content-Disposition", blob.ContentDisposition)
|
|
}
|
|
if blob.Size >= 0 {
|
|
w.Header().Add("Content-Size", strconv.Itoa(blob.Size))
|
|
}
|
|
if lang != "" {
|
|
w.Header().Add("Content-Language", string(lang))
|
|
}
|
|
|
|
_, err := io.Copy(w, blob.Body)
|
|
if err != nil {
|
|
return r.observedParameterError(ErrorStreamingResponse)
|
|
}
|
|
|
|
return nil
|
|
}
|