@@ 1819,7 1819,7 @@ func (r *mutationResolver) AddLinkShort(ctx context.Context, input *model.LinkSh
}
if input.ShortCode != nil {
- validator.Expect(len(*input.ShortCode) < 20,
+ validator.Expect(len(*input.ShortCode) <= 20,
lt.Translate("Short Code may not exceed 20 characters")).
WithField("shortCode").
WithCode(valid.ErrValidationCode)
@@ 1908,10 1908,12 @@ func (r *mutationResolver) AddLinkShort(ctx context.Context, input *model.LinkSh
}
// Validate custom short code
- if input.ShortCode != nil {
+ var shortCode string
+ if input.ShortCode != nil && *input.ShortCode != "" {
+ shortCode = links.SlugifyCase(*input.ShortCode)
opts := &database.FilterOptions{
Filter: sq.And{
- sq.Eq{"l.short_code": *input.ShortCode},
+ sq.Eq{"l.short_code": shortCode},
sq.Eq{"l.domain_id": input.DomainID},
},
Limit: 1,
@@ 1931,16 1933,13 @@ func (r *mutationResolver) AddLinkShort(ctx context.Context, input *model.LinkSh
}
linkShort := &models.LinkShort{
- URL: input.URL,
- OrgID: org.ID,
- UserID: int(user.ID),
- DomainID: input.DomainID,
+ URL: input.URL,
+ OrgID: org.ID,
+ UserID: int(user.ID),
+ DomainID: input.DomainID,
+ ShortCode: shortCode, // if "", it will be generated before saving
}
- if input.ShortCode != nil && *input.ShortCode != "" {
- shortCode := links.SlugifyCase(*input.ShortCode)
- linkShort.ShortCode = shortCode
- }
if input.Title != nil {
linkShort.Title = *input.Title
}
@@ 2001,7 2000,7 @@ func (r *mutationResolver) UpdateLinkShort(ctx context.Context, input *model.Upd
}
if input.ShortCode != nil {
- validator.Expect(len(*input.ShortCode) < 20,
+ validator.Expect(len(*input.ShortCode) <= 20,
lt.Translate("Short Code may not exceed 20 characters")).
WithField("shortCode").
WithCode(valid.ErrValidationCode)
@@ 7,13 7,16 @@ import (
"links/internal/localizer"
"links/models"
"net/http"
+ "net/url"
"strings"
"git.sr.ht/~emersion/gqlclient"
sq "github.com/Masterminds/squirrel"
"github.com/labstack/echo/v4"
+ "golang.org/x/exp/slices"
"netlandish.com/x/gobwebs/auth"
"netlandish.com/x/gobwebs/database"
+ "netlandish.com/x/gobwebs/server"
)
type SlackBlock struct {
@@ 30,11 33,12 @@ type SlackCommandResponse struct {
Blocks []SlackBlock `json:"blocks"`
}
-func linkAddShort(c echo.Context, url, teamID, slackUser, text string) (*SlackCommandResponse, error) {
+func linkAddShort(c echo.Context, surl, teamID, slackUser, text string) (*SlackCommandResponse, error) {
opts := &database.FilterOptions{
Filter: sq.Eq{"sc.team_id": teamID},
Limit: 1,
}
+ gctx := c.(*server.Context)
ctx := c.Request().Context()
lt := localizer.GetSessionLocalizer(c)
slackConns, err := models.GetSlackConnections(ctx, opts)
@@ 64,7 68,7 @@ func linkAddShort(c echo.Context, url, teamID, slackUser, text string) (*SlackCo
}
if len(slackUsers) == 0 {
- return sendInstructionLink(c, slackConn, url, slackUser)
+ return sendInstructionLink(c, slackConn, surl, slackUser)
}
user, err := models.GetUser(ctx, slackUsers[0].UserID, true)
@@ 78,38 82,66 @@ func linkAddShort(c echo.Context, url, teamID, slackUser, text string) (*SlackCo
// index 0 is url
// index 1 is shortcode
// index 2 is domain
- input := strings.Split(text, " ")
- shortCodeArg := strings.Split(input[1], ":")
- if len(shortCodeArg) != 2 {
- block.Text.Text = lt.Translate("Wrong short code argument")
+ var lurl, domstr, code string
+
+ for _, blob := range strings.Split(text, " ") {
+ _, err = url.Parse(blob)
+ if err != nil {
+ lurl = blob
+ continue
+ }
+
+ parts := strings.SplitN(blob, ":", 2)
+ if len(parts) != 2 {
+ // Invalid input, skip
+ continue
+ }
+
+ if !slices.Contains([]string{"code", "domain"}, parts[0]) {
+ // Invalid keyword, skip
+ continue
+ }
+
+ if parts[0] == "code" {
+ code = parts[1]
+ } else {
+ domstr = parts[1]
+ }
+ }
+
+ if lurl == "" {
+ block.Text.Text = lt.Translate("No URL argument was given")
commandResp := &SlackCommandResponse{
Text: "Error",
Blocks: []SlackBlock{block},
}
return commandResp, nil
-
}
- domainArg := strings.Split(input[2], ":")
- if len(domainArg) != 2 {
- block.Text.Text = lt.Translate("Wrong short code argument")
+ if domstr == "" {
+ block.Text.Text = lt.Translate("Wrong domain argument")
commandResp := &SlackCommandResponse{
Text: "Error",
Blocks: []SlackBlock{block},
}
return commandResp, nil
-
}
// Check that the domain exists, it is a short service domain
// and belong to the slack connection organization
opts = &database.FilterOptions{
Filter: sq.And{
- sq.Eq{"d.lookup_name": domainArg[1]},
+ sq.Eq{"d.lookup_name": strings.ToLower(domstr)},
sq.Eq{"d.service": models.DomainServiceShort},
sq.Eq{"d.status": models.DomainStatusApproved},
sq.Eq{"d.is_active": true},
- sq.Eq{"d.org_id": slackConn.OrgID},
+ sq.Or{
+ sq.And{
+ sq.Eq{"d.org_id": slackConn.OrgID},
+ sq.Eq{"d.level": models.DomainLevelUser},
+ },
+ sq.Eq{"d.level": models.DomainLevelSystem},
+ },
},
Limit: 1,
}
@@ 119,7 151,7 @@ func linkAddShort(c echo.Context, url, teamID, slackUser, text string) (*SlackCo
return nil, err
}
if len(domains) == 0 {
- block.Text.Text = lt.Translate("%s: domain not found", domainArg[1])
+ block.Text.Text = lt.Translate("%s: domain not found", domstr)
commandResp := &SlackCommandResponse{
Text: "Error",
Blocks: []SlackBlock{block},
@@ 143,21 175,30 @@ func linkAddShort(c echo.Context, url, teamID, slackUser, text string) (*SlackCo
domainId: $domain,
shortCode: $short}) {
id
+ shortCode
}
}`)
- op.Var("title", input[0])
- op.Var("url", input[0])
+ if len(lurl) > 150 {
+ op.Var("title", fmt.Sprintf("%s...", lurl[:146]))
+ } else {
+ op.Var("title", lurl)
+ }
+ op.Var("url", lurl)
op.Var("slug", slackConn.OrgSlug)
op.Var("domain", domain.ID)
- op.Var("short", shortCodeArg[1])
+ op.Var("short", code)
err = links.Execute(ctx, op, &result)
if err != nil {
return nil, err
}
- block.Type = "section"
- block.Text.Type = "mrkdwn"
- block.Text.Text = lt.Translate("Your short link was successfully created")
+
+ shortURL := &url.URL{
+ Scheme: gctx.Server.Config.Scheme,
+ Host: domain.LookupName,
+ Path: "/" + result.LinkShort.ShortCode,
+ }
+ block.Text.Text = lt.Translate("Your short link was successfully created: %s", shortURL.String())
commandResp := &SlackCommandResponse{
Text: "Add Link",
Blocks: []SlackBlock{block},