diff --git a/internal/store/commands.go b/internal/store/commands.go index 05b161f..2d7efad 100644 --- a/internal/store/commands.go +++ b/internal/store/commands.go @@ -57,15 +57,6 @@ func (s *Store) ListCommands(ctx context.Context) ([]*Command, error) { return collectRows(rows, scanCommand) } -// GetCommand returns a single catalog command by id. -func (s *Store) GetCommand(ctx context.Context, id int64) (*Command, error) { - c, err := scanCommand(s.pool.QueryRow(ctx, `SELECT `+commandCols+` FROM command_catalog WHERE id = $1`, id)) - if err != nil { - return nil, notFoundOr(err, "get command") - } - return c, nil -} - // UpdateCommandFlags updates the catalog metadata an instance-admin controls. func (s *Store) UpdateCommandFlags(ctx context.Context, id int64, risky, share, orgMember, orgAdmin bool) error { _, err := s.pool.Exec(ctx, ` @@ -77,13 +68,3 @@ func (s *Store) UpdateCommandFlags(ctx context.Context, id int64, risky, share, } return nil } - -// DefaultShareCommandIDs returns the catalog ids flagged as the share default -// (used to seed a new share's allowed commands). -func (s *Store) DefaultShareCommandIDs(ctx context.Context) ([]int64, error) { - rows, err := s.pool.Query(ctx, `SELECT id FROM command_catalog WHERE in_share_default`) - if err != nil { - return nil, fmt.Errorf("default share commands: %w", err) - } - return collectRows(rows, scanID) -} diff --git a/internal/store/link_platform_test.go b/internal/store/link_platform_test.go index 9be9e2e..7f86efa 100644 --- a/internal/store/link_platform_test.go +++ b/internal/store/link_platform_test.go @@ -147,6 +147,7 @@ func TestLooksLikeURL(t *testing.T) { "discord.com/invite/abc": true, "https://discord.gg/abc": true, "http://example.com": true, + "//discord.gg/abc": true, // protocol-relative URL "example.com": false, // dotted host but no path — treated as a handle } for in, want := range cases { diff --git a/internal/store/org_domains.go b/internal/store/org_domains.go index 3b21f08..3d37c96 100644 --- a/internal/store/org_domains.go +++ b/internal/store/org_domains.go @@ -50,16 +50,6 @@ func (s *Store) CreateOrgDomain(ctx context.Context, orgID int64, hostname strin return &d, nil } -// ListOrgDomains returns an org's custom domains, newest first. -func (s *Store) ListOrgDomains(ctx context.Context, orgID int64) ([]OrgDomain, error) { - rows, err := s.pool.Query(ctx, - `SELECT `+orgDomainCols+` FROM org_domains WHERE org_id = $1 ORDER BY created_at DESC`, orgID) - if err != nil { - return nil, fmt.Errorf("list org domains: %w", err) - } - return collectRows(rows, scanOrgDomain) -} - // GetOrgDomain returns a single domain scoped to its org, or ErrNotFound. func (s *Store) GetOrgDomain(ctx context.Context, orgID, domainID int64) (*OrgDomain, error) { d, err := scanOrgDomain(s.pool.QueryRow(ctx, diff --git a/internal/store/org_links.go b/internal/store/org_links.go index f0f5db4..09345d3 100644 --- a/internal/store/org_links.go +++ b/internal/store/org_links.go @@ -116,7 +116,7 @@ func (p LinkPlatform) CanonicalHandleURL(raw string) (string, bool) { } // A pasted URL is accepted only on a known host; the handle is its last path // segment. Anything else is treated as a bare handle. - if looksLikeURL(s) { + if LooksLikeURL(s) { u, err := url.Parse(NormalizeLinkURL(s)) if err != nil || !hostAllowed(u.Host, p.Hosts) { return "", false @@ -157,7 +157,7 @@ func (p LinkPlatform) HandleFromURL(stored string) string { // canonicalMastodon accepts "@user@instance", "user@instance", or a profile URL // (https://instance/@user) and returns the canonical https://instance/@user. func canonicalMastodon(s string) (string, bool) { - if looksLikeURL(s) { + if LooksLikeURL(s) { u, err := url.Parse(NormalizeLinkURL(s)) if err != nil || u.Host == "" { return "", false @@ -175,20 +175,6 @@ func canonicalMastodon(s string) (string, bool) { return "https://" + strings.ToLower(parts[1]) + "/@" + parts[0], true } -// looksLikeURL reports whether s is a pasted URL rather than a bare handle. It -// catches an explicit scheme, a protocol-relative "//", and the scheme-less form -// ("github.com/octocat") — distinguished from a handle or Reddit's "u/name" -// shorthand by the segment before the first slash looking like a host (a dot). -func looksLikeURL(s string) bool { - if strings.Contains(s, "://") || strings.HasPrefix(s, "//") { - return true - } - if i := strings.IndexByte(s, '/'); i > 0 { - return strings.Contains(s[:i], ".") - } - return false -} - // hostAllowed reports whether host (case-insensitive, port stripped) is one of // the platform's recognised hosts. func hostAllowed(host string, hosts []string) bool { @@ -365,13 +351,14 @@ func isHTTPURL(value string) bool { return strings.HasPrefix(value, "http://") || strings.HasPrefix(value, "https://") } -// LooksLikeURL reports whether raw was entered as a web URL (a scheme, or a -// dotted host followed by a path like "discord.gg/abc") rather than a bare handle. -// A handle may contain dots (new Discord usernames do) but never a slash, so the -// path is the reliable discriminator. +// LooksLikeURL reports whether raw was entered as a web URL — an explicit scheme, +// a protocol-relative "//", or a dotted host followed by a path like +// "discord.gg/abc" — rather than a bare handle. A handle may contain dots (new +// Discord usernames do) but never a slash, so the path is the reliable +// discriminator. func LooksLikeURL(raw string) bool { raw = strings.TrimSpace(raw) - if strings.Contains(raw, "://") { + if strings.Contains(raw, "://") || strings.HasPrefix(raw, "//") { return true } if i := strings.IndexByte(raw, '/'); i > 0 {