Skip to content

Commit

Permalink
Detect guild invite, send help message in DM
Browse files Browse the repository at this point in the history
  • Loading branch information
depado committed Nov 20, 2020
1 parent cbbb4c5 commit e43dbfb
Show file tree
Hide file tree
Showing 18 changed files with 277 additions and 81 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ fox
dockervol/
*.priv
*.db
*.json
8 changes: 4 additions & 4 deletions acl/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package acl
import (
"fmt"

"github.com/Depado/fox/guild"
"github.com/Depado/fox/models"
"github.com/Depado/fox/storage"
"github.com/bwmarrin/discordgo"
)
Expand Down Expand Up @@ -36,7 +36,7 @@ func NewACL(s *storage.StormDB) *ACL {
// Check will perform checks for the given RoleRestriction and
// ChannelRestriction.
func (a ACL) Check(s *discordgo.Session, m *discordgo.Message, r RoleRestriction, c ChannelRestriction) (bool, error) {
var gc *guild.Conf
var gc *models.Conf
var err error
var rc bool

Expand Down Expand Up @@ -84,12 +84,12 @@ func (a ACL) Check(s *discordgo.Session, m *discordgo.Message, r RoleRestriction
}

// IsMusic will check if the provided message was sent to the music channel.
func (a ACL) IsMusic(m *discordgo.Message, gc *guild.Conf) bool {
func (a ACL) IsMusic(m *discordgo.Message, gc *models.Conf) bool {
return m.ChannelID == gc.TextChannel
}

// IsPrivileged will check if a member is either admin or DJ.
func (a ACL) IsPrivileged(s *discordgo.Session, m *discordgo.Message, gc *guild.Conf) (bool, error) {
func (a ACL) IsPrivileged(s *discordgo.Session, m *discordgo.Message, gc *models.Conf) (bool, error) {
adm, err := a.IsAdmin(s, m)
if err != nil {
return false, fmt.Errorf("check admin: %w", err)
Expand Down
19 changes: 16 additions & 3 deletions acl/display.go
Original file line number Diff line number Diff line change
@@ -1,29 +1,42 @@
package acl

import "fmt"

// RoleRestrictionString returns a user-friendly representation of the role
// restriction
func RoleRestrictionString(r RoleRestriction) string {
var rr string

switch r {
case Admin:
rr = "🔐 Admin"
rr = "🔐 Admin only"
case Privileged:
rr = "🔒 Admin or DJ"
case Anyone:
rr = "🔓 No restriction"
rr = "🔓 No role restriction"
}

return rr
}

// ChannelRestrictionString returns a user-friendly representation of the
// channel restriction
func ChannelRestrictionString(c ChannelRestriction) string {
var cr string

switch c {
case Music:
cr = "🎶 Music text channel only"
case Anywhere:
cr = "🌍 No restriction"
cr = "🌍 No channel restriction"
}

return cr
}

// RestrictionString returns a user-friendly representation of an restriction
// pair
func RestrictionString(c ChannelRestriction, r RoleRestriction) string {
return fmt.Sprintf("%s\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0%s",
ChannelRestrictionString(c), RoleRestrictionString(r))
}
17 changes: 9 additions & 8 deletions bot/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package bot

import (
"fmt"
"time"

"github.com/Depado/fox/message"
"github.com/bwmarrin/discordgo"
Expand All @@ -12,10 +11,7 @@ import (
func (b *Bot) DisplayCommandHelp(s *discordgo.Session, m *discordgo.MessageCreate, cmd string) {
c, ok := b.commands.Get(cmd)
if !ok {
err := message.SendTimedReply(s, m.Message, "", "Unknown command", "", 5*time.Second)
if err != nil {
b.log.Err(err).Msg("unable to send timed reply")
}
message.SendShortTimedNotice(s, m.Message, fmt.Sprintf("Unknown command %s", cmd), b.log)
return
}
c.DisplayHelp(s, m.Message, b.conf.Bot.Prefix)
Expand All @@ -25,10 +21,10 @@ func (b *Bot) DisplayCommandHelp(s *discordgo.Session, m *discordgo.MessageCreat
// global help
func (b *Bot) DisplayGlobalHelp(s *discordgo.Session, m *discordgo.MessageCreate) {
e := &discordgo.MessageEmbed{
Title: "Fox Help",
Title: "Fox Help",
Description: fmt.Sprintf(
"Fox is a music bot. To interact with it, use `%s <command>` where "+
"`command` is one of the following commands. To get more details "+
"`command` is one of the following commands.\nTo get more details "+
"about a given command, you can also use `%s help <command>`",
b.conf.Bot.Prefix, b.conf.Bot.Prefix),
Color: 0xff5500,
Expand All @@ -45,7 +41,12 @@ func (b *Bot) DisplayGlobalHelp(s *discordgo.Session, m *discordgo.MessageCreate
}
e.Fields = fields

if _, err := s.ChannelMessageSendEmbed(m.ChannelID, e); err != nil {
uc, err := s.UserChannelCreate(m.Author.ID)
if err != nil {
b.log.Err(err).Msg("unable to get create channel DM for user")
return
}
if _, err := s.ChannelMessageSendEmbed(uc.ID, e); err != nil {
b.log.Err(err).Msg("unable to send reply")
}
}
13 changes: 11 additions & 2 deletions bot/message.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ func (b *Bot) MessageCreatedHandler(s *discordgo.Session, m *discordgo.MessageCr
message.Delete(s, m.Message, b.log)
return
}
opts := c.Opts()

// Check if DM and if so, check if the command has DM capability
if m.GuildID == "" && !opts.DMCapability {
err := message.SendReply(s, m.Message, "", "Commands must be executed in a server channel.\nThe only exception is the `help` command.", "")
if err != nil {
b.log.Err(err).Msg("unable to send reply")
}
return
}

// Check permissions
cr, rr := c.ACL()
Expand All @@ -59,14 +69,13 @@ func (b *Bot) MessageCreatedHandler(s *discordgo.Session, m *discordgo.MessageCr
return
}
if !ok {
msg := fmt.Sprintf("You do not have permission to do that.\n%s\n%s", acl.RoleRestrictionString(rr), acl.ChannelRestrictionString(cr))
msg := fmt.Sprintf("You do not have permission to do that.\n**%s**", acl.RestrictionString(cr, rr))
message.SendShortTimedNotice(s, m.Message, msg, b.log)
message.Delete(s, m.Message, b.log)
return
}

// Act on command options
opts := c.Opts()
if opts.ArgsRequired && len(args) == 0 {
msg := fmt.Sprintf(
"The `%s` command requires additional arguments.\nType `%s help %s` to view this command's help page",
Expand Down
50 changes: 39 additions & 11 deletions commands/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ type Command interface {
type Options struct {
ArgsRequired bool
DeleteUserMessage bool
DMCapability bool
}

type SubCommand struct {
Long string
Aliases []string
Arg string
Description string
}

type Example struct {
Expand Down Expand Up @@ -69,9 +77,10 @@ type BaseCommand struct {
Options Options

// Internal fields
Help Help
Players *player.Players
log zerolog.Logger
SubCommands []SubCommand
Help Help
Players *player.Players
log zerolog.Logger
}

func (c BaseCommand) ACL() (acl.ChannelRestriction, acl.RoleRestriction) {
Expand All @@ -92,13 +101,26 @@ func (c BaseCommand) GetHelp() Help {

func (c BaseCommand) DisplayHelp(s *discordgo.Session, m *discordgo.Message, prefix string) {
desc := c.Help.Description
if len(c.SubCommands) > 0 {
desc += "\n\n__**Subcommands**__"
for _, sc := range c.SubCommands {
desc += fmt.Sprintf("\n\n`%s", sc.Long)
for _, a := range sc.Aliases {
desc += fmt.Sprintf("/%s", a)
}
if sc.Arg != "" {
desc += fmt.Sprintf(" <%s>", sc.Arg)
}
desc += "`"
if sc.Description != "" {
desc += "\n" + sc.Description
}
}
}
desc += "\n\n__**Restrictions**__\n\n"
desc += fmt.Sprintf(
"\n\nChannel Restriction\n**%s**",
acl.ChannelRestrictionString(c.ChannelRestriction),
)
desc += fmt.Sprintf(
"\n\nRole Restriction\n**%s**",
acl.RoleRestrictionString(c.RoleRestriction),
"**%s\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0%s**",
acl.ChannelRestrictionString(c.ChannelRestriction), acl.RoleRestrictionString(c.RoleRestriction),
)

var aliases string
Expand All @@ -113,7 +135,7 @@ func (c BaseCommand) DisplayHelp(s *discordgo.Session, m *discordgo.Message, pre
}

if len(c.Help.Examples) > 0 {
desc += "\n\n**Examples:**"
desc += "\n\n__**Examples**__"
fields := []*discordgo.MessageEmbedField{}
for _, e := range c.Help.Examples {
fields = append(fields, &discordgo.MessageEmbedField{
Expand All @@ -124,7 +146,13 @@ func (c BaseCommand) DisplayHelp(s *discordgo.Session, m *discordgo.Message, pre
}
e.Description = desc

if _, err := s.ChannelMessageSendEmbed(m.ChannelID, e); err != nil {
uc, err := s.UserChannelCreate(m.Author.ID)
if err != nil {
c.log.Err(err).Msg("unable to get channel to DM user")
return
}

if _, err := s.ChannelMessageSendEmbed(uc.ID, e); err != nil {
c.log.Err(err).Msg("unable to send embed")
}
}
67 changes: 67 additions & 0 deletions commands/fav.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package commands

import (
"github.com/bwmarrin/discordgo"
"github.com/rs/zerolog"

"github.com/Depado/fox/acl"
"github.com/Depado/fox/player"
"github.com/Depado/fox/storage"
)

type fav struct {
BaseCommand
Storage *storage.StormDB
}

func (c *fav) Handler(s *discordgo.Session, m *discordgo.Message, args []string) {
if len(args) == 0 {
// Save
}
if len(args) > 0 {
switch args[0] {
case "show", "s":
// Show favlist
case "clear", "c":
// Clear favlist
default:

}
}
}

func NewFavCommand(p *player.Players, log zerolog.Logger, storage *storage.StormDB) Command {
cmd := "fav"
return &fav{
BaseCommand: BaseCommand{
ChannelRestriction: acl.Anywhere,
RoleRestriction: acl.Anyone,
Options: Options{
ArgsRequired: false,
DeleteUserMessage: true,
},
Long: cmd,
Aliases: []string{"f"},
SubCommands: []SubCommand{
{Long: "show", Aliases: []string{"s"}, Description: "Send your fav list in DM"},
{Long: "clear", Aliases: []string{"c"}, Description: "Clear your fav list"},
},
Help: Help{
Usage: cmd,
ShortDesc: "Display or modify your favorite sound list",
Description: "This command allows you to save the currently " +
"playing track to your own favorite list. You can then access " +
"your list using the `show/s` subcommand, or clear it up using " +
"the `clear/c` subcommand.",
Examples: []Example{
{Command: "fav", Explanation: "Add the currently playing track to your fav list"},
{Command: "fav show", Explanation: "Send your fav list in DM"},
{Command: "fav clear", Explanation: "Clear up your fav list"},
},
},
Players: p,
log: log.With().Str("command", cmd).Logger(),
},
Storage: storage,
}
}
3 changes: 3 additions & 0 deletions commands/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,9 @@ func NewNowPlayingCommand(p *player.Players, log zerolog.Logger) Command {
},
Long: cmd,
Aliases: []string{"np"},
SubCommands: []SubCommand{
{Long: "full", Aliases: []string{"f"}, Description: "Display all the available information"},
},
Help: Help{
Usage: cmd,
ShortDesc: "Display the currently playing track",
Expand Down
18 changes: 11 additions & 7 deletions commands/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"strings"

"github.com/Depado/fox/acl"
"github.com/Depado/fox/guild"
"github.com/Depado/fox/message"
"github.com/Depado/fox/models"
"github.com/Depado/fox/player"
"github.com/Depado/fox/storage"
"github.com/bwmarrin/discordgo"
Expand All @@ -19,9 +19,9 @@ type setup struct {
Storage *storage.StormDB
}

func (c *setup) handleVoiceChannel(s *discordgo.Session, m *discordgo.Message, gconf *guild.Conf, value string) {
func (c *setup) handleVoiceChannel(s *discordgo.Session, m *discordgo.Message, gconf *models.Conf, value string) {
if err := gconf.SetChannel(s, value, true); err != nil {
if errors.Is(err, guild.ChannelNotFoundError) {
if errors.Is(err, models.ChannelNotFoundError) {
message.SendShortTimedNotice(s, m, "I couldn't find any vocal channel named like this", c.log)
return
}
Expand All @@ -31,9 +31,9 @@ func (c *setup) handleVoiceChannel(s *discordgo.Session, m *discordgo.Message, g
message.SendShortTimedNotice(s, m, "Alright, I'll stream the music to this channel from now on", c.log)
}

func (c *setup) handleTextChannel(s *discordgo.Session, m *discordgo.Message, gconf *guild.Conf, value string) {
func (c *setup) handleTextChannel(s *discordgo.Session, m *discordgo.Message, gconf *models.Conf, value string) {
if err := gconf.SetChannel(s, value, false); err != nil {
if errors.Is(err, guild.ChannelNotFoundError) {
if errors.Is(err, models.ChannelNotFoundError) {
message.SendShortTimedNotice(s, m, "I couldn't find any text channel named like this", c.log)
return
}
Expand All @@ -45,10 +45,10 @@ func (c *setup) handleTextChannel(s *discordgo.Session, m *discordgo.Message, gc

func (c *setup) Handler(s *discordgo.Session, m *discordgo.Message, args []string) {
var err error
var gconf *guild.Conf
var gconf *models.Conf

if gconf, err = c.Storage.GetGuilConf(m.GuildID); err != nil {
c.log.Err(err).Msg("unable to fetch guild state")
c.log.Err(err).Msg("unable to fetch guild conf")
return
}

Expand Down Expand Up @@ -92,6 +92,10 @@ func NewSetupCommand(p *player.Players, log zerolog.Logger, storage *storage.Sto
ArgsRequired: false,
DeleteUserMessage: true,
},
SubCommands: []SubCommand{
{Long: "voice", Arg: "voice channel name", Description: "Setup the voice channel"},
{Long: "text", Arg: "text channel name", Description: "Setup the text channel"},
},
Long: cmd,
Help: Help{
Usage: cmd,
Expand Down
Loading

0 comments on commit e43dbfb

Please sign in to comment.