mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-06-13 10:34:43 -04:00
enhancement: make collaboration mention functionality public
This commit is contained in:
committed by
Benedikt Kulmann
parent
159785a3b5
commit
f1208cfa32
@@ -3215,6 +3215,7 @@ def wopiCollaborationService(name):
|
||||
"COLLABORATION_CS3API_DATAGATEWAY_INSECURE": True,
|
||||
"OC_JWT_SECRET": "some-opencloud-jwt-secret",
|
||||
"COLLABORATION_WOPI_SECRET": "some-wopi-secret",
|
||||
"COLLABORATION_EVENTS_ENDPOINT": "%s:9233" % OC_SERVER_NAME,
|
||||
}
|
||||
|
||||
if name == "collabora":
|
||||
|
||||
22
pkg/events/events.go
Normal file
22
pkg/events/events.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
)
|
||||
|
||||
type ResourceMention struct {
|
||||
Executant *user.UserId
|
||||
UserIDs []*user.UserId
|
||||
Ref *provider.Reference
|
||||
Timestamp time.Time
|
||||
}
|
||||
|
||||
func (ResourceMention) Unmarshal(v []byte) (interface{}, error) {
|
||||
e := ResourceMention{}
|
||||
err := json.Unmarshal(v, &e)
|
||||
return e, err
|
||||
}
|
||||
@@ -14,7 +14,8 @@ import (
|
||||
type Permission string
|
||||
|
||||
const (
|
||||
PermissionCollaborationManageFonts Permission = "Collaboration.Fonts.Manage"
|
||||
PermissionCollaborationManageFonts Permission = "Collaboration.Fonts.Manage"
|
||||
PermissionCollaborationPublishNotification Permission = "Collaboration.Notification.Publish"
|
||||
)
|
||||
|
||||
func CheckPermissions(gatewayClient gateway.GatewayAPIClient, ctx context.Context, permission Permission) (*userpb.User, bool, error) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events/stream"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||
"github.com/spf13/afero"
|
||||
@@ -17,6 +18,7 @@ import (
|
||||
microstore "go-micro.dev/v4/store"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
||||
"github.com/opencloud-eu/opencloud/pkg/generators"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
"github.com/opencloud-eu/opencloud/pkg/runner"
|
||||
@@ -27,6 +29,7 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/connector"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/font"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/helpers"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/notification"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/server/debug"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/server/grpc"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/server/http"
|
||||
@@ -171,6 +174,24 @@ func Server(cfg *config.Config) *cobra.Command {
|
||||
fontService = service
|
||||
}
|
||||
|
||||
var notificationService notification.Service
|
||||
{
|
||||
connName := generators.GenerateConnectionName(cfg.Service.Name, generators.NTypeBus)
|
||||
natsStream, err := stream.NatsFromConfig(connName, true, stream.NatsConfig(cfg.Events))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
service, err := notification.NewService(
|
||||
notification.ServiceOptions{}.
|
||||
WithLogger(logger).
|
||||
WithGatewaySelector(gatewaySelector).
|
||||
WithEventPublisher(natsStream).
|
||||
WithMachineAuthAPIKey(cfg.MachineAuthAPIKey),
|
||||
)
|
||||
|
||||
notificationService = service
|
||||
}
|
||||
|
||||
// start HTTP server
|
||||
httpServer, err := http.Server(
|
||||
http.Adapter(connector.NewHttpAdapter(gatewaySelector, cfg, st, selector.NewSelector(selector.Registry(registry.GetRegistry())))),
|
||||
@@ -180,6 +201,7 @@ func Server(cfg *config.Config) *cobra.Command {
|
||||
http.TracerProvider(traceProvider),
|
||||
http.Store(st),
|
||||
http.FontService(fontService),
|
||||
http.NotificationService(notificationService),
|
||||
)
|
||||
if err != nil {
|
||||
logger.Info().Err(err).Str("transport", "http").Msg("Failed to initialize server")
|
||||
|
||||
@@ -14,6 +14,7 @@ type Config struct {
|
||||
App App `yaml:"app"`
|
||||
Font Font `yaml:"font"`
|
||||
Store Store `yaml:"store"`
|
||||
Events Events `yaml:"events"`
|
||||
|
||||
TokenManager *TokenManager `yaml:"token_manager"`
|
||||
|
||||
@@ -27,4 +28,6 @@ type Config struct {
|
||||
Debug Debug `yaml:"debug"`
|
||||
|
||||
Context context.Context `yaml:"-"`
|
||||
|
||||
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OC_MACHINE_AUTH_API_KEY;COLLABORATION_MACHINE_AUTH_API_KEY" desc:"The machine auth API key used to validate internal requests necessary to access resources from other services." introductionVersion:"%%NEXT%%"`
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ func DefaultConfig() *config.Config {
|
||||
AssetPath: filepath.Join(defaults.BaseDataPath(), "collaboration/fonts"),
|
||||
PreviewText: "OpenCloud",
|
||||
},
|
||||
Events: config.Events{
|
||||
Endpoint: "127.0.0.1:9233",
|
||||
Cluster: "opencloud-cluster",
|
||||
},
|
||||
Store: config.Store{
|
||||
Store: "nats-js-kv",
|
||||
Nodes: []string{"127.0.0.1:9233"},
|
||||
@@ -92,6 +96,10 @@ func EnsureDefaults(cfg *config.Config) {
|
||||
if cfg.CS3Api.GRPCClientTLS == nil && cfg.Commons != nil {
|
||||
cfg.CS3Api.GRPCClientTLS = structs.CopyOrZeroValue(cfg.Commons.GRPCClientTLS)
|
||||
}
|
||||
|
||||
if cfg.MachineAuthAPIKey == "" && cfg.Commons != nil && cfg.Commons.MachineAuthAPIKey != "" {
|
||||
cfg.MachineAuthAPIKey = cfg.Commons.MachineAuthAPIKey
|
||||
}
|
||||
}
|
||||
|
||||
// Sanitize sanitized the configuration
|
||||
|
||||
12
services/collaboration/pkg/config/event.go
Normal file
12
services/collaboration/pkg/config/event.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package config
|
||||
|
||||
// Events combines the configuration options for the event bus.
|
||||
type Events struct {
|
||||
Endpoint string `yaml:"endpoint" env:"OC_EVENTS_ENDPOINT;COLLABORATION_EVENTS_ENDPOINT" desc:"The address of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture." introductionVersion:"%%NEXT%%"`
|
||||
Cluster string `yaml:"cluster" env:"OC_EVENTS_CLUSTER;COLLABORATION_EVENTS_CLUSTER" desc:"The clusterID of the event system. The event system is the message queuing service. It is used as message broker for the microservice architecture. Mandatory when using NATS as event system." introductionVersion:"%%NEXT%%"`
|
||||
TLSInsecure bool `yaml:"tls_insecure" env:"OC_INSECURE;OC_EVENTS_TLS_INSECURE;COLLABORATION_EVENTS_TLS_INSECURE" desc:"Whether to verify the server TLS certificates." introductionVersion:"%%NEXT%%"`
|
||||
TLSRootCACertificate string `yaml:"tls_root_ca_certificate" env:"OC_EVENTS_TLS_ROOT_CA_CERTIFICATE;COLLABORATION_EVENTS_TLS_ROOT_CA_CERTIFICATE" desc:"The root CA certificate used to validate the server's TLS certificate. If provided COLLABORATION_EVENTS_TLS_INSECURE will be seen as false." introductionVersion:"%%NEXT%%"`
|
||||
EnableTLS bool `yaml:"enable_tls" env:"OC_EVENTS_ENABLE_TLS;COLLABORATION_EVENTS_ENABLE_TLS" desc:"Enable TLS for the connection to the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"%%NEXT%%"`
|
||||
AuthUsername string `yaml:"username" env:"OC_EVENTS_AUTH_USERNAME;COLLABORATION_EVENTS_AUTH_USERNAME" desc:"The username to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"%%NEXT%%"`
|
||||
AuthPassword string `yaml:"password" env:"OC_EVENTS_AUTH_PASSWORD;COLLABORATION_EVENTS_AUTH_PASSWORD" desc:"The password to authenticate with the events broker. The events broker is the OpenCloud service which receives and delivers events between the services." introductionVersion:"%%NEXT%%"`
|
||||
}
|
||||
10
services/collaboration/pkg/notification/notification.go
Normal file
10
services/collaboration/pkg/notification/notification.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"github.com/go-playground/validator/v10"
|
||||
)
|
||||
|
||||
var validate = validator.New(
|
||||
validator.WithPrivateFieldValidation(),
|
||||
validator.WithRequiredStructEnabled(),
|
||||
)
|
||||
152
services/collaboration/pkg/notification/service.go
Normal file
152
services/collaboration/pkg/notification/service.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package notification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
|
||||
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
revactx "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"google.golang.org/grpc/metadata"
|
||||
|
||||
ocEvents "github.com/opencloud-eu/opencloud/pkg/events"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/collaboration"
|
||||
)
|
||||
|
||||
type ServiceOptions struct {
|
||||
logger log.Logger `validate:"required"`
|
||||
eventPublisher events.Publisher `validate:"required"`
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient] `validate:"required"`
|
||||
machineAuthAPIKey string `validate:"required,min=1"`
|
||||
}
|
||||
|
||||
func (o ServiceOptions) WithLogger(logger log.Logger) ServiceOptions {
|
||||
o.logger = logger
|
||||
return o
|
||||
}
|
||||
|
||||
func (o ServiceOptions) WithEventPublisher(eventPublisher events.Publisher) ServiceOptions {
|
||||
o.eventPublisher = eventPublisher
|
||||
return o
|
||||
}
|
||||
|
||||
func (o ServiceOptions) WithMachineAuthAPIKey(key string) ServiceOptions {
|
||||
o.machineAuthAPIKey = key
|
||||
return o
|
||||
}
|
||||
|
||||
func (o ServiceOptions) WithGatewaySelector(gws pool.Selectable[gateway.GatewayAPIClient]) ServiceOptions {
|
||||
o.gatewaySelector = gws
|
||||
return o
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
log log.Logger
|
||||
eventPublisher events.Publisher
|
||||
gatewaySelector pool.Selectable[gateway.GatewayAPIClient]
|
||||
machineAuthAPIKey string
|
||||
}
|
||||
|
||||
func NewService(options ServiceOptions) (Service, error) {
|
||||
if err := validate.Struct(options); err != nil {
|
||||
return Service{}, err
|
||||
}
|
||||
|
||||
return Service{
|
||||
log: options.logger,
|
||||
eventPublisher: options.eventPublisher,
|
||||
gatewaySelector: options.gatewaySelector,
|
||||
machineAuthAPIKey: options.machineAuthAPIKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s Service) HandleNotification(w http.ResponseWriter, r *http.Request) {
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
requestUser, canManage, err := collaboration.CheckPermissions(gatewayClient, r.Context(), collaboration.PermissionCollaborationPublishNotification)
|
||||
switch {
|
||||
case err != nil:
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
case !canManage:
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
defer func() { _ = r.Body.Close() }()
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var data = struct {
|
||||
Type string `json:"type" validate:"required"`
|
||||
UserIDs []string `json:"userIDs" validate:"required"`
|
||||
FileID string `json:"fileID" validate:"required"`
|
||||
}{}
|
||||
if err := json.Unmarshal(body, &data); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := validate.Struct(data); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
event := ocEvents.ResourceMention{
|
||||
Executant: requestUser.GetId(),
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
|
||||
for _, userID := range data.UserIDs {
|
||||
authResponse, err := gatewayClient.Authenticate(context.Background(), &gateway.AuthenticateRequest{
|
||||
Type: "machine",
|
||||
ClientId: "userid:" + userID,
|
||||
ClientSecret: s.machineAuthAPIKey,
|
||||
})
|
||||
if err != nil || authResponse.Status.Code != rpcv1beta1.Code_CODE_OK {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
resourceID, err := storagespace.ParseID(data.FileID)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
statResponse, err := gatewayClient.Stat(
|
||||
metadata.AppendToOutgoingContext(context.Background(), revactx.TokenHeader, authResponse.GetToken()),
|
||||
&storageprovider.StatRequest{Ref: &storageprovider.Reference{ResourceId: &resourceID}},
|
||||
)
|
||||
if err != nil || statResponse.Status.Code != rpcv1beta1.Code_CODE_OK {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
event.UserIDs = append(event.UserIDs, authResponse.User.GetId())
|
||||
event.Ref = &storageprovider.Reference{
|
||||
ResourceId: statResponse.GetInfo().GetId(),
|
||||
}
|
||||
}
|
||||
|
||||
if err := events.Publish(r.Context(), s.eventPublisher, event); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/config"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/connector"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/font"
|
||||
"github.com/opencloud-eu/opencloud/services/collaboration/pkg/notification"
|
||||
)
|
||||
|
||||
// Option defines a single option function.
|
||||
@@ -17,13 +18,14 @@ type Option func(o *Options)
|
||||
|
||||
// Options define the available options for this package.
|
||||
type Options struct {
|
||||
Adapter *connector.HttpAdapter
|
||||
Logger log.Logger
|
||||
Context context.Context
|
||||
Config *config.Config
|
||||
TracerProvider trace.TracerProvider
|
||||
Store microstore.Store
|
||||
FontService font.Service
|
||||
Adapter *connector.HttpAdapter
|
||||
Logger log.Logger
|
||||
Context context.Context
|
||||
Config *config.Config
|
||||
TracerProvider trace.TracerProvider
|
||||
Store microstore.Store
|
||||
FontService font.Service
|
||||
NotificationService notification.Service
|
||||
}
|
||||
|
||||
// newOptions initializes the available default options.
|
||||
@@ -85,3 +87,10 @@ func FontService(val font.Service) Option {
|
||||
o.FontService = val
|
||||
}
|
||||
}
|
||||
|
||||
// NotificationService provides a function to set the NotificationService option
|
||||
func NotificationService(val notification.Service) Option {
|
||||
return func(o *Options) {
|
||||
o.NotificationService = val
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ func Server(opts ...Option) (http.Service, error) {
|
||||
// prepareRoutes will prepare all the implemented routes
|
||||
func prepareRoutes(r *chi.Mux, options Options) {
|
||||
fontService := options.FontService
|
||||
notificationService := options.NotificationService
|
||||
adapter := options.Adapter
|
||||
logger := options.Logger
|
||||
// prepare basic logger for the request
|
||||
@@ -214,15 +215,18 @@ func prepareRoutes(r *chi.Mux, options Options) {
|
||||
|
||||
})
|
||||
r.Route("/collaboration", func(r chi.Router) {
|
||||
auth := middleware.ExtractAccountUUID(
|
||||
account.Logger(options.Logger),
|
||||
account.JWTSecret(options.Config.TokenManager.JWTSecret),
|
||||
)
|
||||
r.With(auth).Route("/notify", func(r chi.Router) {
|
||||
r.Post("/", notificationService.HandleNotification)
|
||||
})
|
||||
r.Route("/fonts", func(r chi.Router) {
|
||||
r.Get("/", fontService.ListFonts)
|
||||
r.Get("/{id}", fontService.GetFont)
|
||||
r.Get("/preview/{id}", fontService.PreviewFont)
|
||||
r.Route("/manage", func(r chi.Router) {
|
||||
r.Use(middleware.ExtractAccountUUID(
|
||||
account.Logger(options.Logger),
|
||||
account.JWTSecret(options.Config.TokenManager.JWTSecret),
|
||||
))
|
||||
r.With(auth).Route("/manage", func(r chi.Router) {
|
||||
r.Post("/", fontService.UploadFont)
|
||||
r.Delete("/{id}", fontService.DeleteFont)
|
||||
})
|
||||
|
||||
@@ -6,7 +6,12 @@ import (
|
||||
"os/signal"
|
||||
"reflect"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events/stream"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
||||
ocEvents "github.com/opencloud-eu/opencloud/pkg/events"
|
||||
"github.com/opencloud-eu/opencloud/pkg/generators"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
@@ -19,14 +24,12 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/notifications/pkg/config/parser"
|
||||
"github.com/opencloud-eu/opencloud/services/notifications/pkg/server/debug"
|
||||
"github.com/opencloud-eu/opencloud/services/notifications/pkg/service"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events/stream"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
|
||||
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/store"
|
||||
"github.com/spf13/cobra"
|
||||
microstore "go-micro.dev/v4/store"
|
||||
|
||||
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
|
||||
)
|
||||
|
||||
// Server is the entrypoint for the server command.
|
||||
@@ -86,6 +89,7 @@ func Server(cfg *config.Config) *cobra.Command {
|
||||
events.SpaceMembershipExpired{},
|
||||
events.ScienceMeshInviteTokenGenerated{},
|
||||
events.SendEmailsEvent{},
|
||||
ocEvents.ResourceMention{},
|
||||
}
|
||||
registeredEvents := make(map[string]events.Unmarshaller)
|
||||
for _, e := range evs {
|
||||
|
||||
@@ -3,6 +3,7 @@ package email
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
@@ -150,6 +151,11 @@ func callToActionToHTML(s string) string {
|
||||
if strings.TrimSpace(s) == "" {
|
||||
return ""
|
||||
}
|
||||
s = strings.TrimSuffix(s, "{ShareLink}")
|
||||
return s + `<a href="{ShareLink}">{ShareLink}</a>`
|
||||
|
||||
// substitute links
|
||||
for _, token := range []string{"ShareLink", "ResourceLink"} {
|
||||
s = strings.ReplaceAll(s, "{"+token+"}", fmt.Sprintf(`<a href="{%s}">{%s}</a>`, token, token))
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -118,6 +118,15 @@ Please visit your federation settings and use the following details:
|
||||
Greeting: l10n.Template(`Hi {DisplayName},`),
|
||||
MessageBody: "", // is generated using the GroupedTemplates
|
||||
}
|
||||
|
||||
Mention = MessageTemplate{
|
||||
textTemplate: _textTemplate,
|
||||
htmlTemplate: _htmlTemplate,
|
||||
Subject: l10n.Template(`You were mentioned in '{ResourceName}'`),
|
||||
Greeting: l10n.Template(`Hello {RecipientName},`),
|
||||
MessageBody: l10n.Template(`{AuthorName} mentioned you in "{ResourceName}".`),
|
||||
CallToAction: l10n.Template(`You can view the mention here: {ResourceLink}`),
|
||||
}
|
||||
)
|
||||
|
||||
// holds the information to turn the raw template into a parseable go template
|
||||
@@ -134,6 +143,10 @@ var _placeholders = map[string]string{
|
||||
"{ProviderDomain}": "{{ .ProviderDomain }}",
|
||||
"{Token}": "{{ .Token }}",
|
||||
"{DisplayName}": "{{ .DisplayName }}",
|
||||
"{AuthorName}": "{{ .AuthorName }}",
|
||||
"{RecipientName}": "{{ .RecipientName }}",
|
||||
"{ResourceName}": "{{ .ResourceName }}",
|
||||
"{ResourceLink}": "{{ .ResourceLink }}",
|
||||
}
|
||||
|
||||
// MessageTemplate is the data structure for the email
|
||||
|
||||
99
services/notifications/pkg/service/resource.go
Normal file
99
services/notifications/pkg/service/resource.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
|
||||
ocEvents "github.com/opencloud-eu/opencloud/pkg/events"
|
||||
"github.com/opencloud-eu/opencloud/pkg/l10n"
|
||||
"github.com/opencloud-eu/opencloud/services/notifications/pkg/channels"
|
||||
"github.com/opencloud-eu/opencloud/services/notifications/pkg/email"
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
|
||||
)
|
||||
|
||||
func (s eventsNotifier) handleResourceMention(e ocEvents.ResourceMention, eventId string) {
|
||||
logger := s.logger.With().
|
||||
Str("event", "Mention").
|
||||
Str("resourceid", e.Ref.GetResourceId().GetOpaqueId()).
|
||||
Logger()
|
||||
_ = logger
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctx, err := utils.GetServiceUserContextWithContext(context.Background(), gatewayClient, s.serviceAccountID, s.serviceAccountSecret)
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("could not select next gateway client")
|
||||
return
|
||||
}
|
||||
|
||||
var data = struct {
|
||||
resourceLink string `validate:"required,url"`
|
||||
resourceName string `validate:"required,min=1"`
|
||||
author *user.User `validate:"required"`
|
||||
recipients []*user.User `validate:"required,min=1"`
|
||||
}{}
|
||||
|
||||
// fill the data struct with the info we need to render the email
|
||||
{
|
||||
resourceInfo, err := s.getResourceInfo(ctx, e.Ref.GetResourceId(), nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data.resourceName = resourceInfo.GetName()
|
||||
|
||||
data.resourceLink, err = urlJoinPath(s.openCloudURL, "f", storagespace.FormatResourceID(resourceInfo.GetId()))
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("failed to generate resource link.")
|
||||
return
|
||||
}
|
||||
|
||||
for _, userID := range append([]*user.UserId{e.Executant}, e.UserIDs...) {
|
||||
switch u, err := s.getUser(ctx, userID); {
|
||||
case err != nil:
|
||||
logger.Error().Err(err).Msg("could not get user")
|
||||
return
|
||||
case userID.GetOpaqueId() == e.Executant.GetOpaqueId():
|
||||
data.author = u
|
||||
default:
|
||||
data.recipients = append(data.recipients, u)
|
||||
}
|
||||
}
|
||||
|
||||
recipients := s.filter.execute(ctx, data.recipients, defaults.SettingUUIDProfileEventResourceMention)
|
||||
recipientsInstant, recipientsDaily, recipientsInstantWeekly := s.splitter.execute(ctx, recipients)
|
||||
recipientsInstant = append(recipientsInstant, s.userEventStore.persist(_intervalDaily, eventId, recipientsDaily)...)
|
||||
recipientsInstant = append(recipientsInstant, s.userEventStore.persist(_intervalWeekly, eventId, recipientsInstantWeekly)...)
|
||||
data.recipients = recipientsInstant
|
||||
}
|
||||
|
||||
if err := validate.Struct(data); err != nil {
|
||||
logger.Error().Err(err).Msg("data struct validation failed")
|
||||
return
|
||||
}
|
||||
|
||||
messages := make([]*channels.Message, len(data.recipients))
|
||||
for i, recipient := range data.recipients {
|
||||
locale := l10n.MustGetUserLocale(ctx, recipient.GetId().GetOpaqueId(), "", s.valueService)
|
||||
message, err := email.RenderEmailTemplate(email.Mention, locale, s.defaultLanguage, s.emailTemplatePath, s.translationPath, map[string]string{
|
||||
"AuthorName": data.author.GetDisplayName(),
|
||||
"RecipientName": recipient.GetDisplayName(),
|
||||
"ResourceName": data.resourceName,
|
||||
"ResourceLink": data.resourceLink,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Error().Err(err).Msg("could not render email-template")
|
||||
return
|
||||
}
|
||||
|
||||
message.Sender = data.author.GetDisplayName()
|
||||
message.Recipient = []string{recipient.GetMail()}
|
||||
messages[i] = message
|
||||
}
|
||||
|
||||
s.send(ctx, messages)
|
||||
}
|
||||
@@ -10,9 +10,11 @@ import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
|
||||
"go-micro.dev/v4/store"
|
||||
|
||||
ocEvents "github.com/opencloud-eu/opencloud/pkg/events"
|
||||
ehsvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/eventhistory/v0"
|
||||
|
||||
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"
|
||||
@@ -22,6 +24,9 @@ import (
|
||||
"go-micro.dev/v4/metadata"
|
||||
"google.golang.org/protobuf/types/known/fieldmaskpb"
|
||||
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/l10n"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/middleware"
|
||||
@@ -29,16 +34,13 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/notifications/pkg/channels"
|
||||
"github.com/opencloud-eu/opencloud/services/notifications/pkg/email"
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
)
|
||||
|
||||
// validate is the package level validator instance
|
||||
var validate *validator.Validate
|
||||
|
||||
func init() {
|
||||
validate = validator.New()
|
||||
}
|
||||
var validate = validator.New(
|
||||
validator.WithPrivateFieldValidation(),
|
||||
validator.WithRequiredStructEnabled(),
|
||||
)
|
||||
|
||||
// Service should be named `Runner`
|
||||
type Service interface {
|
||||
@@ -131,6 +133,8 @@ EventLoop:
|
||||
s.handleScienceMeshInviteTokenGenerated(e)
|
||||
case events.SendEmailsEvent:
|
||||
s.sendGroupedEmailsJob(e, evt.ID)
|
||||
case ocEvents.ResourceMention:
|
||||
s.handleResourceMention(e, evt.ID)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -292,7 +292,12 @@ func DefaultPolicies() []config.Policy {
|
||||
SkipXAccessToken: true,
|
||||
},
|
||||
{
|
||||
Endpoint: "/collaboration/fonts/manage/",
|
||||
Endpoint: "/collaboration/fonts/manage",
|
||||
Service: "eu.opencloud.web.collaboration",
|
||||
// Method: "POST" // toDo: fails with method, WHY???
|
||||
},
|
||||
{
|
||||
Endpoint: "/collaboration/notify",
|
||||
Service: "eu.opencloud.web.collaboration",
|
||||
// Method: "POST" // toDo: fails with method, WHY???
|
||||
},
|
||||
|
||||
@@ -10,6 +10,12 @@ import (
|
||||
cs3permissions "github.com/cs3org/go-cs3apis/cs3/permissions/v1beta1"
|
||||
rpcv1beta1 "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
"github.com/leonelquinteros/gotext"
|
||||
ctxpkg "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
merrors "go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/l10n"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/middleware"
|
||||
@@ -20,11 +26,6 @@ import (
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/settings"
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
|
||||
metastore "github.com/opencloud-eu/opencloud/services/settings/pkg/store/metadata"
|
||||
ctxpkg "github.com/opencloud-eu/reva/v2/pkg/ctx"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/status"
|
||||
merrors "go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
//go:embed l10n/locale
|
||||
@@ -708,6 +709,7 @@ func translateBundle(bundle *settingsmsg.Bundle, t *gotext.Locale) *settingsmsg.
|
||||
defaults.SettingUUIDProfileEventSpaceUnshared,
|
||||
defaults.SettingUUIDProfileEventSpaceMembershipExpired,
|
||||
defaults.SettingUUIDProfileEventSpaceDisabled,
|
||||
defaults.SettingUUIDProfileEventResourceMention,
|
||||
defaults.SettingUUIDProfileEventSpaceDeleted:
|
||||
// translate event names ('Share Received', 'Share Removed', ...)
|
||||
set.DisplayName = t.Get(set.GetDisplayName(), []any{}...)
|
||||
|
||||
@@ -193,5 +193,6 @@ func getDefaultValueList() map[string]*settingsmsg.ValueWithIdentifier {
|
||||
defaults.SettingUUIDProfileEventSpaceDeleted: nil,
|
||||
defaults.SettingUUIDProfileEventPostprocessingStepFinished: nil,
|
||||
defaults.SettingUUIDProfileEmailSendingInterval: nil,
|
||||
defaults.SettingUUIDProfileEventResourceMention: nil,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,8 @@ const (
|
||||
SettingUUIDProfileEventSpaceDeleted = "094ceca9-5a00-40ba-bb1a-bbc7bccd39ee"
|
||||
// SettingUUIDProfileEventPostprocessingStepFinished is the hardcoded setting UUID for the send in mail setting
|
||||
SettingUUIDProfileEventPostprocessingStepFinished = "fe0a3011-d886-49c8-b797-33d02fa426ef"
|
||||
// SettingUUIDProfileEventResourceMention is the hardcoded setting UUID for the send in mail setting
|
||||
SettingUUIDProfileEventResourceMention = "08aaa973-a622-449d-97dc-3857160d1e97"
|
||||
)
|
||||
|
||||
// GenerateBundlesDefaultRoles bootstraps the default roles.
|
||||
@@ -79,6 +81,7 @@ func ServiceAccountBundle() *settingsmsg.Bundle {
|
||||
Settings: []*settingsmsg.Setting{
|
||||
AccountManagementPermission(All),
|
||||
ChangeLogoPermission(All),
|
||||
CollaborationPublishNotificationPermission(All),
|
||||
CollaborationManageFontsPermission(All),
|
||||
CreatePublicLinkPermission(All),
|
||||
CreateSharePermission(All),
|
||||
@@ -116,6 +119,7 @@ func generateBundleAdminRole() *settingsmsg.Bundle {
|
||||
AccountManagementPermission(All),
|
||||
AutoAcceptSharesPermission(Own),
|
||||
ChangeLogoPermission(All),
|
||||
CollaborationPublishNotificationPermission(All),
|
||||
CollaborationManageFontsPermission(All),
|
||||
CreatePublicLinkPermission(All),
|
||||
CreateSharePermission(All),
|
||||
@@ -180,6 +184,7 @@ func generateBundleSpaceAdminRole() *settingsmsg.Bundle {
|
||||
ProfileEventPostprocessingStepFinishedPermission(Own),
|
||||
LanguageManagementPermission(Own),
|
||||
ListFavoritesPermission(Own),
|
||||
CollaborationPublishNotificationPermission(All),
|
||||
ListSpacesPermission(All),
|
||||
ManageSpacePropertiesPermission(All),
|
||||
SelfManagementPermission(Own),
|
||||
@@ -218,6 +223,7 @@ func generateBundleUserRole() *settingsmsg.Bundle {
|
||||
ProfileEventPostprocessingStepFinishedPermission(Own),
|
||||
LanguageManagementPermission(Own),
|
||||
ListFavoritesPermission(Own),
|
||||
CollaborationPublishNotificationPermission(All),
|
||||
SelfManagementPermission(Own),
|
||||
WriteFavoritesPermission(Own),
|
||||
},
|
||||
@@ -345,6 +351,23 @@ func generateBundleProfileRequest() *settingsmsg.Bundle {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: SettingUUIDProfileEventResourceMention,
|
||||
Name: "event-resource-mention-options",
|
||||
DisplayName: TemplateResourceMention,
|
||||
Description: TemplateResourceMentionDescription,
|
||||
Resource: &settingsmsg.Resource{
|
||||
Type: settingsmsg.Resource_TYPE_USER,
|
||||
},
|
||||
Value: &settingsmsg.Setting_MultiChoiceCollectionValue{
|
||||
MultiChoiceCollectionValue: &settingsmsg.MultiChoiceCollection{
|
||||
Options: []*settingsmsg.MultiChoiceCollectionOption{
|
||||
&optionInAppTrue,
|
||||
&optionMailTrue,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Id: SettingUUIDProfileEventSpaceShared,
|
||||
Name: "event-space-shared-options",
|
||||
|
||||
@@ -67,7 +67,7 @@ func ChangeLogoPermission(c settingsmsg.Permission_Constraint) *settingsmsg.Sett
|
||||
}
|
||||
}
|
||||
|
||||
// ManageFontsPermission is the permission to manage fonts
|
||||
// CollaborationManageFontsPermission is the permission to manage fonts
|
||||
func CollaborationManageFontsPermission(c settingsmsg.Permission_Constraint) *settingsmsg.Setting {
|
||||
return &settingsmsg.Setting{
|
||||
Id: "ed83fc10-1f54-4a9e-b5a7-fb517f5f3e01",
|
||||
@@ -86,6 +86,25 @@ func CollaborationManageFontsPermission(c settingsmsg.Permission_Constraint) *se
|
||||
}
|
||||
}
|
||||
|
||||
// CollaborationPublishNotificationPermission is the permission to manage fonts
|
||||
func CollaborationPublishNotificationPermission(c settingsmsg.Permission_Constraint) *settingsmsg.Setting {
|
||||
return &settingsmsg.Setting{
|
||||
Id: "43e5948e-8238-41d6-9ef1-f259f00591db",
|
||||
Name: "Collaboration.Notification.Publish",
|
||||
DisplayName: "Publish collaboration notifications",
|
||||
Description: "This permission permits to publish collaboration related notifications.",
|
||||
Resource: &settingsmsg.Resource{
|
||||
Type: settingsmsg.Resource_TYPE_SYSTEM,
|
||||
},
|
||||
Value: &settingsmsg.Setting_PermissionValue{
|
||||
PermissionValue: &settingsmsg.Permission{
|
||||
Operation: settingsmsg.Permission_OPERATION_READWRITE,
|
||||
Constraint: c,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CreatePublicLinkPermission is the permission to create public links
|
||||
func CreatePublicLinkPermission(c settingsmsg.Permission_Constraint) *settingsmsg.Setting {
|
||||
return &settingsmsg.Setting{
|
||||
|
||||
@@ -12,6 +12,10 @@ var (
|
||||
TemplateShareRemoved = l10n.Template("Share Removed")
|
||||
// description of the notification option 'Share Removed'
|
||||
TemplateShareRemovedDescription = l10n.Template("Notify when a received share has been removed")
|
||||
// name of the notification option 'Resource Mention'
|
||||
TemplateResourceMention = l10n.Template("Resource Mention")
|
||||
// description of the notification option 'Resource Mention'
|
||||
TemplateResourceMentionDescription = l10n.Template("Notify on resource mentions")
|
||||
// name of the notification option 'Share Expired'
|
||||
TemplateShareExpired = l10n.Template("Share Expired")
|
||||
// description of the notification option 'Share Expired'
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"os/signal"
|
||||
|
||||
"github.com/opencloud-eu/opencloud/pkg/config/configlog"
|
||||
ocEvents "github.com/opencloud-eu/opencloud/pkg/events"
|
||||
"github.com/opencloud-eu/opencloud/pkg/generators"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/registry"
|
||||
@@ -45,6 +46,9 @@ var _registeredEvents = []events.Unmarshaller{
|
||||
events.ShareCreated{},
|
||||
events.ShareRemoved{},
|
||||
events.ShareExpired{},
|
||||
|
||||
// misc
|
||||
ocEvents.ResourceMention{},
|
||||
}
|
||||
|
||||
// Server is the entrypoint for the server command.
|
||||
|
||||
@@ -14,11 +14,13 @@ import (
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
|
||||
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
|
||||
"github.com/opencloud-eu/opencloud/pkg/l10n"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/storagespace"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/utils"
|
||||
|
||||
ocEvents "github.com/opencloud-eu/opencloud/pkg/events"
|
||||
"github.com/opencloud-eu/opencloud/pkg/l10n"
|
||||
)
|
||||
|
||||
//go:embed l10n/locale
|
||||
@@ -115,7 +117,12 @@ func (c *Converter) ConvertEvent(eventid string, event any) (OC10Notification, e
|
||||
return c.shareMessage(eventid, ShareExpired, ev.ShareOwner, ev.ItemID, ev.ShareID, ev.ExpiredAt)
|
||||
case events.ShareRemoved:
|
||||
return c.shareMessage(eventid, ShareRemoved, ev.Executant, ev.ItemID, ev.ShareID, ev.Timestamp)
|
||||
|
||||
// misc
|
||||
case ocEvents.ResourceMention:
|
||||
return c.resourceMention(eventid, Mention, ev.Executant, ev.Ref.GetResourceId(), ev.Timestamp)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ConvertGlobalEvent converts a global event to an OC10Notification
|
||||
@@ -199,6 +206,40 @@ func (c *Converter) spaceMessage(eventid string, nt NotificationTemplate, execut
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Converter) resourceMention(eventid string, nt NotificationTemplate, executant *user.UserId, resourceid *storageprovider.ResourceId, ts time.Time) (OC10Notification, error) {
|
||||
usr, err := c.getUser(context.Background(), executant)
|
||||
if err != nil {
|
||||
return OC10Notification{}, err
|
||||
}
|
||||
|
||||
info, err := c.getResource(c.serviceAccountContext, resourceid)
|
||||
if err != nil {
|
||||
return OC10Notification{}, err
|
||||
}
|
||||
|
||||
subj, subjraw, msg, msgraw, err := composeMessage(nt, c.locale, c.defaultLanguage, c.translationPath, map[string]any{
|
||||
"username": usr.GetDisplayName(),
|
||||
"resourcename": info.GetName(),
|
||||
})
|
||||
if err != nil {
|
||||
return OC10Notification{}, err
|
||||
}
|
||||
|
||||
return OC10Notification{
|
||||
EventID: eventid,
|
||||
Service: c.serviceName,
|
||||
UserName: usr.GetUsername(),
|
||||
Timestamp: ts.Format(time.RFC3339Nano),
|
||||
ResourceID: storagespace.FormatResourceID(info.GetId()),
|
||||
ResourceType: "mention",
|
||||
Subject: subj,
|
||||
SubjectRaw: subjraw,
|
||||
Message: msg,
|
||||
MessageRaw: msgraw,
|
||||
MessageDetails: generateDetails(usr, nil, info, nil),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Converter) shareMessage(eventid string, nt NotificationTemplate, executant *user.UserId, resourceid *storageprovider.ResourceId, shareid *collaboration.ShareId, ts time.Time) (OC10Notification, error) {
|
||||
usr, err := c.getUser(context.Background(), executant)
|
||||
if err != nil {
|
||||
|
||||
@@ -5,12 +5,14 @@ import (
|
||||
"errors"
|
||||
|
||||
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
micrometadata "go-micro.dev/v4/metadata"
|
||||
|
||||
ocEvents "github.com/opencloud-eu/opencloud/pkg/events"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/middleware"
|
||||
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
|
||||
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/events"
|
||||
micrometadata "go-micro.dev/v4/metadata"
|
||||
)
|
||||
|
||||
type userlogFilter struct {
|
||||
@@ -61,6 +63,8 @@ func (ulf userlogFilter) filterUsersBySettings(ctx context.Context, users []stri
|
||||
settingId = defaults.SettingUUIDProfileEventSpaceDisabled
|
||||
case events.SpaceDeleted:
|
||||
settingId = defaults.SettingUUIDProfileEventSpaceDeleted
|
||||
case ocEvents.ResourceMention:
|
||||
settingId = defaults.SettingUUIDProfileEventResourceMention
|
||||
default:
|
||||
// event that cannot be disabled
|
||||
return users
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"go-micro.dev/v4/store"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
ocEvents "github.com/opencloud-eu/opencloud/pkg/events"
|
||||
"github.com/opencloud-eu/opencloud/pkg/l10n"
|
||||
"github.com/opencloud-eu/opencloud/pkg/log"
|
||||
"github.com/opencloud-eu/opencloud/pkg/roles"
|
||||
@@ -168,6 +169,11 @@ func (ul *UserlogService) processEvent(event events.Event) {
|
||||
case events.SpaceShared:
|
||||
executant = e.Executant
|
||||
users, err = utils.ResolveID(ctx, e.GranteeUserID, e.GranteeGroupID, gwc)
|
||||
case ocEvents.ResourceMention:
|
||||
executant = e.Executant
|
||||
for _, userID := range e.UserIDs {
|
||||
users = append(users, userID.GetOpaqueId())
|
||||
}
|
||||
case events.SpaceUnshared:
|
||||
executant = e.Executant
|
||||
users, err = utils.ResolveID(ctx, e.GranteeUserID, e.GranteeGroupID, gwc)
|
||||
|
||||
@@ -49,6 +49,11 @@ var (
|
||||
Message: l10n.Template("{user} unshared {resource} with you"),
|
||||
}
|
||||
|
||||
Mention = NotificationTemplate{
|
||||
Subject: l10n.Template("You have been mentioned"),
|
||||
Message: l10n.Template("{user} mentioned you in {resource}"),
|
||||
}
|
||||
|
||||
ShareExpired = NotificationTemplate{
|
||||
Subject: l10n.Template("Share expired"),
|
||||
Message: l10n.Template("Access to {resource} expired"),
|
||||
|
||||
Reference in New Issue
Block a user