mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-01 18:01:28 -06:00
initial /me/drives implementation
Signed-off-by: Jörn Friedrich Dreyer <jfd@butonic.de>
This commit is contained in:
@@ -63,18 +63,23 @@ type Reva struct {
|
||||
Address string
|
||||
}
|
||||
|
||||
type Spaces struct {
|
||||
WebDavBase string
|
||||
}
|
||||
|
||||
// Config combines all available configuration parts.
|
||||
type Config struct {
|
||||
File string
|
||||
WebdavNamespace string
|
||||
Log Log
|
||||
Debug Debug
|
||||
HTTP HTTP
|
||||
Server Server
|
||||
Tracing Tracing
|
||||
Ldap Ldap
|
||||
OpenIDConnect OpenIDConnect
|
||||
Reva Reva
|
||||
File string
|
||||
WebdavNamespace string
|
||||
Log Log
|
||||
Debug Debug
|
||||
HTTP HTTP
|
||||
Server Server
|
||||
Tracing Tracing
|
||||
Ldap Ldap
|
||||
OpenIDConnect OpenIDConnect
|
||||
Reva Reva
|
||||
Spaces Spaces
|
||||
|
||||
Context context.Context
|
||||
Supervised bool
|
||||
|
||||
@@ -140,6 +140,15 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
|
||||
EnvVars: []string{"GRAPH_HTTP_NAMESPACE"},
|
||||
Destination: &cfg.HTTP.Namespace,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "spaces-webdav-base",
|
||||
Value: flags.OverrideDefaultString(cfg.Spaces.WebDavBase, "https://localhost:9200/dav/spaces/"),
|
||||
Usage: "spaces webdav base URL",
|
||||
EnvVars: []string{"GRAPH_SPACES_WEBDAV_BASE"},
|
||||
Destination: &cfg.Spaces.WebDavBase,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "ldap-network",
|
||||
Value: flags.OverrideDefaultString(cfg.Ldap.Network, "tcp"),
|
||||
@@ -182,6 +191,7 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
|
||||
EnvVars: []string{"GRAPH_LDAP_BASEDN_GROUPS"},
|
||||
Destination: &cfg.Ldap.BaseDNGroups,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "oidc-endpoint",
|
||||
Value: flags.OverrideDefaultString(cfg.OpenIDConnect.Endpoint, "https://localhost:9200"),
|
||||
@@ -202,6 +212,7 @@ func ServerWithConfig(cfg *config.Config) []cli.Flag {
|
||||
EnvVars: []string{"GRAPH_OIDC_REALM"},
|
||||
Destination: &cfg.OpenIDConnect.Realm,
|
||||
},
|
||||
|
||||
&cli.StringFlag{
|
||||
Name: "reva-gateway-addr",
|
||||
Value: flags.OverrideDefaultString(cfg.Reva.Address, "127.0.0.1:9142"),
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/render"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
types "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
|
||||
"github.com/cs3org/reva/pkg/token"
|
||||
msgraph "github.com/yaegashi/msgraph.go/v1.0"
|
||||
)
|
||||
@@ -33,6 +35,71 @@ func getToken(r *http.Request) string {
|
||||
return tokens[0]
|
||||
}
|
||||
|
||||
// GetDrives implements the Service interface.
|
||||
func (g Graph) GetDrives(w http.ResponseWriter, r *http.Request) {
|
||||
g.logger.Info().Msgf("Calling GetDrives")
|
||||
accessToken := getToken(r)
|
||||
if accessToken == "" {
|
||||
g.logger.Error().Msg("no access token provided in request")
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
ctx := r.Context()
|
||||
|
||||
client, err := g.GetClient()
|
||||
if err != nil {
|
||||
g.logger.Err(err).Msg("error getting grpc client")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
t := r.Header.Get("x-access-token")
|
||||
ctx = token.ContextSetToken(ctx, t)
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, "x-access-token", t)
|
||||
|
||||
req := &storageprovider.ListStorageSpacesRequest{
|
||||
|
||||
Filters: []*storageprovider.ListStorageSpacesRequest_Filter{
|
||||
{
|
||||
Type: storageprovider.ListStorageSpacesRequest_Filter_TYPE_ID,
|
||||
Term: &storageprovider.ListStorageSpacesRequest_Filter_Id{
|
||||
Id: &storageprovider.StorageSpaceId{
|
||||
OpaqueId: "1284d238-aa92-42ce-bdc4-0b0000009157", // FIXME dynamically discover home and other storages ... actually the storage registry should provide the list of storage spaces
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
res, err := client.ListStorageSpaces(ctx, req)
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("error sending list storage spaces grpc request")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if res.Status.Code != cs3rpc.Code_CODE_OK {
|
||||
g.logger.Error().Err(err).Msg("error calling grpc list storage spaces")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
wdu, err := url.Parse(g.config.Spaces.WebDavBase)
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msgf("error parsing url", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
files, err := formatDrives(wdu, res.StorageSpaces)
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msgf("error encoding response as json %s", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(w, r, &listResponse{Value: files})
|
||||
}
|
||||
|
||||
// GetRootDriveChildren implements the Service interface.
|
||||
func (g Graph) GetRootDriveChildren(w http.ResponseWriter, r *http.Request) {
|
||||
g.logger.Info().Msgf("Calling GetRootDriveChildren")
|
||||
@@ -53,15 +120,9 @@ func (g Graph) GetRootDriveChildren(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// get reva token
|
||||
authReq := &gateway.AuthenticateRequest{
|
||||
Type: "bearer",
|
||||
ClientSecret: accessToken,
|
||||
}
|
||||
|
||||
authRes, _ := client.Authenticate(ctx, authReq);
|
||||
ctx = token.ContextSetToken(ctx, authRes.Token)
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, "x-access-token", authRes.Token)
|
||||
t := r.Header.Get("x-access-token")
|
||||
ctx = token.ContextSetToken(ctx, t)
|
||||
ctx = metadata.AppendToOutgoingContext(ctx, "x-access-token", t)
|
||||
|
||||
g.logger.Info().Msgf("provides access token %v", ctx)
|
||||
|
||||
@@ -95,13 +156,14 @@ func (g Graph) GetRootDriveChildren(w http.ResponseWriter, r *http.Request) {
|
||||
render.JSON(w, r, &listResponse{Value: files})
|
||||
}
|
||||
|
||||
func cs3TimestampToTime(t *types.Timestamp) time.Time {
|
||||
return time.Unix(int64(t.Seconds), int64(t.Nanos))
|
||||
}
|
||||
|
||||
func cs3ResourceToDriveItem(res *storageprovider.ResourceInfo) (*msgraph.DriveItem, error) {
|
||||
size := new(int)
|
||||
*size = int(res.Size) // uint64 -> int :boom:
|
||||
name := strings.TrimPrefix(res.Path, "/home/")
|
||||
lastModified := new(time.Time)
|
||||
*lastModified = time.Unix(int64(res.Mtime.Seconds), int64(res.Mtime.Nanos))
|
||||
|
||||
driveItem := &msgraph.DriveItem{
|
||||
BaseItem: msgraph.BaseItem{
|
||||
@@ -110,19 +172,21 @@ func cs3ResourceToDriveItem(res *storageprovider.ResourceInfo) (*msgraph.DriveIt
|
||||
ID: &res.Id.OpaqueId,
|
||||
},
|
||||
Name: &name,
|
||||
LastModifiedDateTime: lastModified,
|
||||
ETag: &res.Etag,
|
||||
},
|
||||
Size: size,
|
||||
}
|
||||
if res.Mtime != nil {
|
||||
lastModified := cs3TimestampToTime(res.Mtime)
|
||||
driveItem.BaseItem.LastModifiedDateTime = &lastModified
|
||||
}
|
||||
if res.Type == storageprovider.ResourceType_RESOURCE_TYPE_FILE {
|
||||
driveItem.File = &msgraph.File{
|
||||
MimeType: &res.MimeType,
|
||||
}
|
||||
}
|
||||
if res.Type == storageprovider.ResourceType_RESOURCE_TYPE_CONTAINER {
|
||||
driveItem.Folder = &msgraph.Folder{
|
||||
}
|
||||
driveItem.Folder = &msgraph.Folder{}
|
||||
}
|
||||
return driveItem, nil
|
||||
}
|
||||
@@ -139,3 +203,73 @@ func formatDriveItems(mds []*storageprovider.ResourceInfo) ([]*msgraph.DriveItem
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
func cs3StorageSpaceToDrive(baseUrl *url.URL, space *storageprovider.StorageSpace) (*msgraph.Drive, error) {
|
||||
rootId := space.Root.StorageId + "!" + space.Root.OpaqueId
|
||||
drive := &msgraph.Drive{
|
||||
BaseItem: msgraph.BaseItem{
|
||||
Entity: msgraph.Entity{
|
||||
ID: &space.Id.OpaqueId,
|
||||
},
|
||||
Name: &space.Name,
|
||||
//"createdDateTime": "string (timestamp)", // TODO read from StorageSpace ... needs Opaque for now
|
||||
//"description": "string", // TODO read from StorageSpace ... needs Opaque for now
|
||||
},
|
||||
Owner: &msgraph.IdentitySet{
|
||||
User: &msgraph.Identity{
|
||||
ID: &space.Owner.Id.OpaqueId,
|
||||
// DisplayName: , TODO read and cache from users provider
|
||||
},
|
||||
},
|
||||
|
||||
DriveType: &space.SpaceType,
|
||||
Root: &msgraph.DriveItem{
|
||||
BaseItem: msgraph.BaseItem{
|
||||
Entity: msgraph.Entity{
|
||||
ID: &rootId,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if baseUrl != nil {
|
||||
// TODO read from StorageSpace ... needs Opaque for now
|
||||
// TODO how do we build the url?
|
||||
// for now: read from request
|
||||
webDavURL := baseUrl.String() + rootId
|
||||
drive.Root.WebDavURL = &webDavURL
|
||||
}
|
||||
|
||||
if space.Mtime != nil {
|
||||
lastModified := cs3TimestampToTime(space.Mtime)
|
||||
drive.BaseItem.LastModifiedDateTime = &lastModified
|
||||
}
|
||||
if space.Quota != nil {
|
||||
// FIXME use https://github.com/owncloud/open-graph-api and return proper int64
|
||||
var t int
|
||||
if space.Quota.QuotaMaxBytes > math.MaxInt32 {
|
||||
t = math.MaxInt32
|
||||
} else {
|
||||
t = int(space.Quota.QuotaMaxBytes)
|
||||
}
|
||||
drive.Quota = &msgraph.Quota{
|
||||
Total: &t,
|
||||
}
|
||||
}
|
||||
// FIXME use coowner from https://github.com/owncloud/open-graph-api
|
||||
|
||||
return drive, nil
|
||||
}
|
||||
|
||||
func formatDrives(baseUrl *url.URL, mds []*storageprovider.StorageSpace) ([]*msgraph.Drive, error) {
|
||||
responses := make([]*msgraph.Drive, 0, len(mds))
|
||||
for i := range mds {
|
||||
res, err := cs3StorageSpaceToDrive(baseUrl, mds[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
responses = append(responses, res)
|
||||
}
|
||||
|
||||
return responses, nil
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ func NewService(opts ...Option) Service {
|
||||
r.Route("/v1.0", func(r chi.Router) {
|
||||
r.Route("/me", func(r chi.Router) {
|
||||
r.Get("/", svc.GetMe)
|
||||
r.Get("/drives", svc.GetDrives)
|
||||
r.Get("/drive/root/children", svc.GetRootDriveChildren)
|
||||
})
|
||||
r.Route("/users", func(r chi.Router) {
|
||||
|
||||
Reference in New Issue
Block a user