diff --git a/pkg/internal/http/api/index.go b/pkg/internal/http/api/index.go index e75fd0e..950c728 100644 --- a/pkg/internal/http/api/index.go +++ b/pkg/internal/http/api/index.go @@ -7,6 +7,11 @@ import ( func MapAPIs(app *fiber.App, baseURL string) { api := app.Group(baseURL).Name("API") { + quick := api.Group("/quick") + { + quick.Post("/:channelId/reply/:eventId", quickReply) + } + channels := api.Group("/channels/:realm").Use(realmMiddleware).Name("Channels API") { channels.Get("/", listChannel) diff --git a/pkg/internal/http/api/quick_actions_api.go b/pkg/internal/http/api/quick_actions_api.go new file mode 100644 index 0000000..bcb6035 --- /dev/null +++ b/pkg/internal/http/api/quick_actions_api.go @@ -0,0 +1,71 @@ +package api + +import ( + "fmt" + "strings" + + "git.solsynth.dev/hypernet/messaging/pkg/internal/http/exts" + "git.solsynth.dev/hypernet/messaging/pkg/internal/models" + "git.solsynth.dev/hypernet/messaging/pkg/internal/services" + "git.solsynth.dev/hypernet/nexus/pkg/nex/sec" + authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" + "github.com/gofiber/fiber/v2" + "github.com/google/uuid" + jsoniter "github.com/json-iterator/go" + "github.com/samber/lo" +) + +// quickReply is a simplified API for replying to a message +// It used in the iOS notification action and others +// It did not support all the features of the message event +// But it just works +func quickReply(c *fiber.Ctx) error { + if err := sec.EnsureAuthenticated(c); err != nil { + return err + } + user := c.Locals("user").(authm.Account) + channelId, _ := c.ParamsInt("channelId", 0) + eventId, _ := c.ParamsInt("eventId", 0) + + var data struct { + Type string `json:"type" validate:"required"` + Body models.EventMessageBody `json:"body"` + } + + if err := exts.BindAndValidate(c, &data); err != nil { + return err + } else { + data.Body.QuoteEventID = lo.ToPtr(uint(eventId)) + } + + data.Body.Text = strings.TrimSpace(data.Body.Text) + if len(data.Body.Text) == 0 && len(data.Body.Attachments) == 0 { + return fiber.NewError(fiber.StatusBadRequest, "empty message was not allowed") + } + + channel, member, err := services.GetChannelIdentityWithID(uint(channelId), user.ID) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("channel / member not found: %v", err.Error())) + } + + var parsed map[string]any + raw, _ := jsoniter.Marshal(data.Body) + _ = jsoniter.Unmarshal(raw, &parsed) + + event, err := services.NewEvent(models.Event{ + Uuid: uuid.NewString(), + Body: parsed, + Type: data.Type, + Sender: member, + Channel: channel, + QuoteEventID: data.Body.QuoteEventID, + RelatedEventID: data.Body.RelatedEventID, + ChannelID: channel.ID, + SenderID: member.ID, + }) + if err != nil { + return fiber.NewError(fiber.StatusBadRequest, err.Error()) + } + + return c.JSON(event) +} diff --git a/pkg/internal/services/channels.go b/pkg/internal/services/channels.go index 9706007..768f28c 100644 --- a/pkg/internal/services/channels.go +++ b/pkg/internal/services/channels.go @@ -3,12 +3,13 @@ package services import ( "context" "fmt" + "regexp" + localCache "git.solsynth.dev/hypernet/messaging/pkg/internal/cache" authm "git.solsynth.dev/hypernet/passport/pkg/authkit/models" "github.com/eko/gocache/lib/v4/cache" "github.com/eko/gocache/lib/v4/marshaler" "github.com/eko/gocache/lib/v4/store" - "regexp" "git.solsynth.dev/hypernet/messaging/pkg/internal/database" "git.solsynth.dev/hypernet/messaging/pkg/internal/models" @@ -45,6 +46,19 @@ func CacheChannelIdentityCache(channel models.Channel, member models.ChannelMemb ) } +func GetChannelIdentityWithID(id uint, user uint) (models.Channel, models.ChannelMember, error) { + var member models.ChannelMember + + if err := database.C.Where(models.ChannelMember{ + AccountID: user, + ChannelID: id, + }).Preload("Channel").First(&member).Error; err != nil { + return member.Channel, member, fmt.Errorf("channel principal not found: %v", err.Error()) + } + + return member.Channel, member, nil +} + func GetChannelIdentity(alias string, user uint, realm ...authm.Realm) (models.Channel, models.ChannelMember, error) { cacheManager := cache.New[any](localCache.S) marshal := marshaler.New(cacheManager) diff --git a/pkg/internal/services/events.go b/pkg/internal/services/events.go index 4533bc2..a82f510 100644 --- a/pkg/internal/services/events.go +++ b/pkg/internal/services/events.go @@ -2,12 +2,13 @@ package services import ( "fmt" + "strings" + "git.solsynth.dev/hypernet/messaging/pkg/internal/gap" "git.solsynth.dev/hypernet/nexus/pkg/nex" "git.solsynth.dev/hypernet/nexus/pkg/nex/cruda" "git.solsynth.dev/hypernet/passport/pkg/authkit" "git.solsynth.dev/hypernet/pusher/pkg/pushkit" - "strings" "git.solsynth.dev/hypernet/messaging/pkg/internal/database" "git.solsynth.dev/hypernet/messaging/pkg/internal/models" @@ -180,6 +181,15 @@ func NotifyMessageEvent(members []models.ChannelMember, event models.Event) { displayTitle := fmt.Sprintf("%s (%s)", event.Sender.Nick, event.Channel.DisplayText()) + metadata := map[string]any{ + "avatar": event.Sender.Avatar, + "user_id": event.Sender.AccountID, + "user_name": event.Sender.Name, + "user_nick": event.Sender.Nick, + "channel_id": event.ChannelID, + "event_id": event.ID, + } + if len(pendingUsers) > 0 { log.Debug(). Uint("event_id", event.ID). @@ -195,13 +205,7 @@ func NotifyMessageEvent(members []models.ChannelMember, event models.Event) { Title: displayTitle, Subtitle: displaySubtitle, Body: displayText, - Metadata: map[string]any{ - "avatar": event.Sender.Avatar, - "user_id": event.Sender.AccountID, - "user_name": event.Sender.Name, - "user_nick": event.Sender.Nick, - "channel_id": event.ChannelID, - }, + Metadata: metadata, Priority: 5, }, true, @@ -232,13 +236,7 @@ func NotifyMessageEvent(members []models.ChannelMember, event models.Event) { Title: displayTitle, Subtitle: displaySubtitle, Body: displayText, - Metadata: map[string]any{ - "avatar": event.Sender.Avatar, - "user_id": event.Sender.AccountID, - "user_name": event.Sender.Name, - "user_nick": event.Sender.Nick, - "channel_id": event.ChannelID, - }, + Metadata: metadata, Priority: 5, }, true,