diff --git a/doc/api.oa3 b/doc/api.oa3 index 735129cc..ccff2532 100644 --- a/doc/api.oa3 +++ b/doc/api.oa3 @@ -877,7 +877,47 @@ paths: application/json: schema: $ref: '#/components/schemas/Subject' - + + /alias/groups/{groupId}/subject/{field}: + get: + tags: + - alias + description: Base64 decode and download specified field from the groups's subject. Access granted to app token of account holder. + operationId: get-group-subject-field + security: + - bearerAuth: [] + parameters: + - name: groupId + in: path + description: specified group id + required: true + schema: + type: string + - name: field + in: path + description: field from subject to base64 decode and download + required: true + schema: + type: string + responses: + '200': + description: success + content: + application/json: + schema: + type: string + format: binary + '401': + description: permission denied + '404': + description: field, article not found + '405': + description: invalid field + '410': + description: account disabled + '500': + description: internal server error + /alias/groups/{groupId}/subject: put: tags: diff --git a/net/server/internal/api_getGroupSubjectField.go b/net/server/internal/api_getGroupSubjectField.go new file mode 100644 index 00000000..011b277c --- /dev/null +++ b/net/server/internal/api_getGroupSubjectField.go @@ -0,0 +1,56 @@ +package databag + +import ( + "time" + "bytes" + "errors" + "strings" + "net/http" + "gorm.io/gorm" + "encoding/base64" + "github.com/gorilla/mux" + "databag/internal/store" + "github.com/valyala/fastjson" +) + +func GetGroupSubjectField(w http.ResponseWriter, r *http.Request) { + + // scan parameters + params := mux.Vars(r) + groupId := params["groupId"] + field := params["field"] + elements := strings.Split(field, ".") + + account, code, err := BearerAppToken(r, false); + if err != nil { + ErrResponse(w, code, err) + return + } + + // load group + var slot store.GroupSlot + if err := store.DB.Preload("Group.GroupData").Where("account_id = ? AND group_slot_id = ?", account.ID, groupId).First(&slot).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + ErrResponse(w, http.StatusNotFound, err) + } else { + ErrResponse(w, http.StatusInternalServerError, err) + } + return + } + if slot.Group == nil { + ErrResponse(w, http.StatusNotFound, errors.New("referenced group missing")) + return + } + + // decode data + strData := fastjson.GetString([]byte(slot.Group.GroupData.Data), elements...) + binData, err := base64.StdEncoding.DecodeString(strData) + if err != nil { + ErrResponse(w, http.StatusNotFound, err) + return + } + + // response with content + http.ServeContent(w, r, field, time.Unix(slot.Group.Updated, 0), bytes.NewReader(binData)) +} + diff --git a/net/server/internal/routers.go b/net/server/internal/routers.go index 2ea7d829..c5890e9c 100644 --- a/net/server/internal/routers.go +++ b/net/server/internal/routers.go @@ -271,6 +271,13 @@ var routes = Routes{ AddGroup, }, + Route{ + "GetGroupSubjectField", + strings.ToUpper("Get"), + "/alias/groups/{groupId}/subject/{field}", + GetGroupSubjectField, + }, + Route{ "GetGroups", strings.ToUpper("Get"),