✨ Basically move messages to events
This commit is contained in:
		
							
								
								
									
										97
									
								
								pkg/internal/server/api/events_api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								pkg/internal/server/api/events_api.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| package api | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/gap" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/models" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/server/exts" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/services" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|  | ||||
| func listEvent(c *fiber.Ctx) error { | ||||
| 	if err := gap.H.EnsureAuthenticated(c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user := c.Locals("user").(models.Account) | ||||
| 	take := c.QueryInt("take", 0) | ||||
| 	offset := c.QueryInt("offset", 0) | ||||
| 	alias := c.Params("channel") | ||||
|  | ||||
| 	var err error | ||||
| 	var channel models.Channel | ||||
| 	if val, ok := c.Locals("realm").(models.Realm); ok { | ||||
| 		channel, err = services.GetChannelWithAlias(alias, val.ID) | ||||
| 	} else { | ||||
| 		channel, err = services.GetChannelWithAlias(alias) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 	} else if _, _, err := services.GetAvailableChannel(channel.ID, user); err != nil { | ||||
| 		return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("you need join the channel before you read the messages: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	count := services.CountEvent(channel) | ||||
| 	messages, err := services.ListEvent(channel, take, offset) | ||||
| 	if err != nil { | ||||
| 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return c.JSON(fiber.Map{ | ||||
| 		"count": count, | ||||
| 		"data":  messages, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func newRawEvent(c *fiber.Ctx) error { | ||||
| 	if err := gap.H.EnsureGrantedPerm(c, "CreateMessagingRawEvent", true); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user := c.Locals("user").(models.Account) | ||||
| 	alias := c.Params("channel") | ||||
|  | ||||
| 	var data struct { | ||||
| 		Uuid string         `json:"uuid" validate:"required"` | ||||
| 		Type string         `json:"type" validate:"required"` | ||||
| 		Body map[string]any `json:"body"` | ||||
| 	} | ||||
|  | ||||
| 	if err := exts.BindAndValidate(c, &data); err != nil { | ||||
| 		return err | ||||
| 	} else if len(data.Uuid) < 36 { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, "message uuid was not valid") | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var channel models.Channel | ||||
| 	var member models.ChannelMember | ||||
| 	if val, ok := c.Locals("realm").(models.Realm); ok { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user, val.ID) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} else { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} else if member.PowerLevel < 0 { | ||||
| 			return fiber.NewError(fiber.StatusForbidden, "you have not enough permission to send message") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	message := models.Event{ | ||||
| 		Uuid:      data.Uuid, | ||||
| 		Body:      data.Body, | ||||
| 		Type:      data.Type, | ||||
| 		Sender:    member, | ||||
| 		Channel:   channel, | ||||
| 		ChannelID: channel.ID, | ||||
| 		SenderID:  member.ID, | ||||
| 	} | ||||
|  | ||||
| 	if message, err = services.NewEvent(message); err != nil { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return c.JSON(message) | ||||
| } | ||||
							
								
								
									
										149
									
								
								pkg/internal/server/api/events_message_api.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								pkg/internal/server/api/events_message_api.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,149 @@ | ||||
| package api | ||||
|  | ||||
| import ( | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/gap" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/models" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/server/exts" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/services" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| 	jsoniter "github.com/json-iterator/go" | ||||
| ) | ||||
|  | ||||
| func newMessageEvent(c *fiber.Ctx) error { | ||||
| 	if err := gap.H.EnsureAuthenticated(c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user := c.Locals("user").(models.Account) | ||||
| 	alias := c.Params("channel") | ||||
|  | ||||
| 	var data struct { | ||||
| 		Uuid string                  `json:"uuid" validate:"required"` | ||||
| 		Type string                  `json:"type" validate:"required"` | ||||
| 		Body models.EventMessageBody `json:"body"` | ||||
| 	} | ||||
|  | ||||
| 	if err := exts.BindAndValidate(c, &data); err != nil { | ||||
| 		return err | ||||
| 	} else if len(data.Uuid) < 36 { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, "message uuid was not valid") | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var channel models.Channel | ||||
| 	var member models.ChannelMember | ||||
| 	if val, ok := c.Locals("realm").(models.Realm); ok { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user, val.ID) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} else { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} else if member.PowerLevel < 0 { | ||||
| 			return fiber.NewError(fiber.StatusForbidden, "you have not enough permission to send message") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var parsed map[string]any | ||||
| 	raw, _ := jsoniter.Marshal(data.Body) | ||||
| 	_ = jsoniter.Unmarshal(raw, &parsed) | ||||
|  | ||||
| 	event := models.Event{ | ||||
| 		Uuid:      data.Uuid, | ||||
| 		Body:      parsed, | ||||
| 		Type:      data.Type, | ||||
| 		Sender:    member, | ||||
| 		Channel:   channel, | ||||
| 		ChannelID: channel.ID, | ||||
| 		SenderID:  member.ID, | ||||
| 	} | ||||
|  | ||||
| 	if event, err = services.NewEvent(event); err != nil { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return c.JSON(event) | ||||
| } | ||||
|  | ||||
| func editMessageEvent(c *fiber.Ctx) error { | ||||
| 	if err := gap.H.EnsureAuthenticated(c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user := c.Locals("user").(models.Account) | ||||
| 	alias := c.Params("channel") | ||||
| 	messageId, _ := c.ParamsInt("messageId", 0) | ||||
|  | ||||
| 	var data struct { | ||||
| 		Uuid string                  `json:"uuid" validate:"required"` | ||||
| 		Type string                  `json:"type" validate:"required"` | ||||
| 		Body models.EventMessageBody `json:"body"` | ||||
| 	} | ||||
|  | ||||
| 	if err := exts.BindAndValidate(c, &data); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var channel models.Channel | ||||
| 	var member models.ChannelMember | ||||
| 	if val, ok := c.Locals("realm").(models.Realm); ok { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user, val.ID) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} else { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var event models.Event | ||||
| 	if event, err = services.GetEventWithSender(channel, member, uint(messageId)); err != nil { | ||||
| 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	event, err = services.EditMessage(event, data.Body) | ||||
| 	if err != nil { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return c.JSON(event) | ||||
| } | ||||
|  | ||||
| func deleteMessageEvent(c *fiber.Ctx) error { | ||||
| 	if err := gap.H.EnsureAuthenticated(c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user := c.Locals("user").(models.Account) | ||||
| 	alias := c.Params("channel") | ||||
| 	messageId, _ := c.ParamsInt("messageId", 0) | ||||
|  | ||||
| 	var err error | ||||
| 	var channel models.Channel | ||||
| 	var member models.ChannelMember | ||||
| 	if val, ok := c.Locals("realm").(models.Realm); ok { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user, val.ID) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} else { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var event models.Event | ||||
| 	if event, err = services.GetEventWithSender(channel, member, uint(messageId)); err != nil { | ||||
| 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	event, err = services.DeleteMessage(event) | ||||
| 	if err != nil { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return c.JSON(event) | ||||
| } | ||||
| @@ -33,10 +33,12 @@ func MapAPIs(app *fiber.App) { | ||||
| 			channels.Delete("/:channel/members", removeChannelMember) | ||||
| 			channels.Delete("/:channel/members/me", leaveChannel) | ||||
|  | ||||
| 			channels.Get("/:channel/messages", listMessage) | ||||
| 			channels.Post("/:channel/messages", newMessage) | ||||
| 			channels.Put("/:channel/messages/:messageId", editMessage) | ||||
| 			channels.Delete("/:channel/messages/:messageId", deleteMessage) | ||||
| 			channels.Get("/:channel/events", listEvent) | ||||
| 			channels.Post("/:channel/events", newRawEvent) | ||||
|  | ||||
| 			channels.Post("/:channel/messages", newMessageEvent) | ||||
| 			channels.Put("/:channel/messages/:messageId", editMessageEvent) | ||||
| 			channels.Delete("/:channel/messages/:messageId", deleteMessageEvent) | ||||
|  | ||||
| 			channels.Get("/:channel/calls", listCall) | ||||
| 			channels.Get("/:channel/calls/ongoing", getOngoingCall) | ||||
|   | ||||
| @@ -1,221 +0,0 @@ | ||||
| package api | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/database" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/gap" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/models" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/server/exts" | ||||
| 	"git.solsynth.dev/hydrogen/messaging/pkg/internal/services" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| func listMessage(c *fiber.Ctx) error { | ||||
| 	if err := gap.H.EnsureAuthenticated(c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user := c.Locals("user").(models.Account) | ||||
| 	take := c.QueryInt("take", 0) | ||||
| 	offset := c.QueryInt("offset", 0) | ||||
| 	alias := c.Params("channel") | ||||
|  | ||||
| 	var err error | ||||
| 	var channel models.Channel | ||||
| 	if val, ok := c.Locals("realm").(models.Realm); ok { | ||||
| 		channel, err = services.GetChannelWithAlias(alias, val.ID) | ||||
| 	} else { | ||||
| 		channel, err = services.GetChannelWithAlias(alias) | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 	} else if _, _, err := services.GetAvailableChannel(channel.ID, user); err != nil { | ||||
| 		return fiber.NewError(fiber.StatusForbidden, fmt.Sprintf("you need join the channel before you read the messages: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	count := services.CountMessage(channel) | ||||
| 	messages, err := services.ListMessage(channel, take, offset) | ||||
| 	if err != nil { | ||||
| 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return c.JSON(fiber.Map{ | ||||
| 		"count": count, | ||||
| 		"data":  messages, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func newMessage(c *fiber.Ctx) error { | ||||
| 	if err := gap.H.EnsureAuthenticated(c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user := c.Locals("user").(models.Account) | ||||
| 	alias := c.Params("channel") | ||||
|  | ||||
| 	var data struct { | ||||
| 		Uuid        string         `json:"uuid" validate:"required"` | ||||
| 		Type        string         `json:"type" validate:"required"` | ||||
| 		Content     map[string]any `json:"content"` | ||||
| 		Attachments []uint         `json:"attachments"` | ||||
| 		ReplyTo     *uint          `json:"reply_to"` | ||||
| 	} | ||||
|  | ||||
| 	if err := exts.BindAndValidate(c, &data); err != nil { | ||||
| 		return err | ||||
| 	} else if len(data.Uuid) < 36 { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, "message uuid was not valid") | ||||
| 	} | ||||
|  | ||||
| 	if len(data.Attachments) == 0 { | ||||
| 		if data.Type == models.MessageTextType { | ||||
| 			if val, ok := data.Content["value"].(string); ok && len(strings.TrimSpace(val)) == 0 { | ||||
| 				return fiber.NewError(fiber.StatusBadRequest, "you cannot send an empty message") | ||||
| 			} else if !ok { | ||||
| 				return fiber.NewError(fiber.StatusBadRequest, "invalid content of text message") | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, attachment := range data.Attachments { | ||||
| 		if !services.CheckAttachmentByIDExists(attachment, "m.attachment") { | ||||
| 			return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("attachment %d not found", attachment)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var channel models.Channel | ||||
| 	var member models.ChannelMember | ||||
| 	if val, ok := c.Locals("realm").(models.Realm); ok { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user, val.ID) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} else { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} else if member.PowerLevel < 0 { | ||||
| 			return fiber.NewError(fiber.StatusForbidden, "you have not enough permission to send message") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	message := models.Message{ | ||||
| 		Uuid:        data.Uuid, | ||||
| 		Content:     data.Content, | ||||
| 		Sender:      member, | ||||
| 		Channel:     channel, | ||||
| 		ChannelID:   channel.ID, | ||||
| 		SenderID:    member.ID, | ||||
| 		Attachments: data.Attachments, | ||||
| 		Type:        data.Type, | ||||
| 	} | ||||
|  | ||||
| 	var replyTo models.Message | ||||
| 	if data.ReplyTo != nil { | ||||
| 		if err := database.C.Where("id = ?", data.ReplyTo).First(&replyTo).Error; err != nil { | ||||
| 			return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("message to reply was not found: %v", err)) | ||||
| 		} else { | ||||
| 			message.ReplyTo = &replyTo | ||||
| 			message.ReplyID = &replyTo.ID | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if message, err = services.NewMessage(message); err != nil { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return c.JSON(message) | ||||
| } | ||||
|  | ||||
| func editMessage(c *fiber.Ctx) error { | ||||
| 	if err := gap.H.EnsureAuthenticated(c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user := c.Locals("user").(models.Account) | ||||
| 	alias := c.Params("channel") | ||||
| 	messageId, _ := c.ParamsInt("messageId", 0) | ||||
|  | ||||
| 	var data struct { | ||||
| 		Type        string         `json:"type" validate:"required"` | ||||
| 		Content     map[string]any `json:"content"` | ||||
| 		Attachments []uint         `json:"attachments"` | ||||
| 		ReplyTo     *uint          `json:"reply_to"` | ||||
| 	} | ||||
|  | ||||
| 	if err := exts.BindAndValidate(c, &data); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	for _, attachment := range data.Attachments { | ||||
| 		if !services.CheckAttachmentByIDExists(attachment, "m.attachment") { | ||||
| 			return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("attachment %d not found", attachment)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var channel models.Channel | ||||
| 	var member models.ChannelMember | ||||
| 	if val, ok := c.Locals("realm").(models.Realm); ok { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user, val.ID) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} else { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var message models.Message | ||||
| 	if message, err = services.GetMessageWithPrincipal(channel, member, uint(messageId)); err != nil { | ||||
| 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	message.Attachments = data.Attachments | ||||
| 	message.Content = data.Content | ||||
| 	message.Type = data.Type | ||||
|  | ||||
| 	message, err = services.EditMessage(message) | ||||
| 	if err != nil { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return c.JSON(message) | ||||
| } | ||||
|  | ||||
| func deleteMessage(c *fiber.Ctx) error { | ||||
| 	if err := gap.H.EnsureAuthenticated(c); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	user := c.Locals("user").(models.Account) | ||||
| 	alias := c.Params("channel") | ||||
| 	messageId, _ := c.ParamsInt("messageId", 0) | ||||
|  | ||||
| 	var err error | ||||
| 	var channel models.Channel | ||||
| 	var member models.ChannelMember | ||||
| 	if val, ok := c.Locals("realm").(models.Realm); ok { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user, val.ID) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} else { | ||||
| 		channel, member, err = services.GetAvailableChannelWithAlias(alias, user) | ||||
| 		if err != nil { | ||||
| 			return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var message models.Message | ||||
| 	if message, err = services.GetMessageWithPrincipal(channel, member, uint(messageId)); err != nil { | ||||
| 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	message, err = services.DeleteMessage(message) | ||||
| 	if err != nil { | ||||
| 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return c.JSON(message) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user