Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 38 additions & 20 deletions src/routes/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,41 @@ type urlConversionRequest struct {
URL string `form:"url" binding:"required"`
}

var stackExchangeRegex = regexp.MustCompile(`https://(.+).stackexchange.com/questions/`)
var coreRegex = regexp.MustCompile(`(?:https?://)?(?:www\.)?([^/]+)(/(?:questions|q|a)/.+)`)

// Will return `nil` if `rawUrl` is invalid.
func translateUrl(rawUrl string) string {
coreMatches := coreRegex.FindStringSubmatch(rawUrl)
if coreMatches == nil {
return ""
}

domain := coreMatches[1]
rest := coreMatches[2]

exchange := ""
if domain == "stackoverflow.com" {
// No exchange parameter needed.
} else if sub, found := strings.CutSuffix(domain, ".stackexchange.com"); found {
if sub == "" {
return ""
} else if strings.Contains(sub, ".") {
// Anything containing dots is interpreted as a full domain, so we use the correct full domain.
exchange = domain
} else {
exchange = sub
}
} else {
exchange = domain
}

// Ensure we properly format the return string to avoid double slashes
if exchange == "" {
return rest
} else {
return fmt.Sprintf("/exchange/%s%s", exchange, rest)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I thought I changed that during development but it must have slipped back in.

}
}

func PostHome(c *gin.Context) {
body := urlConversionRequest{}
Expand All @@ -33,31 +67,15 @@ func PostHome(c *gin.Context) {
return
}

soLink := body.URL

// remove the www.
soLink = strings.ReplaceAll(soLink, "www.", "")
translated := translateUrl(body.URL)

// validate URL
isStackOverflow := strings.HasPrefix(soLink, "https://stackoverflow.com/questions/")
isShortenedStackOverflow := strings.HasPrefix(soLink, "https://stackoverflow.com/a/") || strings.HasPrefix(soLink, "https://stackoverflow.com/q/")
isStackExchange := stackExchangeRegex.MatchString(soLink)
if !isStackExchange && !isStackOverflow && !isShortenedStackOverflow {
if translated == "" {
c.HTML(400, "home.html", gin.H{
"errorMessage": "Invalid stack overflow/exchange URL",
"theme": c.MustGet("theme").(string),
})
return
}

// if stack overflow, trim https://stackoverflow.com
if isStackOverflow || isShortenedStackOverflow {
c.Redirect(302, strings.TrimPrefix(soLink, "https://stackoverflow.com"))
return
}

// if stack exchange, extract the subdomain
sub := stackExchangeRegex.FindStringSubmatch(soLink)[1]

c.Redirect(302, fmt.Sprintf("/exchange/%s/%s", sub, strings.TrimPrefix(soLink, fmt.Sprintf("https://%s.stackexchange.com", sub))))
c.Redirect(302, translated)
}
32 changes: 32 additions & 0 deletions src/routes/home_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package routes

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestTranslateUrl(t *testing.T) {
assert := assert.New(t)

// Test with a Valid StackOverflow URL
assert.Equal("/questions/example-question", translateUrl("https://stackoverflow.com/questions/example-question"), "StackOverflow URL should not be modified")

// Test with Complex Subdomain
assert.Equal("/exchange/meta.math.stackexchange.com/q/example-question", translateUrl("https://meta.math.stackexchange.com/q/example-question"), "Complex StackExchange subdomain should be used as full exchange")

// Test with Non-StackExchange Domain
assert.Equal("/exchange/example.com/questions/example-question", translateUrl("https://example.com/questions/example-question"), "Non-StackExchange domain should be detected as exchange")

// Test with Invalid URL
assert.Equal("", translateUrl("This is not a URL"), "Invalid URL should return an empty string")

// Test with Empty String
assert.Equal("", translateUrl(""), "Empty string should return an empty string")

// Test with Missing Path
assert.Equal("", translateUrl("https://stackoverflow.com"), "URL without path should return an empty string")

// Test with Valid URL but Root Domain for StackExchange
assert.Equal("", translateUrl("https://stackexchange.com"), "Root StackExchange domain without subdomain should return an empty string")
}
4 changes: 3 additions & 1 deletion src/routes/question.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ func ViewQuestion(c *gin.Context) {

domain := "stackoverflow.com"

if params.Sub != "" {
if strings.Contains(params.Sub, ".") {
domain = params.Sub
} else if params.Sub != "" {
domain = fmt.Sprintf("%s.stackexchange.com", params.Sub)
}

Expand Down