mirror of
https://github.com/diamondburned/cchat-discord.git
synced 2024-12-22 20:36:45 +00:00
Added folders and categories, markup improvements, bug fixes
This commit is contained in:
parent
8b9b46317b
commit
dac771656e
67
category.go
Normal file
67
category.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
package discord
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/diamondburned/arikawa/discord"
|
||||
"github.com/diamondburned/cchat"
|
||||
"github.com/diamondburned/cchat/text"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Category struct {
|
||||
id discord.Snowflake
|
||||
guildID discord.Snowflake
|
||||
session *Session
|
||||
}
|
||||
|
||||
var (
|
||||
_ cchat.Server = (*Category)(nil)
|
||||
_ cchat.ServerList = (*Category)(nil)
|
||||
)
|
||||
|
||||
func NewCategory(s *Session, ch discord.Channel) *Category {
|
||||
return &Category{
|
||||
id: ch.ID,
|
||||
guildID: ch.GuildID,
|
||||
session: s,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Category) ID() string {
|
||||
return c.id.String()
|
||||
}
|
||||
|
||||
func (c *Category) Name() text.Rich {
|
||||
t, err := c.session.Channel(c.id)
|
||||
if err != nil {
|
||||
// This shouldn't happen.
|
||||
return text.Rich{Content: c.id.String()}
|
||||
}
|
||||
|
||||
return text.Rich{
|
||||
Content: t.Name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Category) Servers(container cchat.ServersContainer) error {
|
||||
t, err := c.session.Channels(c.guildID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to get channels")
|
||||
}
|
||||
|
||||
// Filter out channels with this category ID.
|
||||
var chs = filterAccessible(c.session, filterCategory(t, c.id))
|
||||
|
||||
sort.Slice(chs, func(i, j int) bool {
|
||||
return chs[i].Position < chs[j].Position
|
||||
})
|
||||
|
||||
var chv = make([]cchat.Server, len(chs))
|
||||
for i := range chs {
|
||||
chv[i] = NewChannel(c.session, chs[i])
|
||||
}
|
||||
|
||||
container.SetServers(chv)
|
||||
return nil
|
||||
}
|
44
channel.go
44
channel.go
|
@ -12,6 +12,50 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func chGuildCheck(chType discord.ChannelType) bool {
|
||||
switch chType {
|
||||
case discord.GuildCategory, discord.GuildText:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func filterAccessible(s *Session, chs []discord.Channel) []discord.Channel {
|
||||
u, err := s.Me()
|
||||
if err != nil {
|
||||
// Shouldn't happen.
|
||||
return chs
|
||||
}
|
||||
|
||||
filtered := chs[:0]
|
||||
|
||||
for _, ch := range chs {
|
||||
p, err := s.Permissions(ch.ID, u.ID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if p.Has(discord.PermissionViewChannel) {
|
||||
filtered = append(filtered, ch)
|
||||
}
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
func filterCategory(chs []discord.Channel, catID discord.Snowflake) []discord.Channel {
|
||||
var filtered = chs[:0]
|
||||
|
||||
for _, ch := range chs {
|
||||
if ch.CategoryID == catID && chGuildCheck(ch.Type) {
|
||||
filtered = append(filtered, ch)
|
||||
}
|
||||
}
|
||||
|
||||
return filtered
|
||||
}
|
||||
|
||||
type Channel struct {
|
||||
id discord.Snowflake
|
||||
guildID discord.Snowflake
|
||||
|
|
6
go.mod
6
go.mod
|
@ -2,13 +2,11 @@ module github.com/diamondburned/cchat-discord
|
|||
|
||||
go 1.14
|
||||
|
||||
replace github.com/diamondburned/ningen => ../../ningen/
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/diamondburned/arikawa v0.9.4
|
||||
github.com/diamondburned/arikawa v0.9.5
|
||||
github.com/diamondburned/cchat v0.0.31
|
||||
github.com/diamondburned/ningen v0.0.0-20200618230530-16d4d7fbc521
|
||||
github.com/diamondburned/ningen v0.1.0
|
||||
github.com/go-test/deep v1.0.6
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/yuin/goldmark v1.1.30
|
||||
|
|
8
go.sum
8
go.sum
|
@ -3,6 +3,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||
github.com/diamondburned/arikawa v0.8.7-0.20200522214036-530bff74a2c6/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/arikawa v0.9.4 h1:Mrp0Vz9R2afbvhWS6m/oLIQy22/uxXb459LUv7qrZPA=
|
||||
github.com/diamondburned/arikawa v0.9.4/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/arikawa v0.9.5-0.20200619075944-01021f09025b h1:fTR1esGjH+rR3ssd2vlZoxYLtML29paO0JjRV2lB3s0=
|
||||
github.com/diamondburned/arikawa v0.9.5-0.20200619075944-01021f09025b/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/arikawa v0.9.5 h1:P1ffsp+NHT22wWKYFVC8CdlGRLzPuUV9FcCBKOCJpCI=
|
||||
github.com/diamondburned/arikawa v0.9.5/go.mod h1:nIhVIatzTQhPUa7NB8w4koG1RF9gYbpAr8Fj8sKq660=
|
||||
github.com/diamondburned/cchat v0.0.26 h1:QBt4d65uzUPJz3jF8b2pJ09Jz8LeBRyG2ol47FOy0g0=
|
||||
github.com/diamondburned/cchat v0.0.26/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/cchat v0.0.28 h1:+1VnltW0rl8/NZTUP+x89jVhi3YTTR+e6iLprZ7HcwM=
|
||||
|
@ -11,6 +15,10 @@ github.com/diamondburned/cchat v0.0.31 h1:yUgrh5xbGX0R55glyxYtVewIDL2eXLJ+okIEfV
|
|||
github.com/diamondburned/cchat v0.0.31/go.mod h1:+zXktogE45A0om4fT6B/z6Ii7FXNafjxsNspI0rlhbU=
|
||||
github.com/diamondburned/ningen v0.0.0-20200610212436-159f7105a2be h1:mUw8X/YzJGFSdL8y3Q/XqyzqPyIMNVSDyZGOP3JXgJA=
|
||||
github.com/diamondburned/ningen v0.0.0-20200610212436-159f7105a2be/go.mod h1:B2hq2B4va1MlnMmXuv9vXmyu9gscxJLmwrmcSB1Les8=
|
||||
github.com/diamondburned/ningen v0.0.0-20200619080103-03201e09d2a9 h1:KmmKgOVCXiRufPhBWlGpSILM6ZAUvgATMelQfYNpZIw=
|
||||
github.com/diamondburned/ningen v0.0.0-20200619080103-03201e09d2a9/go.mod h1:Oxl8JrIoyo/OTx2xq9DnvvkJ3V3fUeI6cftO4LmNX84=
|
||||
github.com/diamondburned/ningen v0.1.0 h1:cTnRNrN0g2Wr/kgjLLpa3pqlbEd6JPNa1yGDer8uV4U=
|
||||
github.com/diamondburned/ningen v0.1.0/go.mod h1:1vi8mlBlM2xjJy+IugU51q+IMgyNXggS4Xv3SPFd2Q4=
|
||||
github.com/go-test/deep v1.0.6 h1:UHSEyLZUwX9Qoi99vVwvewiMC8mM2bf7XEM2nqvzEn8=
|
||||
github.com/go-test/deep v1.0.6/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
|
||||
github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY=
|
||||
|
|
100
guild.go
100
guild.go
|
@ -2,13 +2,83 @@ package discord
|
|||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/diamondburned/arikawa/discord"
|
||||
"github.com/diamondburned/arikawa/gateway"
|
||||
"github.com/diamondburned/cchat"
|
||||
"github.com/diamondburned/cchat-discord/segments"
|
||||
"github.com/diamondburned/cchat/text"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type GuildFolder struct {
|
||||
gateway.GuildFolder
|
||||
session *Session
|
||||
}
|
||||
|
||||
var (
|
||||
_ cchat.Server = (*Guild)(nil)
|
||||
_ cchat.ServerList = (*Guild)(nil)
|
||||
)
|
||||
|
||||
func NewGuildFolder(s *Session, gf gateway.GuildFolder) *GuildFolder {
|
||||
// Name should never be empty.
|
||||
if gf.Name == "" {
|
||||
var names = make([]string, 0, len(gf.GuildIDs))
|
||||
|
||||
for _, id := range gf.GuildIDs {
|
||||
if g, _ := s.Store.Guild(id); g != nil {
|
||||
names = append(names, g.Name)
|
||||
}
|
||||
}
|
||||
|
||||
gf.Name = strings.Join(names, ", ")
|
||||
}
|
||||
|
||||
return &GuildFolder{
|
||||
GuildFolder: gf,
|
||||
session: s,
|
||||
}
|
||||
}
|
||||
|
||||
func (gf *GuildFolder) ID() string {
|
||||
return gf.GuildFolder.ID.String()
|
||||
}
|
||||
|
||||
func (gf *GuildFolder) Name() text.Rich {
|
||||
var name = text.Rich{
|
||||
// 1en space for style.
|
||||
Content: gf.GuildFolder.Name,
|
||||
}
|
||||
|
||||
if gf.GuildFolder.Color > 0 {
|
||||
name.Segments = []text.Segment{
|
||||
// The length of this black box is actually 3. Mind == blown.
|
||||
segments.NewColored(len(name.Content), gf.GuildFolder.Color.Uint32()),
|
||||
}
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func (gf *GuildFolder) Servers(container cchat.ServersContainer) error {
|
||||
var servers = make([]cchat.Server, len(gf.GuildIDs))
|
||||
|
||||
for i, id := range gf.GuildIDs {
|
||||
g, err := gf.session.Guild(id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to get guild ID "+id.String())
|
||||
}
|
||||
|
||||
servers[i] = NewGuild(gf.session, g)
|
||||
}
|
||||
|
||||
container.SetServers(servers)
|
||||
return nil
|
||||
}
|
||||
|
||||
type Guild struct {
|
||||
id discord.Snowflake
|
||||
session *Session
|
||||
|
@ -27,6 +97,15 @@ func NewGuild(s *Session, g *discord.Guild) *Guild {
|
|||
}
|
||||
}
|
||||
|
||||
func NewGuildFromID(s *Session, gID discord.Snowflake) (*Guild, error) {
|
||||
g, err := s.Guild(gID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewGuild(s, g), nil
|
||||
}
|
||||
|
||||
func (g *Guild) self(ctx context.Context) (*discord.Guild, error) {
|
||||
return g.session.WithContext(ctx).Guild(g.id)
|
||||
}
|
||||
|
@ -68,11 +147,24 @@ func (g *Guild) Servers(container cchat.ServersContainer) error {
|
|||
return errors.Wrap(err, "Failed to get channels")
|
||||
}
|
||||
|
||||
var channels = make([]cchat.Server, len(c))
|
||||
for i := range c {
|
||||
channels[i] = NewChannel(g.session, c[i])
|
||||
// Only get top-level channels (those with category ID being null).
|
||||
var toplevels = filterAccessible(g.session, filterCategory(c, discord.NullSnowflake))
|
||||
|
||||
sort.Slice(toplevels, func(i, j int) bool {
|
||||
return toplevels[i].Position < toplevels[j].Position
|
||||
})
|
||||
|
||||
var chs = make([]cchat.Server, 0, len(toplevels))
|
||||
|
||||
for _, ch := range toplevels {
|
||||
switch ch.Type {
|
||||
case discord.GuildCategory:
|
||||
chs = append(chs, NewCategory(g.session, ch))
|
||||
case discord.GuildText:
|
||||
chs = append(chs, NewChannel(g.session, ch))
|
||||
}
|
||||
}
|
||||
|
||||
container.SetServers(channels)
|
||||
container.SetServers(chs)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ func NewUser(u discord.User) Author {
|
|||
return Author{
|
||||
id: u.ID,
|
||||
name: text.Rich{Content: u.Username},
|
||||
avatar: u.AvatarURL() + "?size=128",
|
||||
avatar: u.AvatarURL(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ func NewGuildMember(m discord.Member, g discord.Guild) Author {
|
|||
return Author{
|
||||
id: m.User.ID,
|
||||
name: name,
|
||||
avatar: m.User.AvatarURL() + "?size=128",
|
||||
avatar: m.User.AvatarURL(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ func RenderNode(source []byte, n ast.Node) text.Rich {
|
|||
ast.Walk(n, r.renderNode)
|
||||
|
||||
return text.Rich{
|
||||
Content: string(bytes.TrimSpace(buf.Bytes())),
|
||||
Content: buf.String(),
|
||||
Segments: r.segs,
|
||||
}
|
||||
}
|
||||
|
@ -57,14 +57,17 @@ func (r *TextRenderer) i() int {
|
|||
|
||||
// startBlock guarantees enough indentation to start a new block.
|
||||
func (r *TextRenderer) startBlock() {
|
||||
var maxNewlines = 2
|
||||
var maxNewlines = 0
|
||||
|
||||
// Peek twice.
|
||||
if r.peekLast(0) == '\n' {
|
||||
maxNewlines--
|
||||
// Peek twice. If the last character is already a new line or we're only at
|
||||
// the start of line (length 0), then don't pad.
|
||||
if r.buf.Len() > 0 {
|
||||
if r.peekLast(0) != '\n' {
|
||||
maxNewlines++
|
||||
}
|
||||
if r.peekLast(1) != '\n' {
|
||||
maxNewlines++
|
||||
}
|
||||
if r.peekLast(1) == '\n' {
|
||||
maxNewlines--
|
||||
}
|
||||
|
||||
// Write the padding.
|
||||
|
|
64
service.go
64
service.go
|
@ -133,7 +133,59 @@ func (s *Session) Icon(ctx context.Context, iconer cchat.IconContainer) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) Disconnect() error {
|
||||
return s.Close()
|
||||
}
|
||||
|
||||
func (s *Session) Save() (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"token": s.Token,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Session) Servers(container cchat.ServersContainer) error {
|
||||
switch {
|
||||
// If the user has guild folders:
|
||||
case len(s.Ready.Settings.GuildFolders) > 0:
|
||||
// TODO: account for missing guilds.
|
||||
var toplevels = make([]cchat.Server, 0, len(s.Ready.Settings.GuildFolders))
|
||||
|
||||
for _, folder := range s.Ready.Settings.GuildFolders {
|
||||
// TODO: correct.
|
||||
switch {
|
||||
case folder.ID.Valid():
|
||||
fallthrough
|
||||
case len(folder.GuildIDs) > 1:
|
||||
toplevels = append(toplevels, NewGuildFolder(s, folder))
|
||||
|
||||
case len(folder.GuildIDs) == 1:
|
||||
g, err := NewGuildFromID(s, folder.GuildIDs[0])
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to get guild in folder")
|
||||
}
|
||||
toplevels = append(toplevels, g)
|
||||
}
|
||||
}
|
||||
|
||||
container.SetServers(toplevels)
|
||||
|
||||
// If the user doesn't have guild folders but has sorted their guilds
|
||||
// before:
|
||||
case len(s.Ready.Settings.GuildPositions) > 0:
|
||||
var guilds = make([]cchat.Server, 0, len(s.Ready.Settings.GuildPositions))
|
||||
|
||||
for _, id := range s.Ready.Settings.GuildPositions {
|
||||
g, err := NewGuildFromID(s, id)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to get guild in position")
|
||||
}
|
||||
guilds = append(guilds, g)
|
||||
}
|
||||
|
||||
container.SetServers(guilds)
|
||||
|
||||
// None of the above:
|
||||
default:
|
||||
g, err := s.Guilds()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -145,15 +197,7 @@ func (s *Session) Servers(container cchat.ServersContainer) error {
|
|||
}
|
||||
|
||||
container.SetServers(servers)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) Disconnect() error {
|
||||
return s.Close()
|
||||
}
|
||||
|
||||
func (s *Session) Save() (map[string]string, error) {
|
||||
return map[string]string{
|
||||
"token": s.Token,
|
||||
}, nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue