⬆️ Switch to Paperclip
This commit is contained in:
@ -1,127 +1,30 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"context"
|
||||
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||
"github.com/google/uuid"
|
||||
"github.com/spf13/viper"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/grpc"
|
||||
pcpb "git.solsynth.dev/hydrogen/paperclip/pkg/grpc/proto"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func GetAttachmentByID(id uint) (models.Attachment, error) {
|
||||
var attachment models.Attachment
|
||||
if err := database.C.Where(models.Attachment{
|
||||
BaseModel: models.BaseModel{ID: id},
|
||||
}).First(&attachment).Error; err != nil {
|
||||
return attachment, err
|
||||
}
|
||||
return attachment, nil
|
||||
func GetAttachmentByID(id uint) (*pcpb.Attachment, error) {
|
||||
return grpc.Attachments.GetAttachment(context.Background(), &pcpb.AttachmentLookupRequest{
|
||||
Id: lo.ToPtr(uint64(id)),
|
||||
})
|
||||
}
|
||||
|
||||
func GetAttachmentByUUID(fileId string) (models.Attachment, error) {
|
||||
var attachment models.Attachment
|
||||
if err := database.C.Where(models.Attachment{
|
||||
FileID: fileId,
|
||||
}).First(&attachment).Error; err != nil {
|
||||
return attachment, err
|
||||
}
|
||||
return attachment, nil
|
||||
func GetAttachmentByUUID(uuid string) (*pcpb.Attachment, error) {
|
||||
return grpc.Attachments.GetAttachment(context.Background(), &pcpb.AttachmentLookupRequest{
|
||||
Uuid: &uuid,
|
||||
})
|
||||
}
|
||||
|
||||
func GetAttachmentByHashcode(hashcode string) (models.Attachment, error) {
|
||||
var attachment models.Attachment
|
||||
if err := database.C.Where(models.Attachment{
|
||||
Hashcode: hashcode,
|
||||
}).First(&attachment).Error; err != nil {
|
||||
return attachment, err
|
||||
}
|
||||
return attachment, nil
|
||||
}
|
||||
|
||||
func NewAttachment(user models.Account, header *multipart.FileHeader, hashcode string) (models.Attachment, error) {
|
||||
var attachment models.Attachment
|
||||
existsAttachment, err := GetAttachmentByHashcode(hashcode)
|
||||
if err != nil {
|
||||
// Upload the new file
|
||||
attachment = models.Attachment{
|
||||
FileID: uuid.NewString(),
|
||||
Filesize: header.Size,
|
||||
Filename: header.Filename,
|
||||
Hashcode: hashcode,
|
||||
Mimetype: "unknown/unknown",
|
||||
Type: models.AttachmentOthers,
|
||||
AuthorID: user.ID,
|
||||
}
|
||||
|
||||
// Open file
|
||||
file, err := header.Open()
|
||||
if err != nil {
|
||||
return attachment, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Detect mimetype
|
||||
fileHeader := make([]byte, 512)
|
||||
_, err = file.Read(fileHeader)
|
||||
if err != nil {
|
||||
return attachment, err
|
||||
}
|
||||
attachment.Mimetype = http.DetectContentType(fileHeader)
|
||||
|
||||
switch strings.Split(attachment.Mimetype, "/")[0] {
|
||||
case "image":
|
||||
attachment.Type = models.AttachmentPhoto
|
||||
case "video":
|
||||
attachment.Type = models.AttachmentVideo
|
||||
case "audio":
|
||||
attachment.Type = models.AttachmentAudio
|
||||
default:
|
||||
attachment.Type = models.AttachmentOthers
|
||||
}
|
||||
} else {
|
||||
// Instant upload, build link with the exists file
|
||||
attachment = models.Attachment{
|
||||
FileID: existsAttachment.FileID,
|
||||
Filesize: header.Size,
|
||||
Filename: header.Filename,
|
||||
Hashcode: hashcode,
|
||||
Mimetype: existsAttachment.Mimetype,
|
||||
Type: existsAttachment.Type,
|
||||
AuthorID: user.ID,
|
||||
}
|
||||
}
|
||||
|
||||
// Save into database
|
||||
err = database.C.Save(&attachment).Error
|
||||
|
||||
return attachment, err
|
||||
}
|
||||
|
||||
func DeleteAttachment(item models.Attachment) error {
|
||||
var dupeCount int64
|
||||
if err := database.C.
|
||||
Where(&models.Attachment{Hashcode: item.Hashcode}).
|
||||
Model(&models.Attachment{}).
|
||||
Count(&dupeCount).Error; err != nil {
|
||||
dupeCount = -1
|
||||
}
|
||||
|
||||
if err := database.C.Delete(&item).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if dupeCount != -1 && dupeCount <= 1 {
|
||||
// Safe for deletion the physics file
|
||||
basepath := viper.GetString("content")
|
||||
fullpath := filepath.Join(basepath, item.FileID)
|
||||
|
||||
os.Remove(fullpath)
|
||||
}
|
||||
|
||||
return nil
|
||||
func CheckAttachmentByIDExists(id uint, usage string) bool {
|
||||
_, err := grpc.Attachments.CheckAttachmentExists(context.Background(), &pcpb.AttachmentLookupRequest{
|
||||
Id: lo.ToPtr(uint64(id)),
|
||||
Usage: &usage,
|
||||
})
|
||||
|
||||
return err == nil
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||
)
|
||||
@ -19,6 +20,18 @@ func ListChannelMember(channelId uint) ([]models.ChannelMember, error) {
|
||||
return members, nil
|
||||
}
|
||||
|
||||
func GetChannelMember(user models.Account, channelId uint) (models.ChannelMember, error) {
|
||||
var member models.ChannelMember
|
||||
|
||||
if err := database.C.
|
||||
Where(&models.ChannelMember{AccountID: user.ID, ChannelID: channelId}).
|
||||
Find(&member).Error; err != nil {
|
||||
return member, err
|
||||
}
|
||||
|
||||
return member, nil
|
||||
}
|
||||
|
||||
func AddChannelMemberWithCheck(user models.Account, target models.Channel) error {
|
||||
if _, err := GetAccountFriend(user.ID, target.AccountID, 1); err != nil {
|
||||
return fmt.Errorf("you only can invite your friends to your channel")
|
||||
|
@ -80,11 +80,9 @@ func GetAvailableChannel(id uint, user models.Account) (models.Channel, models.C
|
||||
|
||||
func ListChannel(realmId ...uint) ([]models.Channel, error) {
|
||||
var channels []models.Channel
|
||||
tx := database.C.Preload("Account")
|
||||
tx := database.C.Preload("Account").Preload("Realm")
|
||||
if len(realmId) > 0 {
|
||||
tx = tx.Where("realm_id = ?", realmId)
|
||||
} else {
|
||||
tx = tx.Where("realm_id IS NULL")
|
||||
}
|
||||
if err := tx.Find(&channels).Error; err != nil {
|
||||
return channels, err
|
||||
@ -95,7 +93,7 @@ func ListChannel(realmId ...uint) ([]models.Channel, error) {
|
||||
|
||||
func ListChannelWithUser(user models.Account, realmId ...uint) ([]models.Channel, error) {
|
||||
var channels []models.Channel
|
||||
tx := database.C.Where(&models.Channel{AccountID: user.ID})
|
||||
tx := database.C.Where(&models.Channel{AccountID: user.ID}).Preload("Realm")
|
||||
if len(realmId) > 0 {
|
||||
tx = tx.Where("realm_id = ?", realmId)
|
||||
} else {
|
||||
@ -121,7 +119,7 @@ func ListAvailableChannel(user models.Account, realmId ...uint) ([]models.Channe
|
||||
return item.ChannelID
|
||||
})
|
||||
|
||||
tx := database.C.Where("id IN ?", idx)
|
||||
tx := database.C.Preload("Realm").Where("id IN ?", idx)
|
||||
if len(realmId) > 0 {
|
||||
tx = tx.Where("realm_id = ?", realmId)
|
||||
} else {
|
||||
@ -134,23 +132,8 @@ func ListAvailableChannel(user models.Account, realmId ...uint) ([]models.Channe
|
||||
return channels, nil
|
||||
}
|
||||
|
||||
func NewChannel(user models.Account, alias, name, description string, isEncrypted bool, realmId ...uint) (models.Channel, error) {
|
||||
channel := models.Channel{
|
||||
Alias: alias,
|
||||
Name: name,
|
||||
Description: description,
|
||||
IsEncrypted: isEncrypted,
|
||||
AccountID: user.ID,
|
||||
Members: []models.ChannelMember{
|
||||
{AccountID: user.ID},
|
||||
},
|
||||
}
|
||||
if len(realmId) > 0 {
|
||||
channel.RealmID = &realmId[0]
|
||||
}
|
||||
|
||||
func NewChannel(channel models.Channel) (models.Channel, error) {
|
||||
err := database.C.Save(&channel).Error
|
||||
|
||||
return channel, err
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||
"github.com/rs/zerolog/log"
|
||||
"time"
|
||||
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func DoAutoDatabaseCleanup() {
|
||||
@ -16,18 +16,10 @@ func DoAutoDatabaseCleanup() {
|
||||
for _, model := range database.DatabaseAutoActionRange {
|
||||
tx := database.C.Unscoped().Delete(model, "deleted_at >= ?", deadline)
|
||||
if tx.Error != nil {
|
||||
log.Error().Err(tx.Error).Msg("An error occurred when running auth context cleanup...")
|
||||
log.Error().Err(tx.Error).Msg("An error occurred when running database cleanup...")
|
||||
}
|
||||
count += tx.RowsAffected
|
||||
}
|
||||
|
||||
// Clean up outdated chat history
|
||||
tx := database.C.Unscoped().Delete(&models.Message{}, "created_at < ?", time.Now().Add(30*24*time.Hour))
|
||||
if tx.Error != nil {
|
||||
log.Error().Err(tx.Error).Msg("An error occurred when running auth context cleanup...")
|
||||
} else {
|
||||
count += tx.RowsAffected
|
||||
}
|
||||
|
||||
log.Debug().Int64("affected", count).Msg("Clean up entire database accomplished.")
|
||||
}
|
||||
|
@ -1,24 +1,33 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||
"github.com/gofiber/contrib/websocket"
|
||||
)
|
||||
|
||||
var wsConn = make(map[uint]map[*websocket.Conn]bool)
|
||||
var (
|
||||
wsMutex sync.Mutex
|
||||
wsConn = make(map[uint]map[*websocket.Conn]bool)
|
||||
)
|
||||
|
||||
func ClientRegister(user models.Account, conn *websocket.Conn) {
|
||||
wsMutex.Lock()
|
||||
if wsConn[user.ID] == nil {
|
||||
wsConn[user.ID] = make(map[*websocket.Conn]bool)
|
||||
}
|
||||
wsConn[user.ID][conn] = true
|
||||
wsMutex.Unlock()
|
||||
}
|
||||
|
||||
func ClientUnregister(user models.Account, conn *websocket.Conn) {
|
||||
wsMutex.Lock()
|
||||
if wsConn[user.ID] == nil {
|
||||
wsConn[user.ID] = make(map[*websocket.Conn]bool)
|
||||
}
|
||||
delete(wsConn[user.ID], conn)
|
||||
wsMutex.Unlock()
|
||||
}
|
||||
|
||||
func PushCommand(userId uint, task models.UnifiedCommand) {
|
||||
|
@ -2,11 +2,11 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func CountMessage(channel models.Channel) int64 {
|
||||
@ -31,7 +31,6 @@ func ListMessage(channel models.Channel, take int, offset int) ([]models.Message
|
||||
ChannelID: channel.ID,
|
||||
}).Limit(take).Offset(offset).
|
||||
Order("created_at DESC").
|
||||
Preload("Attachments").
|
||||
Preload("ReplyTo").
|
||||
Preload("ReplyTo.Sender").
|
||||
Preload("ReplyTo.Sender.Account").
|
||||
@ -54,7 +53,6 @@ func GetMessage(channel models.Channel, id uint) (models.Message, error) {
|
||||
Preload("ReplyTo").
|
||||
Preload("ReplyTo.Sender").
|
||||
Preload("ReplyTo.Sender.Account").
|
||||
Preload("Attachments").
|
||||
Preload("Sender").
|
||||
Preload("Sender.Account").
|
||||
First(&message).Error; err != nil {
|
||||
@ -78,9 +76,6 @@ func GetMessageWithPrincipal(channel models.Channel, member models.ChannelMember
|
||||
}
|
||||
|
||||
func NewMessage(message models.Message) (models.Message, error) {
|
||||
var decodedContent fiber.Map
|
||||
_ = jsoniter.Unmarshal(message.Content, &decodedContent)
|
||||
|
||||
var members []models.ChannelMember
|
||||
if err := database.C.Save(&message).Error; err != nil {
|
||||
return message, err
|
||||
@ -91,20 +86,39 @@ func NewMessage(message models.Message) (models.Message, error) {
|
||||
message, _ = GetMessage(message.Channel, message.ID)
|
||||
for _, member := range members {
|
||||
if member.ID != message.Sender.ID {
|
||||
// TODO Check the mentioned status
|
||||
if member.Notify == models.NotifyLevelAll {
|
||||
displayText := "*encrypted message*"
|
||||
if decodedContent["algorithm"] == "plain" {
|
||||
displayText, _ = decodedContent["value"].(string)
|
||||
}
|
||||
err = NotifyAccount(member.Account,
|
||||
fmt.Sprintf("New Message #%s", channel.Alias),
|
||||
fmt.Sprintf("%s: %s", message.Sender.Account.Name, displayText),
|
||||
true,
|
||||
)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("An error occurred when trying notify user.")
|
||||
switch member.Notify {
|
||||
case models.NotifyLevelNone:
|
||||
continue
|
||||
case models.NotifyLevelMentioned:
|
||||
if val, ok := message.Content["metioned_users"]; ok {
|
||||
if usernames, ok := val.([]string); ok {
|
||||
if lo.Contains(usernames, member.Account.Name) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
var displayText string
|
||||
if message.Content["algorithm"] == "plain" {
|
||||
displayText, _ = message.Content["value"].(string)
|
||||
} else {
|
||||
displayText = "*encrypted message*"
|
||||
}
|
||||
|
||||
if len(displayText) == 0 {
|
||||
displayText = fmt.Sprintf("%d attachment(s)", len(message.Attachments))
|
||||
}
|
||||
|
||||
err = NotifyAccount(member.Account,
|
||||
fmt.Sprintf("New Message #%s", channel.Alias),
|
||||
fmt.Sprintf("%s: %s", message.Sender.Account.Name, displayText),
|
||||
true,
|
||||
)
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("An error occurred when trying notify user.")
|
||||
}
|
||||
}
|
||||
PushCommand(member.AccountID, models.UnifiedCommand{
|
||||
|
Reference in New Issue
Block a user