summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/client/ui/core/banreason/banreason.go155
-rw-r--r--internal/client/ui/core/core.go24
-rw-r--r--internal/client/ui/core/memberlist/memberlist.go25
-rw-r--r--internal/client/ui/ui.go6
-rw-r--r--internal/packet/models.go1
-rw-r--r--internal/server/api/api.go8
6 files changed, 216 insertions, 3 deletions
diff --git a/internal/client/ui/core/banreason/banreason.go b/internal/client/ui/core/banreason/banreason.go
new file mode 100644
index 0000000..4e62514
--- /dev/null
+++ b/internal/client/ui/core/banreason/banreason.go
@@ -0,0 +1,155 @@
+package banreason
+
+import (
+ tea "github.com/charmbracelet/bubbletea"
+ "github.com/charmbracelet/lipgloss"
+ "github.com/kyren223/eko/internal/client/gateway"
+ "github.com/kyren223/eko/internal/client/ui/colors"
+ "github.com/kyren223/eko/internal/client/ui/core/state"
+ "github.com/kyren223/eko/internal/client/ui/field"
+ "github.com/kyren223/eko/internal/client/ui/layouts/flex"
+ "github.com/kyren223/eko/internal/packet"
+ "github.com/kyren223/eko/pkg/assert"
+ "github.com/kyren223/eko/pkg/snowflake"
+)
+
+var (
+ width = 48
+
+ style = lipgloss.NewStyle().
+ Border(lipgloss.ThickBorder()).
+ Padding(1, 4).
+ Align(lipgloss.Center, lipgloss.Center)
+
+ headerStyle = lipgloss.NewStyle().Foreground(colors.Turquoise)
+
+ fieldBlurredStyle = lipgloss.NewStyle().
+ PaddingLeft(1).
+ Border(lipgloss.RoundedBorder()).
+ BorderForeground(colors.DarkCyan)
+ fieldFocusedStyle = fieldBlurredStyle.
+ BorderForeground(colors.Focus).
+ Border(lipgloss.ThickBorder())
+
+ blurredBanStyle = lipgloss.NewStyle().
+ Background(colors.Gray).Padding(0, 1)
+ focusedBanStyle = lipgloss.NewStyle().
+ Background(colors.Blue).Padding(0, 1)
+)
+
+const (
+ BanReasonField = iota
+ BanField
+ FieldCount
+)
+
+type Model struct {
+ networkId snowflake.ID
+ userId snowflake.ID
+ banReason field.Model
+ banStyle lipgloss.Style
+
+ selected int
+ nameWidth int
+}
+
+func New(userId, networkId snowflake.ID) Model {
+ banReason := field.New(width)
+ banReason.Header = "Ban Reason"
+ banReason.HeaderStyle = headerStyle
+ banReason.FocusedStyle = fieldFocusedStyle
+ banReason.BlurredStyle = fieldBlurredStyle
+ banReason.Input.CharLimit = packet.MaxBanReasonBytes
+ banReason.Focus()
+ nameWidth := lipgloss.Width(banReason.View())
+
+ return Model{
+ networkId: networkId,
+ userId: userId,
+ banReason: banReason,
+ banStyle: blurredBanStyle,
+ selected: 0,
+ nameWidth: nameWidth,
+ }
+}
+
+func (m Model) Init() tea.Cmd {
+ return nil
+}
+
+func (m Model) View() string {
+ name := m.banReason.View()
+ ban := lipgloss.NewStyle().
+ Width(m.nameWidth).Align(lipgloss.Center).
+ Render(m.banStyle.Render("Ban", state.State.Users[m.userId].Name))
+
+ content := flex.NewVertical(name, ban).WithGap(1).View()
+ return style.Render(content)
+}
+
+func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
+ switch msg := msg.(type) {
+ case tea.KeyMsg:
+ key := msg.Type
+ switch key {
+ case tea.KeyTab:
+ return m, m.cycle(1)
+ case tea.KeyShiftTab:
+ return m, m.cycle(-1)
+
+ default:
+ var cmd tea.Cmd
+ switch m.selected {
+ case BanReasonField:
+ m.banReason, cmd = m.banReason.Update(msg)
+ }
+ return m, cmd
+ }
+ }
+
+ return m, nil
+}
+
+func (m *Model) cycle(step int) tea.Cmd {
+ m.selected += step
+ if m.selected < 0 {
+ m.selected = FieldCount - 1
+ } else {
+ m.selected %= FieldCount
+ }
+ return m.updateFocus()
+}
+
+func (m *Model) updateFocus() tea.Cmd {
+ m.banReason.Blur()
+ m.banStyle = blurredBanStyle
+ switch m.selected {
+ case BanReasonField:
+ return m.banReason.Focus()
+ case BanField:
+ m.banStyle = focusedBanStyle
+ return nil
+ default:
+ assert.Never("missing switch statement field in update focus", "selected", m.selected)
+ return nil
+ }
+}
+
+func (m *Model) Select() tea.Cmd {
+ if m.selected != BanField {
+ return nil
+ }
+
+ banReason := m.banReason.Input.Value()
+
+ yes := true
+ return gateway.Send(&packet.SetMember{
+ Member: nil,
+ Admin: nil,
+ Muted: nil,
+ Banned: &yes,
+ BanReason: &banReason,
+ Network: m.networkId,
+ User: m.userId,
+ })
+}
diff --git a/internal/client/ui/core/core.go b/internal/client/ui/core/core.go
index 43695e7..df5fbde 100644
--- a/internal/client/ui/core/core.go
+++ b/internal/client/ui/core/core.go
@@ -14,6 +14,7 @@ import (
"github.com/charmbracelet/lipgloss"
"github.com/kyren223/eko/internal/client/gateway"
"github.com/kyren223/eko/internal/client/ui"
+ "github.com/kyren223/eko/internal/client/ui/core/banreason"
"github.com/kyren223/eko/internal/client/ui/core/chat"
"github.com/kyren223/eko/internal/client/ui/core/frequencycreation"
"github.com/kyren223/eko/internal/client/ui/core/frequencylist"
@@ -71,6 +72,7 @@ type Model struct {
networkJoinPopup *networkjoin.Model
frequencyCreationPopup *frequencycreation.Model
frequencyUpdatePopup *frequencyupdate.Model
+ banReasonPopup *banreason.Model
networkList networklist.Model
frequencyList frequencylist.Model
memberList memberlist.Model
@@ -93,6 +95,7 @@ func New(privKey ed25519.PrivateKey, name string) Model {
networkJoinPopup: nil,
frequencyCreationPopup: nil,
frequencyUpdatePopup: nil,
+ banReasonPopup: nil,
networkList: networklist.New(),
frequencyList: frequencylist.New(),
memberList: memberlist.New(),
@@ -140,6 +143,8 @@ func (m Model) View() string {
popup = m.frequencyUpdatePopup.View()
} else if m.networkJoinPopup != nil {
popup = m.networkJoinPopup.View()
+ } else if m.banReasonPopup != nil {
+ popup = m.banReasonPopup.View()
}
if popup != "" {
x := (ui.Width - lipgloss.Width(popup)) / 2
@@ -296,6 +301,10 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
case *packet.TrustInfo:
state.UpdateTrusteds(msg)
+ case ui.BanPopupMsg:
+ popup := banreason.New(msg.User, msg.Network)
+ m.banReasonPopup = &popup
+
case tea.KeyMsg:
switch msg.String() {
case "n":
@@ -407,6 +416,7 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
m.frequencyCreationPopup = nil
m.frequencyUpdatePopup = nil
m.networkJoinPopup = nil
+ m.banReasonPopup = nil
}
case "enter":
@@ -448,12 +458,17 @@ func (m *Model) updateConnected(msg tea.Msg) tea.Cmd {
m.networkJoinPopup = nil
}
return cmd
+ } else if m.banReasonPopup != nil {
+ cmd := m.banReasonPopup.Select()
+ if cmd != nil {
+ m.banReasonPopup = nil
+ }
+ return cmd
}
default:
isChatLocked := m.focus == FocusChat && m.chat.Locked()
if !m.HasPopup() && !isChatLocked {
-
left := msg.String() == "H"
right := msg.String() == "L"
direction := 0
@@ -562,6 +577,10 @@ func (m *Model) updatePopups(msg tea.Msg) tea.Cmd {
popup, cmd := m.networkJoinPopup.Update(msg)
m.networkJoinPopup = &popup
return cmd
+ } else if m.banReasonPopup != nil {
+ popup, cmd := m.banReasonPopup.Update(msg)
+ m.banReasonPopup = &popup
+ return cmd
}
return nil
}
@@ -573,5 +592,6 @@ func (m *Model) HasPopup() bool {
m.networkUpdatePopup != nil ||
m.frequencyCreationPopup != nil ||
m.frequencyUpdatePopup != nil ||
- m.networkJoinPopup != nil
+ m.networkJoinPopup != nil ||
+ m.banReasonPopup != nil
}
diff --git a/internal/client/ui/core/memberlist/memberlist.go b/internal/client/ui/core/memberlist/memberlist.go
index f42a4ac..beb6807 100644
--- a/internal/client/ui/core/memberlist/memberlist.go
+++ b/internal/client/ui/core/memberlist/memberlist.go
@@ -282,6 +282,31 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
})
case "B":
// TODO: ban
+ networkId := state.NetworkId(m.networkIndex)
+ network := state.State.Networks[*networkId]
+ member := m.Members()[m.index]
+
+ if !m.MembersMap()[*state.UserID].IsAdmin {
+ return m, nil
+ }
+
+ if member.UserID == *state.UserID {
+ return m, nil
+ }
+
+ if member.IsAdmin && network.OwnerID != *state.UserID {
+ return m, nil
+ }
+
+ cmd := func() tea.Msg {
+ return ui.BanPopupMsg{
+ Network: *state.NetworkId(m.networkIndex),
+ User: member.UserID,
+ }
+ }
+ return m, cmd
+ case "b":
+ // TODO: switch to ban list
// Owner
case "D":
diff --git a/internal/client/ui/ui.go b/internal/client/ui/ui.go
index d199fa1..746fdd5 100644
--- a/internal/client/ui/ui.go
+++ b/internal/client/ui/ui.go
@@ -14,6 +14,7 @@ import (
"github.com/kyren223/eko/internal/client/ui/colors"
"github.com/kyren223/eko/pkg/assert"
+ "github.com/kyren223/eko/pkg/snowflake"
)
const (
@@ -51,6 +52,11 @@ func Transition(model tea.Model) tea.Cmd {
type QuitMsg struct{}
+type BanPopupMsg struct {
+ Network snowflake.ID
+ User snowflake.ID
+}
+
func AddBorderHeader(header string, headerOffset int, style lipgloss.Style, render string) string {
b := style.GetBorderStyle()
body := style.UnsetBorderTop().Render(render)
diff --git a/internal/packet/models.go b/internal/packet/models.go
index adf875d..a61c61d 100644
--- a/internal/packet/models.go
+++ b/internal/packet/models.go
@@ -10,6 +10,7 @@ const (
MaxMessageBytes = 2000
MaxUsernameBytes = 32
MaxUserDescriptionBytes = 200
+ MaxBanReasonBytes = 64
)
const (
diff --git a/internal/server/api/api.go b/internal/server/api/api.go
index 1c18ea9..007cce5 100644
--- a/internal/server/api/api.go
+++ b/internal/server/api/api.go
@@ -487,6 +487,12 @@ func DeleteNetwork(ctx context.Context, sess *session.Session, request *packet.D
}
func SetMember(ctx context.Context, sess *session.Session, request *packet.SetMember) packet.Payload {
+ if request.BanReason != nil && len(*request.BanReason) > packet.MaxBanReasonBytes {
+ return &packet.Error{Error: fmt.Sprintf(
+ "Ban reason may not exceed %v bytes", packet.MaxBanReasonBytes,
+ )}
+ }
+
queries := data.New(db)
network, err := queries.GetNetworkById(ctx, request.Network)
@@ -584,7 +590,7 @@ func SetMember(ctx context.Context, sess *session.Session, request *packet.SetMe
isMember = true
}
} else if request.Admin != nil {
- if isSessOwner && request.User != sess.ID() {
+ if isSessOwner && request.User != sess.ID() && isMember {
isAdmin = *request.Admin
}
} else if request.Muted != nil {