Initial QSfera import
This commit is contained in:
@@ -0,0 +1,357 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
libregraph "github.com/opencloud-eu/libre-graph-api-go"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
|
||||
"github.com/qsfera/server/pkg/l10n"
|
||||
)
|
||||
|
||||
// Translations
|
||||
var (
|
||||
MessageResourceCreated = l10n.Template("{user} added {resource} to {folder}")
|
||||
MessageResourceUpdated = l10n.Template("{user} updated {resource} in {folder}")
|
||||
MessageResourceDownloaded = l10n.Template("{resource} was downloaded via public link {token}")
|
||||
MessageResourceTrashed = l10n.Template("{user} deleted {resource} from {folder}")
|
||||
MessageResourceMoved = l10n.Template("{user} moved {resource} to {folder}")
|
||||
MessageResourceRenamed = l10n.Template("{user} renamed {oldResource} to {resource}")
|
||||
MessageShareCreated = l10n.Template("{user} shared {resource} with {sharee}")
|
||||
MessageShareUpdated = l10n.Template("{user} updated {field} for the {resource}")
|
||||
MessageShareDeleted = l10n.Template("{user} removed {sharee} from {resource}")
|
||||
MessageLinkCreated = l10n.Template("{user} shared {resource} via link")
|
||||
MessageLinkUpdated = l10n.Template("{user} updated {field} for a link {token} on {resource}")
|
||||
MessageLinkDeleted = l10n.Template("{user} removed link to {resource}")
|
||||
MessageSpaceShared = l10n.Template("{user} added {sharee} as member of {space}")
|
||||
MessageSpaceUnshared = l10n.Template("{user} removed {sharee} from {space}")
|
||||
|
||||
StrSomeField = l10n.Template("some field")
|
||||
StrPermission = l10n.Template("permission")
|
||||
StrPassword = l10n.Template("password")
|
||||
StrExpirationDate = l10n.Template("expiration date")
|
||||
StrDisplayName = l10n.Template("display name")
|
||||
StrDescription = l10n.Template("description")
|
||||
)
|
||||
|
||||
// GetActivitiesResponse is the response on GET activities requests
|
||||
type GetActivitiesResponse struct {
|
||||
Activities []libregraph.Activity `json:"value"`
|
||||
}
|
||||
|
||||
// Resource represents an item such as a file or folder
|
||||
type Resource struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// Actor represents a user
|
||||
type Actor struct {
|
||||
ID string `json:"id"`
|
||||
DisplayName string `json:"displayName"`
|
||||
}
|
||||
|
||||
// Sharee represents a share reciever (group or user)
|
||||
type Sharee struct {
|
||||
ID string `json:"id"`
|
||||
DisplayName string `json:"displayName"`
|
||||
ShareType string `json:"shareType"`
|
||||
}
|
||||
|
||||
// ActivityOption allows setting variables for an activity
|
||||
type ActivityOption func(context.Context, gateway.GatewayAPIClient, map[string]any) error
|
||||
|
||||
// WithResource sets the resource variable for an activity
|
||||
func WithResource(ref *provider.Reference, addSpace bool, explicitResourceName string) ActivityOption {
|
||||
return func(ctx context.Context, gwc gateway.GatewayAPIClient, vars map[string]any) error {
|
||||
info, err := utils.GetResource(ctx, ref, gwc)
|
||||
if err != nil {
|
||||
if explicitResourceName == "" {
|
||||
explicitResourceName = filepath.Base(ref.GetPath())
|
||||
}
|
||||
vars["resource"] = Resource{
|
||||
Name: explicitResourceName,
|
||||
}
|
||||
n := getFolderName(ctx, gwc, ref)
|
||||
vars["folder"] = Resource{
|
||||
Name: n,
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if explicitResourceName == "" {
|
||||
explicitResourceName = info.GetName()
|
||||
}
|
||||
vars["resource"] = Resource{
|
||||
ID: storagespace.FormatResourceID(info.GetId()),
|
||||
Name: explicitResourceName,
|
||||
}
|
||||
|
||||
if addSpace {
|
||||
vars["space"] = Resource{
|
||||
ID: info.GetSpace().GetId().GetOpaqueId(),
|
||||
Name: info.GetSpace().GetName(),
|
||||
}
|
||||
}
|
||||
|
||||
parent, err := utils.GetResourceByID(ctx, info.GetParentId(), gwc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vars["folder"] = Resource{
|
||||
ID: info.GetParentId().GetOpaqueId(),
|
||||
Name: parent.GetName(),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithOldResource sets the oldResource variable for an activity
|
||||
func WithOldResource(ref *provider.Reference) ActivityOption {
|
||||
return func(_ context.Context, _ gateway.GatewayAPIClient, vars map[string]any) error {
|
||||
name := filepath.Base(ref.GetPath())
|
||||
vars["oldResource"] = Resource{
|
||||
Name: name,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithTrashedResource sets the resource variable if the resource is trashed
|
||||
func WithTrashedResource(ref *provider.Reference, rid *provider.ResourceId) ActivityOption {
|
||||
return func(ctx context.Context, gwc gateway.GatewayAPIClient, vars map[string]any) error {
|
||||
vars["resource"] = Resource{
|
||||
Name: filepath.Base(ref.GetPath()),
|
||||
}
|
||||
n := getFolderName(ctx, gwc, ref)
|
||||
vars["folder"] = Resource{
|
||||
Name: n,
|
||||
}
|
||||
|
||||
resp, err := gwc.ListRecycle(ctx, &provider.ListRecycleRequest{
|
||||
Ref: ref,
|
||||
Key: rid.GetOpaqueId(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.GetStatus().GetCode() != rpc.Code_CODE_OK {
|
||||
return fmt.Errorf("error listing recycle: %s", resp.GetStatus().GetMessage())
|
||||
}
|
||||
|
||||
for _, item := range resp.GetRecycleItems() {
|
||||
if item.GetKey() == rid.GetOpaqueId() {
|
||||
|
||||
vars["resource"] = Resource{
|
||||
ID: storagespace.FormatResourceID(rid),
|
||||
Name: filepath.Base(item.GetRef().GetPath()),
|
||||
}
|
||||
in := filepath.Base(filepath.Dir(item.GetRef().GetPath()))
|
||||
if in != "." && in != "/" {
|
||||
vars["folder"] = Resource{
|
||||
Name: in,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithUser sets the user variable for an Activity
|
||||
func WithUser(uid *user.UserId, u *user.User, impersonator *user.User) ActivityOption {
|
||||
return func(ctx context.Context, gwc gateway.GatewayAPIClient, vars map[string]any) error {
|
||||
var target *user.User
|
||||
switch {
|
||||
case impersonator != nil:
|
||||
target = impersonator
|
||||
case u != nil:
|
||||
target = u
|
||||
case uid != nil:
|
||||
us, err := utils.GetUserNoGroups(ctx, uid, gwc)
|
||||
target = us
|
||||
|
||||
if err != nil {
|
||||
target = &user.User{
|
||||
Id: uid,
|
||||
DisplayName: "DeletedUser",
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("no user provided")
|
||||
}
|
||||
|
||||
vars["user"] = Actor{
|
||||
ID: target.GetId().GetOpaqueId(),
|
||||
DisplayName: target.GetDisplayName(),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithSharee sets the sharee variable for an activity
|
||||
func WithSharee(uid *user.UserId, gid *group.GroupId) ActivityOption {
|
||||
return func(ctx context.Context, gwc gateway.GatewayAPIClient, vars map[string]any) error {
|
||||
switch {
|
||||
case uid != nil:
|
||||
u, err := utils.GetUserNoGroups(ctx, uid, gwc)
|
||||
if err != nil {
|
||||
vars["sharee"] = Sharee{
|
||||
DisplayName: "DeletedUser",
|
||||
ShareType: "user",
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
vars["sharee"] = Sharee{
|
||||
ID: uid.GetOpaqueId(),
|
||||
DisplayName: u.GetUsername(),
|
||||
ShareType: "user",
|
||||
}
|
||||
case gid != nil:
|
||||
vars["sharee"] = Sharee{
|
||||
ID: gid.GetOpaqueId(),
|
||||
DisplayName: "DeletedGroup",
|
||||
ShareType: "group",
|
||||
}
|
||||
r, err := gwc.GetGroup(ctx, &group.GetGroupRequest{GroupId: gid})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting group: %w", err)
|
||||
}
|
||||
|
||||
if r.GetStatus().GetCode() != rpc.Code_CODE_OK {
|
||||
return fmt.Errorf("error getting group: %s", r.GetStatus().GetMessage())
|
||||
}
|
||||
|
||||
vars["sharee"] = Sharee{
|
||||
ID: gid.GetOpaqueId(),
|
||||
DisplayName: r.GetGroup().GetDisplayName(),
|
||||
ShareType: "group",
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithSpace sets the space variable for an activity
|
||||
func WithSpace(spaceid *provider.StorageSpaceId) ActivityOption {
|
||||
return func(ctx context.Context, gwc gateway.GatewayAPIClient, vars map[string]any) error {
|
||||
s, err := utils.GetSpace(ctx, spaceid.GetOpaqueId(), gwc)
|
||||
if err != nil {
|
||||
vars["space"] = Resource{
|
||||
ID: spaceid.GetOpaqueId(),
|
||||
Name: "DeletedSpace",
|
||||
}
|
||||
return err
|
||||
}
|
||||
vars["space"] = Resource{
|
||||
ID: s.GetId().GetOpaqueId(),
|
||||
Name: s.GetName(),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithTranslation sets a variable that translation is needed for
|
||||
func WithTranslation(t *l10n.Translator, locale string, key string, values []string) ActivityOption {
|
||||
return func(_ context.Context, _ gateway.GatewayAPIClient, vars map[string]any) error {
|
||||
f := t.Translate(StrSomeField, locale)
|
||||
if len(values) > 0 {
|
||||
for i := range values {
|
||||
values[i] = t.Translate(mapField(values[i]), locale)
|
||||
}
|
||||
f = strings.Join(values, ", ")
|
||||
}
|
||||
vars[key] = Resource{
|
||||
Name: f,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithVar sets a variable for an activity
|
||||
func WithVar(key, id, name string) ActivityOption {
|
||||
return func(_ context.Context, _ gateway.GatewayAPIClient, vars map[string]any) error {
|
||||
vars[key] = Resource{
|
||||
ID: id,
|
||||
Name: name,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewActivity creates a new activity
|
||||
func NewActivity(message string, ts time.Time, eventID string, vars map[string]any) libregraph.Activity {
|
||||
return libregraph.Activity{
|
||||
Id: eventID,
|
||||
Times: libregraph.ActivityTimes{RecordedTime: ts},
|
||||
Template: libregraph.ActivityTemplate{
|
||||
Message: message,
|
||||
Variables: vars,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetVars calls other service to gather the required data for the activity variables
|
||||
func (s *ActivitylogService) GetVars(ctx context.Context, opts ...ActivityOption) (map[string]any, error) {
|
||||
gwc, err := s.gws.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vars := make(map[string]any)
|
||||
for _, opt := range opts {
|
||||
if err := opt(ctx, gwc, vars); err != nil {
|
||||
s.log.Info().Err(err).Msg("error getting activity vars")
|
||||
}
|
||||
}
|
||||
|
||||
return vars, nil
|
||||
}
|
||||
|
||||
func getFolderName(ctx context.Context, gwc gateway.GatewayAPIClient, ref *provider.Reference) string {
|
||||
n := filepath.Base(filepath.Dir(ref.GetPath()))
|
||||
if n == "." || n == "/" {
|
||||
s, err := utils.GetSpace(ctx, toSpace(ref).GetOpaqueId(), gwc)
|
||||
if err == nil {
|
||||
n = s.GetName()
|
||||
} else {
|
||||
n = "root"
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func mapField(val string) string {
|
||||
switch val {
|
||||
case "TYPE_PERMISSIONS", "permission", "permissions":
|
||||
return StrPermission
|
||||
case "TYPE_PASSWORD", "password":
|
||||
return StrPassword
|
||||
case "TYPE_EXPIRATION", "expiration":
|
||||
return StrExpirationDate
|
||||
case "TYPE_DISPLAYNAME":
|
||||
return StrDisplayName
|
||||
case "TYPE_DESCRIPTION":
|
||||
return StrDescription
|
||||
}
|
||||
return StrSomeField
|
||||
}
|
||||
Reference in New Issue
Block a user