Skip to content

Commit

Permalink
Added support for 20k chars long ccs for premium servers (#1641)
Browse files Browse the repository at this point in the history
Co-authored-by: Ashish Jhanwar <[email protected]>
  • Loading branch information
ashishjh-bst and ashishjh-bst authored Apr 19, 2024
1 parent ac517d1 commit 11fd926
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 202 deletions.
6 changes: 3 additions & 3 deletions customcommands/assets/customcommands-editcmd.html
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ <h2 class="card-title">
<div class="col-lg-12">
<div class="form-group">
<label for="responses">Response (<span
class="cc-length-counter">x</span>/10000)</label>
class="cc-length-counter">x</span>/{{.MaxCCLength}})</label>
<!-- Use .btn-add for simplicity and let the page loader adjust. -->
{{range .CC.Responses}}
<div id="cc-responses" class="entry input-group input-group-sm">
Expand Down Expand Up @@ -659,8 +659,8 @@ <h2 class="card-title">Custom Command Information</h2>

var display = document.querySelector(".cc-length-counter")
display.textContent = combinedLength

if (combinedLength > 10000) {
if (combinedLength > {{.MaxCCLength}}) {
display.classList.add("text-danger");
} else {
display.classList.remove("text-danger");
Expand Down
8 changes: 4 additions & 4 deletions customcommands/assets/customcommands-public.html
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ <h2 class="card-title">
<div class="row mb-2">
<div class="col-lg-12">
<div class="form-group">
<label for="responses">Response (<span class="cc-length-counter">x</span>/10000)</label>
<label for="responses">Total Response Length: <span class="cc-length-counter">x</span> <br/><span id="premium-only-import"><span></label>
{{range $i, $r := .CC.Responses}}
<div id="cc-responses" class="entry input-group input-group-sm">
<textarea id="response-{{$i}}" class="form-control response-text-area tab-textbox cc-editor" id=""
Expand Down Expand Up @@ -334,10 +334,10 @@ <h2 class="card-title">WARNING: IMPORTING A CUSTOM COMMAND</h2>
var display = document.querySelector(".cc-length-counter")
display.textContent = combinedLength

var premiumOnlyImport = document.querySelector("#premium-only-import")
if (combinedLength > 10000) {
display.classList.add("text-danger");
} else {
display.classList.remove("text-danger");
premiumOnlyImport.textContent = "This CC can only be imported to Premium servers, as it exceeds Free server limits.";
premiumOnlyImport.classList.add("text-danger");
}
}
function isTextTrigger(t) {
Expand Down
7 changes: 7 additions & 0 deletions customcommands/assets/customcommands.html
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ <h2 class="card-title">
<link rel="stylesheet" href="/static/vendorr/highlightjs/atom-one-dark.css">

<script>
$(function () {
let search = new URLSearchParams(window.location.search);
if (search.has('import_err') && search.get('import_err') == 'true') {
alert('Failed to import command, please check the url or the command itself.');
window.location.search = '';
}
})

// Register the custom language
// its based off markdown with custom stuff in tags
Expand Down
17 changes: 7 additions & 10 deletions customcommands/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,10 @@ func (p *Plugin) OnRemovedPremiumGuild(GuildID int64) error {
return errors.WrapIf(err, "Failed disabling trigger on edits on premium removal")
}

_, err = models.CustomCommands(qm.Where("guild_id = ? AND length(regexp_replace(array_to_string(responses, ''), E'\\r', '', 'g')) > ?", GuildID, MaxCCResponsesLength)).UpdateAllG(context.Background(), models.M{"disabled": true})
if err != nil {
return errors.WrapIf(err, "Failed disabling long customs commands on premium removal")
}
return nil
}

Expand Down Expand Up @@ -654,7 +658,7 @@ func HandleMessageUpdate(evt *eventsystem.EventData) {
mu := evt.MessageUpdate()
cs := evt.CSOrThread()

if isPremium, _ := premium.IsGuildPremiumCached(mu.GuildID); !isPremium {
if isPremium, _ := premium.IsGuildPremium(mu.GuildID); !isPremium {
return
}

Expand Down Expand Up @@ -769,7 +773,7 @@ func findMessageTriggerCustomCommands(ctx context.Context, cs *dstate.ChannelSta
sortTriggeredCCs(matched)

limit := CCMessageExecLimitNormal
if isPremium, _ := premium.IsGuildPremiumCached(msg.GuildID); isPremium {
if isPremium, _ := premium.IsGuildPremium(msg.GuildID); isPremium {
limit = CCMessageExecLimitPremium
}

Expand Down Expand Up @@ -827,7 +831,7 @@ func findReactionTriggerCustomCommands(ctx context.Context, cs *dstate.ChannelSt
sortTriggeredCCs(filtered)

limit := CCMessageExecLimitNormal
if isPremium, _ := premium.IsGuildPremiumCached(cs.GuildID); isPremium {
if isPremium, _ := premium.IsGuildPremium(cs.GuildID); isPremium {
limit = CCMessageExecLimitPremium
}

Expand Down Expand Up @@ -1128,13 +1132,6 @@ func updatePostCommandRan(cmd *models.CustomCommand, runErr error) {
if err != nil {
logger.WithError(err).WithField("guild", cmd.GuildID).Error("failed running post command executed query")
}

// if runErr != nil {
// err := pubsub.Publish("custom_commands_clear_cache", cmd.GuildID, nil)
// if err != nil {
// logger.WithError(err).Error("failed creating cache eviction pubsub event in updatePostCommandRan")
// }
// }
}

// CheckMatch returns true if the given cmd matches, as well as the arguments
Expand Down
133 changes: 38 additions & 95 deletions customcommands/customcommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"encoding/json"
"fmt"
"math"
"sort"
"strings"
"unicode/utf8"

Expand All @@ -20,7 +19,6 @@ import (
"github.com/botlabs-gg/yagpdb/v2/premium"
"github.com/botlabs-gg/yagpdb/v2/web"
"github.com/karlseguin/ccache"
"github.com/mediocregopher/radix/v3"
"github.com/volatiletech/null/v8"
"github.com/volatiletech/sqlboiler/v4/queries/qm"
)
Expand Down Expand Up @@ -72,8 +70,8 @@ const (
CommandTriggerContains CommandTriggerType = 2
CommandTriggerRegex CommandTriggerType = 3
CommandTriggerExact CommandTriggerType = 4
CommandTriggerReaction CommandTriggerType = 6
CommandTriggerInterval CommandTriggerType = 5
CommandTriggerReaction CommandTriggerType = 6
)

var (
Expand Down Expand Up @@ -114,15 +112,13 @@ type CustomCommand struct {
TriggerType CommandTriggerType `json:"trigger_type"`
TriggerTypeForm string `json:"-" schema:"type"`
Trigger string `json:"trigger" schema:"trigger" valid:",0,1000"`
// TODO: Retire the legacy Response field.
Response string `json:"response,omitempty" schema:"response" valid:"template,10000"`
Responses []string `json:"responses" schema:"responses" valid:"template,10000"`
CaseSensitive bool `json:"case_sensitive" schema:"case_sensitive"`
ID int64 `json:"id"`
Name string `json:"name" schema:"name" valid:",0,100"`
IsEnabled bool `json:"is_enabled" schema:"is_enabled"`
Public bool `json:"public" schema:"public"`
PublicID string `json:"public_id" schema:"public_id"`
Responses []string `json:"responses" schema:"responses" valid:"template,20000"`
CaseSensitive bool `json:"case_sensitive" schema:"case_sensitive"`
ID int64 `json:"id"`
Name string `json:"name" schema:"name" valid:",0,100"`
IsEnabled bool `json:"is_enabled" schema:"is_enabled"`
Public bool `json:"public" schema:"public"`
PublicID string `json:"public_id" schema:"public_id"`

ContextChannel int64 `schema:"context_channel" valid:"channel,true"`

Expand All @@ -148,7 +144,22 @@ type CustomCommand struct {

var _ web.CustomValidator = (*CustomCommand)(nil)

func (cc *CustomCommand) Validate(tmpl web.TemplateData) (ok bool) {
func validateCCResponseLength(responses []string, guild_id int64) bool {
combinedSize := 0
for _, v := range responses {
combinedSize += utf8.RuneCountInString(v)
}

ccMaxLength := MaxCCResponsesLength
isGuildPremium, _ := premium.IsGuildPremium(guild_id)
if isGuildPremium {
ccMaxLength = MaxCCResponsesLengthPremium
}

return combinedSize <= ccMaxLength
}

func (cc *CustomCommand) Validate(tmpl web.TemplateData, guild_id int64) (ok bool) {
if len(cc.Responses) > MaxUserMessages {
tmpl.AddAlerts(web.ErrorAlert(fmt.Sprintf("Too many responses, max %d", MaxUserMessages)))
return false
Expand All @@ -167,13 +178,10 @@ func (cc *CustomCommand) Validate(tmpl web.TemplateData) (ok bool) {
return false
}

combinedSize := 0
for _, v := range cc.Responses {
combinedSize += utf8.RuneCountInString(v)
}
isValidCCLength := validateCCResponseLength(cc.Responses, guild_id)

if combinedSize > 10000 {
tmpl.AddAlerts(web.ErrorAlert("Max combined command size can be 10k"))
if cc.IsEnabled && !isValidCCLength {
tmpl.AddAlerts(web.ErrorAlert("Max combined command size can be 10k for free servers, and 20k for premium servers"))
return false
}

Expand Down Expand Up @@ -259,22 +267,12 @@ func CmdRunsInChannel(cc *models.CustomCommand, channel int64) bool {
// check command specifc restrictions
for _, v := range cc.Channels {
if v == channel {
if cc.ChannelsWhitelistMode {
return true
}

// Ignore the channel
return false
return cc.ChannelsWhitelistMode
}
}

// Not found
if cc.ChannelsWhitelistMode {
return false
}

// Not in ignore list
return true
return !cc.ChannelsWhitelistMode
}

func CmdRunsForUser(cc *models.CustomCommand, ms *dstate.MemberState) bool {
Expand All @@ -292,74 +290,17 @@ func CmdRunsForUser(cc *models.CustomCommand, ms *dstate.MemberState) bool {
// check command specific restrictions
if len(cc.Roles) == 0 {
// Fast path
if cc.RolesWhitelistMode {
return false
}

return true
return !cc.RolesWhitelistMode
}

for _, v := range cc.Roles {
if common.ContainsInt64Slice(ms.Member.Roles, v) {
if cc.RolesWhitelistMode {
return true
}

return false
return cc.RolesWhitelistMode
}
}

// Not found
if cc.RolesWhitelistMode {
return false
}

return true
}

// Migrate modifies a CustomCommand to remove legacy fields.
func (cc *CustomCommand) Migrate() *CustomCommand {
cc.Responses = filterEmptyResponses(cc.Response, cc.Responses...)
cc.Response = ""
if len(cc.Responses) > MaxUserMessages {
cc.Responses = cc.Responses[:MaxUserMessages]
}

return cc
}

func LegacyGetCommands(guild int64) ([]*CustomCommand, int64, error) {
var hashMap map[string]string

err := common.RedisPool.Do(radix.Cmd(&hashMap, "HGETALL", KeyCommands(guild)))
if err != nil {
return nil, 0, err
}

highest := int64(0)
result := make([]*CustomCommand, len(hashMap))

// Decode the commands, and also calculate the highest id
i := 0
for k, raw := range hashMap {
var decoded *CustomCommand
err = json.Unmarshal([]byte(raw), &decoded)
if err != nil {
logger.WithError(err).WithField("guild", guild).WithField("custom_command", k).Error("Failed decoding custom command")
result[i] = &CustomCommand{}
} else {
result[i] = decoded.Migrate()
if decoded.ID > highest {
highest = decoded.ID
}
}
i++
}

// Sort by id
sort.Sort(CustomCommandSlice(result))

return result, highest, nil
return !cc.RolesWhitelistMode
}

type CustomCommandSlice []*CustomCommand
Expand Down Expand Up @@ -398,10 +339,12 @@ func filterEmptyResponses(s string, ss ...string) []string {
}

const (
MaxCommands = 100
MaxCommandsPremium = 250
MaxUserMessages = 20
MaxGroups = 50
MaxCommands = 100
MaxCommandsPremium = 250
MaxCCResponsesLength = 10000
MaxCCResponsesLengthPremium = 20000
MaxUserMessages = 20
MaxGroups = 50
)

func MaxCommandsForContext(ctx context.Context) int {
Expand Down
76 changes: 0 additions & 76 deletions customcommands/migration.go

This file was deleted.

Loading

0 comments on commit 11fd926

Please sign in to comment.