implemented the /go shortcut processing

This commit is contained in:
2026-01-22 22:46:15 -07:00
parent 9218025450
commit c3e31e295c
3 changed files with 123 additions and 4 deletions
+78 -1
View File
@@ -1,6 +1,6 @@
/*
* Amsterdam Web Communities System
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -92,6 +92,83 @@ func (d *PostLinkData) AsString() string {
return b.String()
}
/* Classify tells us what kind of post link this is and where we should interpret it from.
* Returns:
* String value indicating the scope of the link:
* "global" - Scope across the entire site.
* "community" - Scope within a community.
* "conference" - Scope within a conference.
* "topic" - Scope within a specific topic.
* Empty string - Null link.
* String value indicating what the link points to:
* "community" - Points to a community.
* "conference" - Points to a conference.
* "topic" - Points to a topic.
* "post" - Points to a single post within the topic.
* "postrange" - Points to a range of posts within the topic.
* "postopenrange" - Points to an open-ended range of posts within the topic.
* Empty string - Null link.
*/
func (d *PostLinkData) Classify() (string, string) {
if d.Community == "" {
if d.Conference == "" {
if d.Topic == -1 {
if d.FirstPost == -1 {
return "", ""
} else if d.LastPost == -1 {
return "topic", "postopenrange"
} else if d.LastPost == d.FirstPost {
return "topic", "post"
} else {
return "topic", "postrange"
}
} else {
if d.FirstPost == -1 {
return "conference", "topic"
} else if d.LastPost == -1 {
return "conference", "postopenrange"
} else if d.LastPost == d.FirstPost {
return "conference", "post"
} else {
return "conference", "postrange"
}
}
} else {
if d.Topic == -1 {
return "community", "conference"
} else {
if d.FirstPost == -1 {
return "community", "topic"
} else if d.LastPost == -1 {
return "community", "postopenrange"
} else if d.LastPost == d.FirstPost {
return "community", "post"
} else {
return "community", "postrange"
}
}
}
} else {
if d.Conference == "" {
return "global", "community"
} else {
if d.Topic == -1 {
return "global", "conference"
} else {
if d.FirstPost == -1 {
return "global", "topic"
} else if d.LastPost == -1 {
return "global", "postopenrange"
} else if d.LastPost == d.FirstPost {
return "global", "post"
} else {
return "global", "postrange"
}
}
}
}
}
// Maximum lengths of the components.
const (
maxLinkLength = 130
+4 -2
View File
@@ -50,7 +50,7 @@ func setupEcho() *echo.Echo {
e.POST("/TODO/*", fn)
e.GET("/img/*", ui.AmServeImage)
e.GET("/static/*", ui.AmStaticFileHandler())
e.GET("/go/:postlink", fn)
e.GET("/go/:postlink", ui.AmWrap(JumpToShortcut))
e.GET("/", ui.AmWrap(TopPage))
e.GET("/about", ui.AmWrap(AboutPage))
@@ -79,7 +79,9 @@ func setupEcho() *echo.Echo {
// community group
commGroup := e.Group("/comm/:cid", ui.SetCommunity)
commGroup.GET("/profile", ui.AmWrap(ShowCommunity))
fn1 := ui.AmWrap(ShowCommunity)
commGroup.GET("", fn1)
commGroup.GET("/profile", fn1)
commGroup.GET("/join", ui.AmWrap(JoinCommunity))
commGroup.POST("/join", ui.AmWrap(JoinCommunityWithKey))
commGroup.GET("/unjoin", ui.AmWrap(UnjoinCommunity))
+41 -1
View File
@@ -1,6 +1,6 @@
/*
* Amsterdam Web Communities System
* Copyright (c) 2025 Erbosoft Metaverse Design Solutions, All Rights Reserved
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -11,6 +11,7 @@ package main
import (
"fmt"
"net/http"
"git.erbosoft.com/amy/amsterdam/database"
"git.erbosoft.com/amy/amsterdam/ui"
@@ -210,3 +211,42 @@ func AboutPage(ctxt ui.AmContext) (string, any, error) {
ctxt.VarMap().Set("amsterdam_pageTitle", "About Amsterdam")
return "framed_template", "about.jet", nil
}
/* JumpToShortcut resolves "/go" links by redirecting them to the appropriate page.
* Parameters:
* ctxt - The AmContext for the request.
* Returns:
* Command string dictating what to be rendered.
* Data as a parameter for the command string.
* Standard Go error status.
*/
func JumpToShortcut(ctxt ui.AmContext) (string, any, error) {
link, err := database.AmDecodePostLink(ctxt.URLParam("postlink"))
if err != nil {
ctxt.SetRC(http.StatusNotFound)
return ui.ErrorPage(ctxt, fmt.Errorf("not found: %s (%v)", ctxt.URLParam("postlink"), err))
}
scope, target := link.Classify()
if scope != "global" {
ctxt.SetRC(http.StatusNotFound)
return ui.ErrorPage(ctxt, fmt.Errorf("not found: %s", ctxt.URLParam("postlink")))
}
if err = link.VerifyNames(ctxt.Ctx()); err != nil {
ctxt.SetRC(http.StatusNotFound)
return ui.ErrorPage(ctxt, fmt.Errorf("not found: %s (%v)", ctxt.URLParam("postlink"), err))
}
targetURL := ""
switch target {
case "community":
targetURL = fmt.Sprintf("/comm/%s", link.Community)
case "conference":
targetURL = fmt.Sprintf("/comm/%s/conf/%s", link.Community, link.Conference)
case "topic":
targetURL = fmt.Sprintf("/comm/%s/conf/%s/r/%d", link.Community, link.Conference, link.Topic)
case "post", "postrange", "postopenrange":
targetURL = fmt.Sprintf("/comm/%s/conf/%s/r/%d?r=%d,%d", link.Community, link.Conference, link.Topic, link.FirstPost, link.LastPost)
default:
return ui.ErrorPage(ctxt, fmt.Errorf("invalid target '%s' for link: %s", target, ctxt.URLParam("postlink")))
}
return "redirect", targetURL, nil
}