Skip to content

Commit cd6d155

Browse files
committed
feat: add anti-spam feature to Heimdallr.
Adds an anti-spam moderation feature, designed to prevent spam messages across multiple channels, common for when scammers spam links across all channels. It is not designed to handle spam in a single channel.
1 parent 7b2c3a6 commit cd6d155

File tree

6 files changed

+308
-31
lines changed

6 files changed

+308
-31
lines changed

commands/admin.go

+103-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package commands
22

33
import (
44
"fmt"
5+
"log/slog"
56

67
"github.com/cbroglie/mustache"
78
"github.com/disgoorg/disgo/discord"
89
"github.com/disgoorg/disgo/handler"
910
"github.com/disgoorg/json"
11+
1012
"github.com/myrkvi/heimdallr/model"
1113
"github.com/myrkvi/heimdallr/utils"
1214
)
@@ -15,7 +17,7 @@ var AdminCommand = discord.SlashCommandCreate{
1517
Name: "admin",
1618
Description: "admin commands",
1719
DefaultMemberPermissions: json.NewNullablePtr(discord.PermissionAdministrator),
18-
DMPermission: utils.Ref(false),
20+
Contexts: []discord.InteractionContextType{discord.InteractionContextTypeGuild},
1921
Options: []discord.ApplicationCommandOption{
2022
discord.ApplicationCommandOptionSubCommand{
2123
Name: "info",
@@ -125,6 +127,32 @@ var AdminCommand = discord.SlashCommandCreate{
125127
Name: "leave-message",
126128
Description: "Set the message to send when a user leaves",
127129
},
130+
131+
discord.ApplicationCommandOptionSubCommand{
132+
Name: "anti-spam",
133+
Description: "View or set anti-spam settings",
134+
Options: []discord.ApplicationCommandOption{
135+
discord.ApplicationCommandOptionBool{
136+
Name: "enabled",
137+
Description: "Whether to enable the anti-spam system",
138+
Required: false,
139+
},
140+
discord.ApplicationCommandOptionInt{
141+
Name: "count",
142+
Description: "The number of messages needed for Heimdallr to take action (within the cooldown period)",
143+
Required: false,
144+
MinValue: utils.Ref(2),
145+
MaxValue: utils.Ref(10),
146+
},
147+
discord.ApplicationCommandOptionInt{
148+
Name: "cooldown",
149+
Description: "The time in seconds to wait before resetting the message count",
150+
Required: false,
151+
MinValue: utils.Ref(1),
152+
MaxValue: utils.Ref(60),
153+
},
154+
},
155+
},
128156
},
129157
}
130158

@@ -145,9 +173,10 @@ func AdminInfoHandler(e *handler.CommandEvent) error {
145173
infractionSettings := infractionInfo(settings)
146174
gatekeepSettings := gatekeepInfo(settings)
147175
joinLeaveSettings := joinLeaveInfo(settings)
176+
antiSpamSettings := antiSpamInfo(settings)
148177

149-
message := fmt.Sprintf("# Server settings\n%s\n\n%s\n\n%s\n\n%s",
150-
modChannel, infractionSettings, gatekeepSettings, joinLeaveSettings)
178+
message := fmt.Sprintf("# Server settings\n%s\n\n%s\n\n%s\n\n%s\n\n%s",
179+
modChannel, infractionSettings, gatekeepSettings, joinLeaveSettings, antiSpamSettings)
151180

152181
return e.CreateMessage(discord.NewMessageCreateBuilder().
153182
SetContent(message).
@@ -232,6 +261,23 @@ func joinLeaveInfo(settings *model.GuildSettings) string {
232261
joinMessageEnabled, leaveMessageEnabled, joinLeaveChannel, joinLeaveMessageInfo)
233262
}
234263

264+
func antiSpamInfo(settings *model.GuildSettings) string {
265+
antispamEnabledInfo := "> This determines whether to enable the anti-spam system."
266+
antispamEnabled := fmt.Sprintf("**Anti-spam enabled:** %s\n%s",
267+
utils.Iif(settings.AntiSpamEnabled, "yes", "no"), antispamEnabledInfo)
268+
269+
antispamCountInfo := "> This is the number of messages needed for Heimdallr to take action (within the cooldown period)."
270+
antispamCount := fmt.Sprintf("**Anti-spam count:** %d\n%s",
271+
settings.AntiSpamCount, antispamCountInfo)
272+
273+
antispamCooldownInfo := "> This is the time in seconds to wait before resetting the message count."
274+
antispamCooldown := fmt.Sprintf("**Anti-spam cooldown:** %d\n%s",
275+
settings.AntiSpamCooldownSeconds, antispamCooldownInfo)
276+
277+
return fmt.Sprintf("## Anti-spam settings\n%s\n\n%s\n\n%s",
278+
antispamEnabled, antispamCount, antispamCooldown)
279+
}
280+
235281
func AdminModChannelHandler(e *handler.CommandEvent) error {
236282
data := e.SlashCommandInteractionData()
237283
guild, isGuild := e.Guild()
@@ -699,3 +745,57 @@ func AdminLeaveMessageModalHandler(e *handler.ModalEvent) error {
699745
SetAllowedMentions(&discord.AllowedMentions{}).
700746
Build())
701747
}
748+
func AdminAntiSpamHandler(e *handler.CommandEvent) error {
749+
utils.LogInteraction("admin anti-spam", e)
750+
data := e.SlashCommandInteractionData()
751+
guild, isGuild := e.Guild()
752+
if !isGuild {
753+
return ErrEventNoGuildID
754+
}
755+
756+
settings, err := model.GetGuildSettings(guild.ID)
757+
if err != nil {
758+
slog.Warn("Failed to get guild settings", "err", err)
759+
return err
760+
}
761+
762+
message := ""
763+
764+
enabled, hasEnabled := data.OptBool("enabled")
765+
if hasEnabled {
766+
settings.AntiSpamEnabled = enabled
767+
message += fmt.Sprintf("Anti-spam enabled set to %s\n", utils.Iif(enabled, "yes", "no"))
768+
}
769+
770+
count, hasCount := data.OptInt("count")
771+
if hasCount {
772+
settings.AntiSpamCount = count
773+
message += fmt.Sprintf("Anti-spam count (message threshold within cooldown period) set to %d\n", count)
774+
}
775+
776+
cooldown, hasCooldown := data.OptInt("cooldown")
777+
if hasCooldown {
778+
settings.AntiSpamCooldownSeconds = cooldown
779+
message += fmt.Sprintf("Anti-spam cooldown (seconds) set to %d\n", cooldown)
780+
}
781+
782+
if !utils.Any(hasEnabled, hasCount, hasCooldown) {
783+
return e.CreateMessage(discord.NewMessageCreateBuilder().
784+
SetContent(antiSpamInfo(settings)).
785+
SetEphemeral(true).
786+
SetAllowedMentions(&discord.AllowedMentions{}).
787+
Build())
788+
}
789+
790+
err = model.SetGuildSettings(settings)
791+
if err != nil {
792+
slog.Warn("Failed to set guild settings", "err", err)
793+
return err
794+
}
795+
796+
return e.CreateMessage(discord.NewMessageCreateBuilder().
797+
SetContent(message).
798+
SetEphemeral(true).
799+
SetAllowedMentions(&discord.AllowedMentions{}).
800+
Build())
801+
}

go.mod

+4
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,20 @@ module github.com/myrkvi/heimdallr
33
go 1.23.0
44

55
require (
6+
github.com/agnivade/levenshtein v1.2.0
67
github.com/cbroglie/mustache v1.4.0
78
github.com/disgoorg/disgo v0.18.14
89
github.com/disgoorg/json v1.2.0
910
github.com/disgoorg/snowflake/v2 v2.0.3
1011
github.com/glebarez/sqlite v1.11.0
12+
github.com/jellydator/ttlcache/v3 v3.3.0
1113
github.com/spf13/viper v1.19.0
1214
github.com/sqids/sqids-go v0.4.1
1315
gorm.io/gorm v1.25.12
1416
)
1517

18+
require golang.org/x/sync v0.8.0 // indirect
19+
1620
require (
1721
github.com/dustin/go-humanize v1.0.1 // indirect
1822
github.com/fsnotify/fsnotify v1.7.0 // indirect

go.sum

+12-28
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
1+
github.com/agnivade/levenshtein v1.2.0 h1:U9L4IOT0Y3i0TIlUIDJ7rVUziKi/zPbrJGaFrtYH3SY=
2+
github.com/agnivade/levenshtein v1.2.0/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU=
3+
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
4+
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
15
github.com/cbroglie/mustache v1.4.0 h1:Azg0dVhxTml5me+7PsZ7WPrQq1Gkf3WApcHMjMprYoU=
26
github.com/cbroglie/mustache v1.4.0/go.mod h1:SS1FTIghy0sjse4DUVGV1k/40B1qE1XkD9DtDsHo9iM=
37
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
48
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
59
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
610
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7-
github.com/disgoorg/disgo v0.18.10 h1:1O7lYLuIrLYNzJvnSdUSacFmFzHb0Zs4oDTkGSkoFzY=
8-
github.com/disgoorg/disgo v0.18.10/go.mod h1:TN4tM8VaOaZebO+Ek3686RIATCL32uqPGSNdUYP8yVI=
9-
github.com/disgoorg/disgo v0.18.11 h1:hvWpU43PtThNeKOeP6ghx3nyjpgP0oaQz2WL3yizCIA=
10-
github.com/disgoorg/disgo v0.18.11/go.mod h1:mkNGTSWCxIgTXCIg8GqRJedAqNw4T++xOgBOTEk9d7U=
11-
github.com/disgoorg/disgo v0.18.12 h1:bB4bgJ9KEyJ+vKfa/fYEwEYv8Ds3C8RUoavotF2xHxY=
12-
github.com/disgoorg/disgo v0.18.12/go.mod h1:wZ/ZW6x43QivIVrYrJxwSeFbIbrMqpi5vAU1ovsod8o=
13-
github.com/disgoorg/disgo v0.18.13 h1:RswLnakVS+RbCACBfK7mLv3YGdZh625N2SMnngnqd+Q=
14-
github.com/disgoorg/disgo v0.18.13/go.mod h1:wZ/ZW6x43QivIVrYrJxwSeFbIbrMqpi5vAU1ovsod8o=
11+
github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo=
12+
github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
1513
github.com/disgoorg/disgo v0.18.14 h1:ipalZjUGeCYjL/Qa7djlGZU5Dk0TicECZPSeNW774Q8=
1614
github.com/disgoorg/disgo v0.18.14/go.mod h1:wZ/ZW6x43QivIVrYrJxwSeFbIbrMqpi5vAU1ovsod8o=
17-
github.com/disgoorg/json v1.1.0 h1:7xigHvomlVA9PQw9bMGO02PHGJJPqvX5AnwlYg/Tnys=
18-
github.com/disgoorg/json v1.1.0/go.mod h1:BHDwdde0rpQFDVsRLKhma6Y7fTbQKub/zdGO5O9NqqA=
1915
github.com/disgoorg/json v1.2.0 h1:6e/j4BCfSHIvucG1cd7tJPAOp1RgnnMFSqkvZUtEd1Y=
2016
github.com/disgoorg/json v1.2.0/go.mod h1:BHDwdde0rpQFDVsRLKhma6Y7fTbQKub/zdGO5O9NqqA=
2117
github.com/disgoorg/snowflake/v2 v2.0.3 h1:3B+PpFjr7j4ad7oeJu4RlQ+nYOTadsKapJIzgvSI2Ro=
@@ -28,8 +24,6 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos
2824
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
2925
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
3026
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
31-
github.com/glebarez/sqlite v1.10.0 h1:u4gt8y7OND/cCei/NMHmfbLxF6xP2wgKcT/BJf2pYkc=
32-
github.com/glebarez/sqlite v1.10.0/go.mod h1:IJ+lfSOmiekhQsFTJRx/lHtGYmCdtAiTaf5wI9u5uHA=
3327
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
3428
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
3529
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -42,6 +36,8 @@ github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aN
4236
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
4337
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
4438
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
39+
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
40+
github.com/jellydator/ttlcache/v3 v3.3.0/go.mod h1:bj2/e0l4jRnQdrnSTaGTsh4GSXvMjQcy41i7th0GVGw=
4541
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
4642
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
4743
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
@@ -61,8 +57,6 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
6157
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
6258
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
6359
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
64-
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
65-
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
6660
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
6761
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
6862
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -86,8 +80,6 @@ github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
8680
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
8781
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
8882
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
89-
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
90-
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
9183
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
9284
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
9385
github.com/sqids/sqids-go v0.4.1 h1:eQKYzmAZbLlRwHeHYPF35QhgxwZHLnlmVj9AkIj/rrw=
@@ -103,25 +95,21 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
10395
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
10496
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
10597
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
98+
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
99+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
106100
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
107101
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
108-
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
109-
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
110102
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
111103
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
112104
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 h1:mchzmB1XO2pMaKFRqk/+MV3mgGG96aqaPXaMifQU47w=
113105
golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
114106
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
115107
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
116-
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
117-
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
108+
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
109+
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
118110
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
119-
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
120-
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
121111
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
122112
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
123-
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
124-
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
125113
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
126114
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
127115
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
@@ -134,10 +122,6 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
134122
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
135123
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
136124
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
137-
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
138-
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
139-
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg=
140-
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
141125
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
142126
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
143127
modernc.org/cc/v4 v4.21.0 h1:D/gLKtcztomvWbsbvBKo3leKQv+86f+DdqEZBBXhnag=

0 commit comments

Comments
 (0)