mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-05 19:59:37 -06:00
enhancement: refine the profile photo service and introduce httpDataProviders which allows reusing the endpoints
This commit is contained in:
@@ -16,6 +16,7 @@ packages:
|
||||
HTTPClient:
|
||||
Permissions:
|
||||
RoleService:
|
||||
UsersUserProfilePhotoProvider:
|
||||
github.com/opencloud-eu/reva/v2/pkg/events:
|
||||
config:
|
||||
dir: "mocks"
|
||||
|
||||
191
services/graph/mocks/users_user_profile_photo_provider.go
Normal file
191
services/graph/mocks/users_user_profile_photo_provider.go
Normal file
@@ -0,0 +1,191 @@
|
||||
// Code generated by mockery. DO NOT EDIT.
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
io "io"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// UsersUserProfilePhotoProvider is an autogenerated mock type for the UsersUserProfilePhotoProvider type
|
||||
type UsersUserProfilePhotoProvider struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type UsersUserProfilePhotoProvider_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *UsersUserProfilePhotoProvider) EXPECT() *UsersUserProfilePhotoProvider_Expecter {
|
||||
return &UsersUserProfilePhotoProvider_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// DeletePhoto provides a mock function with given fields: ctx, id
|
||||
func (_m *UsersUserProfilePhotoProvider) DeletePhoto(ctx context.Context, id string) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for DeletePhoto")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UsersUserProfilePhotoProvider_DeletePhoto_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DeletePhoto'
|
||||
type UsersUserProfilePhotoProvider_DeletePhoto_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// DeletePhoto is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - id string
|
||||
func (_e *UsersUserProfilePhotoProvider_Expecter) DeletePhoto(ctx interface{}, id interface{}) *UsersUserProfilePhotoProvider_DeletePhoto_Call {
|
||||
return &UsersUserProfilePhotoProvider_DeletePhoto_Call{Call: _e.mock.On("DeletePhoto", ctx, id)}
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_DeletePhoto_Call) Run(run func(ctx context.Context, id string)) *UsersUserProfilePhotoProvider_DeletePhoto_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_DeletePhoto_Call) Return(_a0 error) *UsersUserProfilePhotoProvider_DeletePhoto_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_DeletePhoto_Call) RunAndReturn(run func(context.Context, string) error) *UsersUserProfilePhotoProvider_DeletePhoto_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// GetPhoto provides a mock function with given fields: ctx, id
|
||||
func (_m *UsersUserProfilePhotoProvider) GetPhoto(ctx context.Context, id string) ([]byte, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for GetPhoto")
|
||||
}
|
||||
|
||||
var r0 []byte
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) ([]byte, error)); ok {
|
||||
return rf(ctx, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string) []byte); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]byte)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UsersUserProfilePhotoProvider_GetPhoto_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPhoto'
|
||||
type UsersUserProfilePhotoProvider_GetPhoto_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// GetPhoto is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - id string
|
||||
func (_e *UsersUserProfilePhotoProvider_Expecter) GetPhoto(ctx interface{}, id interface{}) *UsersUserProfilePhotoProvider_GetPhoto_Call {
|
||||
return &UsersUserProfilePhotoProvider_GetPhoto_Call{Call: _e.mock.On("GetPhoto", ctx, id)}
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_GetPhoto_Call) Run(run func(ctx context.Context, id string)) *UsersUserProfilePhotoProvider_GetPhoto_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_GetPhoto_Call) Return(_a0 []byte, _a1 error) *UsersUserProfilePhotoProvider_GetPhoto_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_GetPhoto_Call) RunAndReturn(run func(context.Context, string) ([]byte, error)) *UsersUserProfilePhotoProvider_GetPhoto_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// UpdatePhoto provides a mock function with given fields: ctx, id, rc
|
||||
func (_m *UsersUserProfilePhotoProvider) UpdatePhoto(ctx context.Context, id string, rc io.Reader) error {
|
||||
ret := _m.Called(ctx, id, rc)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdatePhoto")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, io.Reader) error); ok {
|
||||
r0 = rf(ctx, id, rc)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// UsersUserProfilePhotoProvider_UpdatePhoto_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UpdatePhoto'
|
||||
type UsersUserProfilePhotoProvider_UpdatePhoto_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// UpdatePhoto is a helper method to define mock.On call
|
||||
// - ctx context.Context
|
||||
// - id string
|
||||
// - rc io.Reader
|
||||
func (_e *UsersUserProfilePhotoProvider_Expecter) UpdatePhoto(ctx interface{}, id interface{}, rc interface{}) *UsersUserProfilePhotoProvider_UpdatePhoto_Call {
|
||||
return &UsersUserProfilePhotoProvider_UpdatePhoto_Call{Call: _e.mock.On("UpdatePhoto", ctx, id, rc)}
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_UpdatePhoto_Call) Run(run func(ctx context.Context, id string, rc io.Reader)) *UsersUserProfilePhotoProvider_UpdatePhoto_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(string), args[2].(io.Reader))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_UpdatePhoto_Call) Return(_a0 error) *UsersUserProfilePhotoProvider_UpdatePhoto_Call {
|
||||
_c.Call.Return(_a0)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *UsersUserProfilePhotoProvider_UpdatePhoto_Call) RunAndReturn(run func(context.Context, string, io.Reader) error) *UsersUserProfilePhotoProvider_UpdatePhoto_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewUsersUserProfilePhotoProvider creates a new instance of UsersUserProfilePhotoProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewUsersUserProfilePhotoProvider(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *UsersUserProfilePhotoProvider {
|
||||
mock := &UsersUserProfilePhotoProvider{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storage/utils/metadata"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
@@ -21,7 +20,7 @@ type (
|
||||
GetPhoto(ctx context.Context, id string) ([]byte, error)
|
||||
|
||||
// UpdatePhoto retrieves the requested photo
|
||||
UpdatePhoto(ctx context.Context, id string, rc io.Reader) error
|
||||
UpdatePhoto(ctx context.Context, id string, r io.Reader) error
|
||||
|
||||
// DeletePhoto deletes the requested photo
|
||||
DeletePhoto(ctx context.Context, id string) error
|
||||
@@ -34,9 +33,6 @@ var (
|
||||
|
||||
// ErrNoBytes is returned when no bytes are found
|
||||
ErrNoBytes = errors.New("no bytes")
|
||||
|
||||
// ErrNoUser is returned when no user is found
|
||||
ErrNoUser = errors.New("no user found")
|
||||
)
|
||||
|
||||
// UsersUserProfilePhotoService is the implementation of the UsersUserProfilePhotoProvider interface
|
||||
@@ -71,8 +67,8 @@ func (s UsersUserProfilePhotoService) DeletePhoto(ctx context.Context, id string
|
||||
}
|
||||
|
||||
// UpdatePhoto updates the requested photo
|
||||
func (s UsersUserProfilePhotoService) UpdatePhoto(ctx context.Context, id string, rc io.Reader) error {
|
||||
photo, err := io.ReadAll(rc)
|
||||
func (s UsersUserProfilePhotoService) UpdatePhoto(ctx context.Context, id string, r io.Reader) error {
|
||||
photo, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -98,66 +94,61 @@ func NewUsersUserProfilePhotoApi(usersUserProfilePhotoService UsersUserProfilePh
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetProfilePhoto provides the requested photo
|
||||
func (api UsersUserProfilePhotoApi) GetProfilePhoto(w http.ResponseWriter, r *http.Request) {
|
||||
id, ok := api.getUserID(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// GetProfilePhoto creates a handler which renders the corresponding photo
|
||||
func (api UsersUserProfilePhotoApi) GetProfilePhoto(h HTTPDataHandler[string]) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
v, ok := h(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
photo, err := api.usersUserProfilePhotoService.GetPhoto(r.Context(), id)
|
||||
if err != nil {
|
||||
api.logger.Debug().Err(err)
|
||||
errorcode.GeneralException.Render(w, r, http.StatusNotFound, "failed to get photo")
|
||||
return
|
||||
}
|
||||
photo, err := api.usersUserProfilePhotoService.GetPhoto(r.Context(), v)
|
||||
if err != nil {
|
||||
api.logger.Debug().Err(err)
|
||||
errorcode.GeneralException.Render(w, r, http.StatusNotFound, "failed to get photo")
|
||||
return
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
_, _ = w.Write(photo)
|
||||
render.Status(r, http.StatusOK)
|
||||
_, _ = w.Write(photo)
|
||||
}
|
||||
}
|
||||
|
||||
// UpsertProfilePhoto updates or inserts (initial create) the requested photo
|
||||
func (api UsersUserProfilePhotoApi) UpsertProfilePhoto(w http.ResponseWriter, r *http.Request) {
|
||||
id, ok := api.getUserID(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// UpsertProfilePhoto creates a handler which updates or creates the corresponding photo
|
||||
func (api UsersUserProfilePhotoApi) UpsertProfilePhoto(h HTTPDataHandler[string]) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
v, ok := h(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if err := api.usersUserProfilePhotoService.UpdatePhoto(r.Context(), id, r.Body); err != nil {
|
||||
api.logger.Debug().Err(err)
|
||||
errorcode.GeneralException.Render(w, r, http.StatusNotFound, "failed to update photo")
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = r.Body.Close()
|
||||
}()
|
||||
if err := api.usersUserProfilePhotoService.UpdatePhoto(r.Context(), v, r.Body); err != nil {
|
||||
api.logger.Debug().Err(err)
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "failed to update photo")
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
_ = r.Body.Close()
|
||||
}()
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
render.Status(r, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteProfilePhoto deletes the requested photo
|
||||
func (api UsersUserProfilePhotoApi) DeleteProfilePhoto(w http.ResponseWriter, r *http.Request) {
|
||||
id, ok := api.getUserID(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// DeleteProfilePhoto creates a handler which deletes the corresponding photo
|
||||
func (api UsersUserProfilePhotoApi) DeleteProfilePhoto(h HTTPDataHandler[string]) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
v, ok := h(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if err := api.usersUserProfilePhotoService.DeletePhoto(r.Context(), id); err != nil {
|
||||
api.logger.Debug().Err(err)
|
||||
errorcode.GeneralException.Render(w, r, http.StatusNotFound, "failed to delete photo")
|
||||
return
|
||||
}
|
||||
if err := api.usersUserProfilePhotoService.DeletePhoto(r.Context(), v); err != nil {
|
||||
api.logger.Debug().Err(err)
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "failed to delete photo")
|
||||
return
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
}
|
||||
|
||||
func (api UsersUserProfilePhotoApi) getUserID(w http.ResponseWriter, r *http.Request) (string, bool) {
|
||||
u, ok := revactx.ContextGetUser(r.Context())
|
||||
if !ok {
|
||||
api.logger.Debug().Msg(ErrNoUser.Error())
|
||||
errorcode.GeneralException.Render(w, r, http.StatusMethodNotAllowed, ErrNoUser.Error())
|
||||
return "", false
|
||||
}
|
||||
|
||||
return u.GetId().GetOpaqueId(), true
|
||||
render.Status(r, http.StatusOK)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,118 @@
|
||||
package svc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/services/graph/mocks"
|
||||
svc "github.com/opencloud-eu/opencloud/services/graph/pkg/service/v0"
|
||||
)
|
||||
|
||||
func TestNewUsersUserProfilePhotoApi(t *testing.T) {
|
||||
panic("add UsersUserProfilePhotoApi tests")
|
||||
}
|
||||
func TestUsersUserProfilePhotoApi(t *testing.T) {
|
||||
var (
|
||||
usersUserProfilePhotoProvider = mocks.NewUsersUserProfilePhotoProvider(t)
|
||||
dummyDataProvider = func(w http.ResponseWriter, r *http.Request) (string, bool) {
|
||||
return "123", true
|
||||
}
|
||||
)
|
||||
|
||||
func TestNewUsersUserProfilePhotoService(t *testing.T) {
|
||||
panic("add UsersUserProfilePhotoService tests")
|
||||
api, err := svc.NewUsersUserProfilePhotoApi(usersUserProfilePhotoProvider, log.NopLogger())
|
||||
assert.NoError(t, err)
|
||||
|
||||
t.Run("GetProfilePhoto", func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodGet, "/", nil)
|
||||
ep := api.GetProfilePhoto(dummyDataProvider)
|
||||
|
||||
t.Run("fails if photo provider errors", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
usersUserProfilePhotoProvider.EXPECT().GetPhoto(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) ([]byte, error) {
|
||||
return nil, errors.New("any")
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
})
|
||||
|
||||
t.Run("successfully returns the requested photo", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
usersUserProfilePhotoProvider.EXPECT().GetPhoto(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) ([]byte, error) {
|
||||
return []byte("photo"), nil
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
assert.Equal(t, "photo", w.Body.String())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("DeleteProfilePhoto", func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodDelete, "/", nil)
|
||||
ep := api.DeleteProfilePhoto(dummyDataProvider)
|
||||
|
||||
t.Run("fails if photo provider errors", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
usersUserProfilePhotoProvider.EXPECT().DeletePhoto(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) error {
|
||||
return errors.New("any")
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
})
|
||||
|
||||
t.Run("successfully deletes the requested photo", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
usersUserProfilePhotoProvider.EXPECT().DeletePhoto(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string) error {
|
||||
return nil
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("UpsertProfilePhoto", func(t *testing.T) {
|
||||
r := httptest.NewRequest(http.MethodPut, "/", strings.NewReader("body"))
|
||||
ep := api.UpsertProfilePhoto(dummyDataProvider)
|
||||
|
||||
t.Run("fails if photo provider errors", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
usersUserProfilePhotoProvider.EXPECT().UpdatePhoto(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string, r io.Reader) error {
|
||||
return errors.New("any")
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusInternalServerError, w.Code)
|
||||
})
|
||||
|
||||
t.Run("successfully upserts the photo", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
usersUserProfilePhotoProvider.EXPECT().UpdatePhoto(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, s string, r io.Reader) error {
|
||||
return nil
|
||||
}).Once()
|
||||
|
||||
ep.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
42
services/graph/pkg/service/v0/data.go
Normal file
42
services/graph/pkg/service/v0/data.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/services/graph/pkg/errorcode"
|
||||
)
|
||||
|
||||
// HTTPDataHandler returns data from the request, it should exit early and return false in the case of any error
|
||||
type HTTPDataHandler[T any] func(w http.ResponseWriter, r *http.Request) (T, bool)
|
||||
|
||||
var (
|
||||
// ErrNoUser is returned when no user is found
|
||||
ErrNoUser = errors.New("no user found")
|
||||
)
|
||||
|
||||
// GetUserIDFromCTX extracts the user from the request
|
||||
func GetUserIDFromCTX(w http.ResponseWriter, r *http.Request) (string, bool) {
|
||||
u, ok := revactx.ContextGetUser(r.Context())
|
||||
if !ok {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusMethodNotAllowed, ErrNoUser.Error())
|
||||
}
|
||||
|
||||
return u.GetId().GetOpaqueId(), ok
|
||||
}
|
||||
|
||||
func GetSlugValue(key string) HTTPDataHandler[string] {
|
||||
return func(w http.ResponseWriter, r *http.Request) (string, bool) {
|
||||
v, err := url.PathUnescape(chi.URLParam(r, key))
|
||||
if err != nil {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, fmt.Sprintf(`failed to get slug: "%s"`, key))
|
||||
}
|
||||
|
||||
return v, err == nil
|
||||
}
|
||||
}
|
||||
@@ -144,14 +144,57 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
identity.IdentityCacheWithGroupsTTL(time.Duration(options.Config.Spaces.GroupsCacheTTL)),
|
||||
)
|
||||
|
||||
storage, err := metadata.NewCS3Storage(
|
||||
options.Config.Metadata.GatewayAddress,
|
||||
options.Config.Metadata.StorageAddress,
|
||||
options.Config.Metadata.SystemUserID,
|
||||
options.Config.Metadata.SystemUserIDP,
|
||||
options.Config.Metadata.SystemUserAPIKey,
|
||||
)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
baseGraphService := BaseGraphService{
|
||||
logger: &options.Logger,
|
||||
identityCache: identityCache,
|
||||
gatewaySelector: options.GatewaySelector,
|
||||
config: options.Config,
|
||||
availableRoles: unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(options.Config.UnifiedRoles.AvailableRoles...)),
|
||||
}
|
||||
|
||||
drivesDriveItemService, err := NewDrivesDriveItemService(options.Logger, options.GatewaySelector)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
drivesDriveItemApi, err := NewDrivesDriveItemApi(drivesDriveItemService, baseGraphService, options.Logger)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
driveItemPermissionsService, err := NewDriveItemPermissionsService(options.Logger, options.GatewaySelector, identityCache, options.Config)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
driveItemPermissionsApi, err := NewDriveItemPermissionsApi(driveItemPermissionsService, options.Logger, options.Config)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
usersUserProfilePhotoService, err := NewUsersUserProfilePhotoService(storage)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
usersUserProfilePhotoApi, err := NewUsersUserProfilePhotoApi(usersUserProfilePhotoService, options.Logger)
|
||||
if err != nil {
|
||||
return Graph{}, err
|
||||
}
|
||||
|
||||
svc := Graph{
|
||||
BaseGraphService: BaseGraphService{
|
||||
logger: &options.Logger,
|
||||
identityCache: identityCache,
|
||||
gatewaySelector: options.GatewaySelector,
|
||||
config: options.Config,
|
||||
availableRoles: unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(options.Config.UnifiedRoles.AvailableRoles...)),
|
||||
},
|
||||
BaseGraphService: baseGraphService,
|
||||
mux: m,
|
||||
specialDriveItemsCache: spacePropertiesCache,
|
||||
eventsPublisher: options.EventsPublisher,
|
||||
@@ -206,47 +249,6 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
requireAdmin = options.RequireAdminMiddleware
|
||||
}
|
||||
|
||||
drivesDriveItemService, err := NewDrivesDriveItemService(options.Logger, options.GatewaySelector)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
drivesDriveItemApi, err := NewDrivesDriveItemApi(drivesDriveItemService, svc.BaseGraphService, options.Logger)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
driveItemPermissionsService, err := NewDriveItemPermissionsService(options.Logger, options.GatewaySelector, identityCache, options.Config)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
driveItemPermissionsApi, err := NewDriveItemPermissionsApi(driveItemPermissionsService, options.Logger, options.Config)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
storage, err := metadata.NewCS3Storage(
|
||||
options.Config.Metadata.GatewayAddress,
|
||||
options.Config.Metadata.StorageAddress,
|
||||
options.Config.Metadata.SystemUserID,
|
||||
options.Config.Metadata.SystemUserIDP,
|
||||
options.Config.Metadata.SystemUserAPIKey,
|
||||
)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
usersUserProfilePhotoService, err := NewUsersUserProfilePhotoService(storage)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
usersUserProfilePhotoApi, err := NewUsersUserProfilePhotoApi(usersUserProfilePhotoService, options.Logger)
|
||||
if err != nil {
|
||||
return svc, err
|
||||
}
|
||||
|
||||
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
|
||||
r.Use(middleware.StripSlashes)
|
||||
|
||||
@@ -315,11 +317,11 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
})
|
||||
r.Get("/drives", svc.GetDrives(APIVersion_1))
|
||||
r.Post("/changePassword", svc.ChangeOwnPassword)
|
||||
r.Route("/photo", func(r chi.Router) {
|
||||
r.Get("/", usersUserProfilePhotoApi.GetProfilePhoto)
|
||||
r.Put("/", usersUserProfilePhotoApi.UpsertProfilePhoto)
|
||||
r.Patch("/", usersUserProfilePhotoApi.UpsertProfilePhoto)
|
||||
r.Delete("/", usersUserProfilePhotoApi.DeleteProfilePhoto)
|
||||
r.Route("/photo/$value", func(r chi.Router) {
|
||||
r.Get("/", usersUserProfilePhotoApi.GetProfilePhoto(GetUserIDFromCTX))
|
||||
r.Put("/", usersUserProfilePhotoApi.UpsertProfilePhoto(GetUserIDFromCTX))
|
||||
r.Patch("/", usersUserProfilePhotoApi.UpsertProfilePhoto(GetUserIDFromCTX))
|
||||
r.Delete("/", usersUserProfilePhotoApi.DeleteProfilePhoto(GetUserIDFromCTX))
|
||||
})
|
||||
})
|
||||
r.Route("/users", func(r chi.Router) {
|
||||
@@ -329,6 +331,9 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
|
||||
r.Get("/", svc.GetUser)
|
||||
r.Get("/drive", svc.GetUserDrive)
|
||||
r.Post("/exportPersonalData", svc.ExportPersonalData)
|
||||
r.Route("/photo/$value", func(r chi.Router) {
|
||||
r.Get("/", usersUserProfilePhotoApi.GetProfilePhoto(GetSlugValue("userID")))
|
||||
})
|
||||
r.With(requireAdmin).Delete("/", svc.DeleteUser)
|
||||
r.With(requireAdmin).Patch("/", svc.PatchUser)
|
||||
if svc.roleService != nil {
|
||||
|
||||
Reference in New Issue
Block a user