diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/client/ui/core/chat/chat.go | 110 | ||||
| -rw-r--r-- | internal/data/messages.sql.go | 23 | ||||
| -rw-r--r-- | internal/data/models.go | 1 | ||||
| -rw-r--r-- | internal/packet/models.go | 7 | ||||
| -rw-r--r-- | internal/packet/types.go | 1 | ||||
| -rw-r--r-- | internal/server/api/api.go | 30 | ||||
| -rw-r--r-- | internal/server/api/migrations/20250127154005_ping.sql | 8 |
7 files changed, 157 insertions, 23 deletions
diff --git a/internal/client/ui/core/chat/chat.go b/internal/client/ui/core/chat/chat.go index c796050..3cad1b5 100644 --- a/internal/client/ui/core/chat/chat.go +++ b/internal/client/ui/core/chat/chat.go @@ -76,6 +76,11 @@ var ( MutedSymbol = lipgloss.NewStyle(). Foreground(colors.Red).Render(" ") + + PingPrefix = "@ping:" + + PingedBorderStyle = lipgloss.NewStyle(). + Border(lipgloss.Border{Left: "┃"}, false, false, false, true) ) const ( @@ -561,19 +566,13 @@ func (m Model) Locked() bool { func (m *Model) sendMessage() tea.Cmd { message := m.vi.String() - if len(message) > MaxCharCount { - return nil - } - if len(strings.TrimSpace(message)) == 0 { - return nil - } - m.vi.Reset() - m.base = SnapToBottom + var ping *snowflake.ID var receiverId *snowflake.ID = nil if m.receiverIndex != -1 { receiverId = &state.Data.Peers[m.receiverIndex] + ping = nil } var frequencyId *snowflake.ID = nil @@ -581,12 +580,50 @@ func (m *Model) sendMessage() tea.Cmd { if m.frequencyIndex != -1 && networkId != nil { frequencies := state.State.Frequencies[*networkId] frequencyId = &frequencies[m.frequencyIndex].ID + + // Parse ping + if strings.HasPrefix(message, PingPrefix) { + index := strings.Index(message, "\n") + if index != -1 { + value := message[len(PingPrefix):index] + switch value { + case "everyone": + pingValue := packet.PingEveryone + ping = &pingValue + message = message[index+1:] + case "admins": + pingValue := packet.PingAdmins + ping = &pingValue + message = message[index+1:] + default: + num, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return nil + } + ping = (*snowflake.ID)(&num) + message = message[index+1:] + } + } + } else { + ping = nil + } } + if len(message) > MaxCharCount { + return nil + } + if len(strings.TrimSpace(message)) == 0 { + return nil + } + + m.vi.Reset() + m.base = SnapToBottom + return gateway.Send(&packet.SendMessage{ ReceiverID: receiverId, FrequencyID: frequencyId, Content: message, + Ping: ping, }) } @@ -903,8 +940,27 @@ func (m *Model) renderMessageGroup(group []data.Message, remaining *int, height // Render all messages content messageStyle := lipgloss.NewStyle().Width(m.width). - PaddingLeft(PaddingCount + 2).PaddingRight(PaddingCount) + MarginLeft(PaddingCount + 2).PaddingRight(PaddingCount) + for i := len(group) - 1; i >= 0; i-- { + messageStyle := messageStyle + if m.frequencyIndex != -1 && group[i].Ping != nil { + members := state.State.Members[*state.NetworkId(m.networkIndex)] + if *group[i].Ping == *state.UserID { + messageStyle = messageStyle. + MarginLeft(PaddingCount).PaddingLeft(1). + Inherit(PingedBorderStyle).BorderForeground(colors.Gold) + } else if *group[i].Ping == packet.PingEveryone { + messageStyle = messageStyle. + MarginLeft(PaddingCount).PaddingLeft(1). + Inherit(PingedBorderStyle).BorderForeground(colors.Purple) + } else if *group[i].Ping == packet.PingAdmins && members[*state.UserID].IsAdmin { + messageStyle = messageStyle. + MarginLeft(PaddingCount).PaddingLeft(1). + Inherit(PingedBorderStyle).BorderForeground(colors.Red) + } + } + rawContent := group[i].Content content := messageStyle.Render(rawContent) heights[i] = lipgloss.Height(content) @@ -953,6 +1009,23 @@ func (m *Model) renderMessageGroup(group []data.Message, remaining *int, height } style := messageStyle.Background(colors.BackgroundDim) + if m.frequencyIndex != -1 && group[selectedIndex].Ping != nil { + members := state.State.Members[*state.NetworkId(m.networkIndex)] + if *group[selectedIndex].Ping == *state.UserID { + style = style. + MarginLeft(PaddingCount).PaddingLeft(1). + Inherit(PingedBorderStyle).BorderForeground(colors.Gold) + } else if *group[selectedIndex].Ping == packet.PingEveryone { + style = style. + MarginLeft(PaddingCount).PaddingLeft(1). + Inherit(PingedBorderStyle).BorderForeground(colors.Purple) + } else if *group[selectedIndex].Ping == packet.PingAdmins && members[*state.UserID].IsAdmin { + style = style. + MarginLeft(PaddingCount).PaddingLeft(1). + Inherit(PingedBorderStyle).BorderForeground(colors.Red) + } + } + rawContent := group[selectedIndex].Content content := style.Render(rawContent) if group[selectedIndex].Edited { @@ -963,12 +1036,31 @@ func (m *Model) renderMessageGroup(group []data.Message, remaining *int, height content = style.Render(rawContent + SelectedEditedIndicatorNL) } } + content = lipgloss.NewStyle().Background(colors.BackgroundDim).Render(content) buf = append(buf, content...) buf = append(buf, '\n') // Redraw rest for i := selectedIndex - 1; i >= 0; i-- { + messageStyle := messageStyle + if m.frequencyIndex != -1 && group[i].Ping != nil { + members := state.State.Members[*state.NetworkId(m.networkIndex)] + if *group[i].Ping == *state.UserID { + messageStyle = messageStyle. + MarginLeft(PaddingCount).PaddingLeft(1). + Inherit(PingedBorderStyle).BorderForeground(colors.Gold) + } else if *group[i].Ping == packet.PingEveryone { + messageStyle = messageStyle. + MarginLeft(PaddingCount).PaddingLeft(1). + Inherit(PingedBorderStyle).BorderForeground(colors.Purple) + } else if *group[i].Ping == packet.PingAdmins && members[*state.UserID].IsAdmin { + messageStyle = messageStyle. + MarginLeft(PaddingCount).PaddingLeft(1). + Inherit(PingedBorderStyle).BorderForeground(colors.Red) + } + } + rawContent := group[i].Content content := messageStyle.Render(rawContent) heights[i] = lipgloss.Height(content) diff --git a/internal/data/messages.sql.go b/internal/data/messages.sql.go index a3d8257..82909e3 100644 --- a/internal/data/messages.sql.go +++ b/internal/data/messages.sql.go @@ -13,11 +13,11 @@ import ( const createMessage = `-- name: CreateMessage :one INSERT INTO messages ( - id, content, sender_id, frequency_id, receiver_id + id, content, sender_id, frequency_id, receiver_id, ping ) VALUES ( - ?, ?, ?, ?, ? + ?, ?, ?, ?, ?, ? ) -RETURNING id, sender_id, content, edited, frequency_id, receiver_id +RETURNING id, sender_id, content, edited, frequency_id, receiver_id, ping ` type CreateMessageParams struct { @@ -26,6 +26,7 @@ type CreateMessageParams struct { SenderID snowflake.ID FrequencyID *snowflake.ID ReceiverID *snowflake.ID + Ping *snowflake.ID } func (q *Queries) CreateMessage(ctx context.Context, arg CreateMessageParams) (Message, error) { @@ -35,6 +36,7 @@ func (q *Queries) CreateMessage(ctx context.Context, arg CreateMessageParams) (M arg.SenderID, arg.FrequencyID, arg.ReceiverID, + arg.Ping, ) var i Message err := row.Scan( @@ -44,6 +46,7 @@ func (q *Queries) CreateMessage(ctx context.Context, arg CreateMessageParams) (M &i.Edited, &i.FrequencyID, &i.ReceiverID, + &i.Ping, ) return i, err } @@ -63,7 +66,7 @@ UPDATE messages SET edited = true, content = ? WHERE id = ? -RETURNING id, sender_id, content, edited, frequency_id, receiver_id +RETURNING id, sender_id, content, edited, frequency_id, receiver_id, ping ` type EditMessageParams struct { @@ -81,14 +84,15 @@ func (q *Queries) EditMessage(ctx context.Context, arg EditMessageParams) (Messa &i.Edited, &i.FrequencyID, &i.ReceiverID, + &i.Ping, ) return i, err } const getDirectMessages = `-- name: GetDirectMessages :many -SELECT id, sender_id, content, edited, frequency_id, receiver_id FROM messages +SELECT id, sender_id, content, edited, frequency_id, receiver_id, ping FROM messages WHERE - (sender_id = ?1 AND receiver_id = ?2) OR + (sender_id = ?1 AND receiver_id = ?2) OR (sender_id = ?2 AND receiver_id = ?1) ORDER BY id ` @@ -114,6 +118,7 @@ func (q *Queries) GetDirectMessages(ctx context.Context, arg GetDirectMessagesPa &i.Edited, &i.FrequencyID, &i.ReceiverID, + &i.Ping, ); err != nil { return nil, err } @@ -129,7 +134,7 @@ func (q *Queries) GetDirectMessages(ctx context.Context, arg GetDirectMessagesPa } const getFrequencyMessages = `-- name: GetFrequencyMessages :many -SELECT id, sender_id, content, edited, frequency_id, receiver_id FROM messages +SELECT id, sender_id, content, edited, frequency_id, receiver_id, ping FROM messages WHERE frequency_id = ? ORDER BY id ` @@ -150,6 +155,7 @@ func (q *Queries) GetFrequencyMessages(ctx context.Context, frequencyID *snowfla &i.Edited, &i.FrequencyID, &i.ReceiverID, + &i.Ping, ); err != nil { return nil, err } @@ -165,7 +171,7 @@ func (q *Queries) GetFrequencyMessages(ctx context.Context, frequencyID *snowfla } const getMessageById = `-- name: GetMessageById :one -SELECT id, sender_id, content, edited, frequency_id, receiver_id FROM messages +SELECT id, sender_id, content, edited, frequency_id, receiver_id, ping FROM messages WHERE id = ? ` @@ -179,6 +185,7 @@ func (q *Queries) GetMessageById(ctx context.Context, id snowflake.ID) (Message, &i.Edited, &i.FrequencyID, &i.ReceiverID, + &i.Ping, ) return i, err } diff --git a/internal/data/models.go b/internal/data/models.go index 9bc2961..8470e2a 100644 --- a/internal/data/models.go +++ b/internal/data/models.go @@ -41,6 +41,7 @@ type Message struct { Edited bool FrequencyID *snowflake.ID ReceiverID *snowflake.ID + Ping *snowflake.ID } type Network struct { diff --git a/internal/packet/models.go b/internal/packet/models.go index a61c61d..c26d93a 100644 --- a/internal/packet/models.go +++ b/internal/packet/models.go @@ -1,5 +1,7 @@ package packet +import "github.com/kyren223/eko/pkg/snowflake" + const ( MaxNetworkNameBytes = 32 MaxIconBytes = 16 @@ -19,3 +21,8 @@ const ( PermReadWrite PermMax ) + +const ( + PingEveryone = snowflake.ID(0) + PingAdmins = snowflake.ID(1) +) diff --git a/internal/packet/types.go b/internal/packet/types.go index f8e164c..6d0b1dd 100644 --- a/internal/packet/types.go +++ b/internal/packet/types.go @@ -139,6 +139,7 @@ type SendMessage struct { ReceiverID *snowflake.ID FrequencyID *snowflake.ID Content string + Ping *snowflake.ID } func (m *SendMessage) Type() PacketType { diff --git a/internal/server/api/api.go b/internal/server/api/api.go index d7a0ef5..3fff656 100644 --- a/internal/server/api/api.go +++ b/internal/server/api/api.go @@ -71,19 +71,36 @@ func SendMessage(ctx context.Context, sess *session.Session, request *packet.Sen } if frequency.Perms != packet.PermReadWrite && !member.IsAdmin { - log.Println("No perms") return &ErrPermissionDenied } + if request.Ping != nil { + if *request.Ping == packet.PingEveryone { + if !member.IsAdmin { + return &ErrPermissionDenied + } + } else if *request.Ping != packet.PingAdmins { + _, err := queries.GetUserById(ctx, *request.Ping) + if err == sql.ErrNoRows { + return &packet.Error{Error: "pinged user doesn't exist"} + } + if err != nil { + log.Println("database error 2:", err) + return &ErrInternalError + } + } + } + message, err := queries.CreateMessage(ctx, data.CreateMessageParams{ ID: sess.Manager().Node().Generate(), SenderID: sess.ID(), Content: content, FrequencyID: request.FrequencyID, ReceiverID: nil, + Ping: request.Ping, }) if err != nil { - log.Println(sess.Addr(), "database error 2:", err) + log.Println("database error 3:", err) return &ErrInternalError } @@ -105,7 +122,7 @@ func SendMessage(ctx context.Context, sess *session.Session, request *packet.Sen return &packet.Error{Error: "user doesn't exist"} } if err != nil { - log.Println(sess.Addr(), "database error 3:", err) + log.Println("database error 4:", err) return &ErrInternalError } if !user.IsPublicDM { @@ -117,7 +134,7 @@ func SendMessage(ctx context.Context, sess *session.Session, request *packet.Sen return &ErrPermissionDenied } if err != nil { - log.Println(sess.Addr(), "database error 4:", err) + log.Println("database error 5:", err) return &ErrInternalError } if !bytes.Equal(sess.PubKey, pubKey) { @@ -127,13 +144,14 @@ func SendMessage(ctx context.Context, sess *session.Session, request *packet.Sen message, err := queries.CreateMessage(ctx, data.CreateMessageParams{ ID: sess.Manager().Node().Generate(), - SenderID: sess.ID(), Content: content, + SenderID: sess.ID(), FrequencyID: nil, ReceiverID: request.ReceiverID, + Ping: nil, }) if err != nil { - log.Println(sess.Addr(), "database error 5:", err) + log.Println("database error 6:", err) return &ErrInternalError } diff --git a/internal/server/api/migrations/20250127154005_ping.sql b/internal/server/api/migrations/20250127154005_ping.sql new file mode 100644 index 0000000..54f207a --- /dev/null +++ b/internal/server/api/migrations/20250127154005_ping.sql @@ -0,0 +1,8 @@ +-- +goose Up +ALTER TABLE messages ADD ping INTEGER DEFAULT NULL; +-- Must be null if freuqencyId is null +-- 0 - @ping:everyone, 1 - @ping:admins, otherwise references userId + + +-- +goose Down +ALTER TABLE messages DROP ping; |
