From d5f8e58b3ae9d5f94b74dca70a7441ffe2a5c70a Mon Sep 17 00:00:00 2001 From: rxdn <29165304+rxdn@users.noreply.github.com> Date: Sat, 18 Jun 2022 20:00:44 +0100 Subject: [PATCH] Custom naming schemes --- app/http/endpoints/api/panel/panelcreate.go | 53 ++++++++++++ app/http/endpoints/api/panel/panellist.go | 20 +++-- app/http/endpoints/api/panel/panelupdate.go | 1 + frontend/package-lock.json | 86 ++++++++++++++++++- frontend/package.json | 3 +- frontend/src/components/form/Input.svelte | 35 +++++++- .../manage/PanelCreationForm.svelte | 42 +++++++-- frontend/src/includes/Head.svelte | 2 +- frontend/src/layouts/ManageLayout.svelte | 2 +- go.mod | 4 + utils/sliceutils.go | 8 +- 11 files changed, 233 insertions(+), 23 deletions(-) diff --git a/app/http/endpoints/api/panel/panelcreate.go b/app/http/endpoints/api/panel/panelcreate.go index 67d9133..3043af3 100644 --- a/app/http/endpoints/api/panel/panelcreate.go +++ b/app/http/endpoints/api/panel/panelcreate.go @@ -23,6 +23,11 @@ import ( const freePanelLimit = 3 +var ( + placeholderPattern = regexp.MustCompile(`%(\w+)%`) + channelNamePattern = regexp.MustCompile(`^[\w\d-_]+$`) +) + type panelBody struct { ChannelId uint64 `json:"channel_id,string"` MessageId uint64 `json:"message_id,string"` @@ -40,6 +45,7 @@ type panelBody struct { ButtonStyle component.ButtonStyle `json:"button_style,string"` ButtonLabel string `json:"button_label"` FormId *int `json:"form_id"` + NamingScheme *string `json:"naming_scheme"` } func (p *panelBody) IntoPanelMessageData(customId string, isPremium bool) panelMessageData { @@ -153,6 +159,7 @@ func CreatePanel(ctx *gin.Context) { ButtonStyle: int(data.ButtonStyle), ButtonLabel: data.ButtonLabel, FormId: data.FormId, + NamingScheme: data.NamingScheme, } panelId, err := dbclient.Client.Panel.Create(panel) @@ -305,6 +312,11 @@ func (p *panelBody) doValidations(ctx *gin.Context, guildId uint64) bool { } } + if !p.verifyNamingScheme() { + ctx.JSON(400, utils.ErrorStr("Invalid naming scheme: ensure that the naming scheme is less than 100 characters and the placeholders you have used are valid")) + return false + } + return true } @@ -459,6 +471,47 @@ func (p *panelBody) verifyTeams(guildId uint64) (bool, error) { return dbclient.Client.SupportTeam.AllTeamsExistForGuild(guildId, p.Teams) } +func (p *panelBody) verifyNamingScheme() bool { + if p.NamingScheme == nil { + return true + } + + if len(*p.NamingScheme) == 0 { + p.NamingScheme = nil + return true + } + + // Substitute out {} users may use by mistake, spaces for dashes and convert to lowercase + p.NamingScheme = utils.Ptr(strings.ReplaceAll(*p.NamingScheme, "{", "%")) + p.NamingScheme = utils.Ptr(strings.ReplaceAll(*p.NamingScheme, "}", "%")) + p.NamingScheme = utils.Ptr(strings.ReplaceAll(*p.NamingScheme, " ", "-")) + p.NamingScheme = utils.Ptr(strings.ToLower(*p.NamingScheme)) + + if len(*p.NamingScheme) > 100 { + return false + } + + // We must remove all placeholders from the string to check whether the rest of the string is legal + noPlaceholders := *p.NamingScheme + + // Validate placeholders used + validPlaceholders := []string{"id", "username"} + for _, match := range placeholderPattern.FindAllStringSubmatch(*p.NamingScheme, -1) { + if len(match) < 2 { // Infallible + return false + } + + placeholder := match[1] + if !utils.Contains(validPlaceholders, placeholder) { + return false + } + + noPlaceholders = strings.Replace(noPlaceholders, match[0], "", -1) // match[0] = "%placeholder%" + } + + return channelNamePattern.MatchString(noPlaceholders) +} + func getRoleHashSet(guildId uint64) (*collections.Set[uint64], error) { ctx, err := botcontext.ContextForGuild(guildId) if err != nil { diff --git a/app/http/endpoints/api/panel/panellist.go b/app/http/endpoints/api/panel/panellist.go index c85d954..f5504a8 100644 --- a/app/http/endpoints/api/panel/panellist.go +++ b/app/http/endpoints/api/panel/panellist.go @@ -13,10 +13,11 @@ import ( func ListPanels(ctx *gin.Context) { type panelResponse struct { database.Panel - UseCustomEmoji bool `json:"use_custom_emoji"` - Emoji types.Emoji `json:"emote"` - Mentions []string `json:"mentions"` - Teams []int `json:"teams"` + UseCustomEmoji bool `json:"use_custom_emoji"` + Emoji types.Emoji `json:"emote"` + Mentions []string `json:"mentions"` + Teams []int `json:"teams"` + UseServerDefaultNamingScheme bool `json:"use_server_default_naming_scheme"` } guildId := ctx.Keys["guildid"].(uint64) @@ -74,11 +75,12 @@ func ListPanels(ctx *gin.Context) { } wrapped[i] = panelResponse{ - Panel: p, - UseCustomEmoji: p.EmojiId != nil, - Emoji: types.NewEmoji(p.EmojiName, p.EmojiId), - Mentions: mentions, - Teams: teamIds, + Panel: p, + UseCustomEmoji: p.EmojiId != nil, + Emoji: types.NewEmoji(p.EmojiName, p.EmojiId), + Mentions: mentions, + Teams: teamIds, + UseServerDefaultNamingScheme: p.NamingScheme == nil, } return nil diff --git a/app/http/endpoints/api/panel/panelupdate.go b/app/http/endpoints/api/panel/panelupdate.go index 599c9b2..45eb1f8 100644 --- a/app/http/endpoints/api/panel/panelupdate.go +++ b/app/http/endpoints/api/panel/panelupdate.go @@ -125,6 +125,7 @@ func UpdatePanel(ctx *gin.Context) { ButtonStyle: int(data.ButtonStyle), ButtonLabel: data.ButtonLabel, FormId: data.FormId, + NamingScheme: data.NamingScheme, } if err = dbclient.Client.Panel.Update(panel); err != nil { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7d10704..452e7ca 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,7 +12,8 @@ "sirv-cli": "^1.0.0", "svelte-emoji-selector": "^1.0.1", "svelte-router-spa": "^6.0.2", - "svelte-select": "^3.17.0" + "svelte-select": "^3.17.0", + "svelte-tooltip": "^1.2.0" }, "devDependencies": { "@babel/core": "^7.14.6", @@ -3176,6 +3177,51 @@ "integrity": "sha512-2gzDDMDhM+ImDaLEZVlnlHVY1340Y368tT4Qk5IwLnCeRJ4zV3cVwliVGacoHy7iCDukcGXzKwDzG/hTTcaljg==", "dev": true }, + "node_modules/svelte-tooltip": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/svelte-tooltip/-/svelte-tooltip-1.2.0.tgz", + "integrity": "sha512-FmaiNoCGkXBqF5AAscv+NdLtVIhywpqcaKw7mP1IksLJPMW3QaOPB8G23CHPQWde0J3A0NdCDQ3DI2isWGsDbg==", + "dependencies": { + "sirv-cli": "^0.4.4" + } + }, + "node_modules/svelte-tooltip/node_modules/@polka/url": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", + "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==" + }, + "node_modules/svelte-tooltip/node_modules/sirv": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-0.4.6.tgz", + "integrity": "sha512-rYpOXlNbpHiY4nVXxuDf4mXPvKz1reZGap/LkWp9TvcZ84qD/nPBjjH/6GZsgIjVMbOslnY8YYULAyP8jMn1GQ==", + "dependencies": { + "@polka/url": "^0.5.0", + "mime": "^2.3.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/svelte-tooltip/node_modules/sirv-cli": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-0.4.6.tgz", + "integrity": "sha512-/Vj85/kBvPL+n9ibgX6FicLE8VjidC1BhlX67PYPBfbBAphzR6i0k0HtU5c2arejfU3uzq8l3SYPCwl1x7z6Ww==", + "dependencies": { + "console-clear": "^1.1.0", + "get-port": "^3.2.0", + "kleur": "^3.0.0", + "local-access": "^1.0.1", + "sade": "^1.4.0", + "sirv": "^0.4.6", + "tinydate": "^1.0.0" + }, + "bin": { + "sirv": "index.js" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/terser": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz", @@ -5606,6 +5652,44 @@ "integrity": "sha512-2gzDDMDhM+ImDaLEZVlnlHVY1340Y368tT4Qk5IwLnCeRJ4zV3cVwliVGacoHy7iCDukcGXzKwDzG/hTTcaljg==", "dev": true }, + "svelte-tooltip": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/svelte-tooltip/-/svelte-tooltip-1.2.0.tgz", + "integrity": "sha512-FmaiNoCGkXBqF5AAscv+NdLtVIhywpqcaKw7mP1IksLJPMW3QaOPB8G23CHPQWde0J3A0NdCDQ3DI2isWGsDbg==", + "requires": { + "sirv-cli": "^0.4.4" + }, + "dependencies": { + "@polka/url": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", + "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==" + }, + "sirv": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-0.4.6.tgz", + "integrity": "sha512-rYpOXlNbpHiY4nVXxuDf4mXPvKz1reZGap/LkWp9TvcZ84qD/nPBjjH/6GZsgIjVMbOslnY8YYULAyP8jMn1GQ==", + "requires": { + "@polka/url": "^0.5.0", + "mime": "^2.3.1" + } + }, + "sirv-cli": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-0.4.6.tgz", + "integrity": "sha512-/Vj85/kBvPL+n9ibgX6FicLE8VjidC1BhlX67PYPBfbBAphzR6i0k0HtU5c2arejfU3uzq8l3SYPCwl1x7z6Ww==", + "requires": { + "console-clear": "^1.1.0", + "get-port": "^3.2.0", + "kleur": "^3.0.0", + "local-access": "^1.0.1", + "sade": "^1.4.0", + "sirv": "^0.4.6", + "tinydate": "^1.0.0" + } + } + } + }, "terser": { "version": "5.7.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 6e8f2fe..3beb2fa 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,6 +28,7 @@ "sirv-cli": "^1.0.0", "svelte-emoji-selector": "^1.0.1", "svelte-router-spa": "^6.0.2", - "svelte-select": "^3.17.0" + "svelte-select": "^3.17.0", + "svelte-tooltip": "^1.2.0" } } diff --git a/frontend/src/components/form/Input.svelte b/frontend/src/components/form/Input.svelte index 7ad5180..c84f776 100644 --- a/frontend/src/components/form/Input.svelte +++ b/frontend/src/components/form/Input.svelte @@ -1,17 +1,39 @@