feat: support multiple type shortcuts link

This commit is contained in:
Steven 2023-07-01 00:17:30 +08:00
parent fbf958cf3e
commit fc27490766
4 changed files with 48 additions and 16 deletions

View File

@ -3,6 +3,7 @@ package v1
import (
"encoding/json"
"net/http"
"net/url"
"github.com/boojack/shortify/store"
"github.com/labstack/echo/v4"
@ -39,7 +40,10 @@ func (s *APIV1Service) registerRedirectorRoutes(g *echo.Group) {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create activity").SetInternal(err)
}
return c.Redirect(http.StatusSeeOther, shortcut.Link)
if isValidURLString(shortcut.Link) {
return c.Redirect(http.StatusSeeOther, shortcut.Link)
}
return c.String(http.StatusOK, shortcut.Link)
})
}
@ -66,3 +70,8 @@ func (s *APIV1Service) createShortcutViewActivity(c echo.Context, shortcut *stor
}
return nil
}
func isValidURLString(s string) bool {
_, err := url.ParseRequestURI(s)
return err == nil
}

33
api/v1/redirector_test.go Normal file
View File

@ -0,0 +1,33 @@
package v1
import "testing"
func TestIsValidURLString(t *testing.T) {
tests := []struct {
link string
expected bool
}{
{
link: "https://google.com",
expected: true,
},
{
link: "http://google.com",
expected: true,
},
{
link: "google.com",
expected: false,
},
{
link: "mailto:email@example.com",
expected: true,
},
}
for _, test := range tests {
if isValidURLString(test.link) != test.expected {
t.Errorf("isValidURLString(%s) = %v, expected %v", test.link, !test.expected, test.expected)
}
}
}

View File

@ -8,7 +8,6 @@ import (
"strconv"
"strings"
"github.com/boojack/shortify/internal/util"
"github.com/boojack/shortify/store"
"github.com/pkg/errors"
@ -86,9 +85,6 @@ func (s *APIV1Service) registerShortcutRoutes(g *echo.Group) {
if err := json.NewDecoder(c.Request().Body).Decode(create); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post shortcut request").SetInternal(err)
}
if !validateLink(create.Link) {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid link: %s", create.Link))
}
shortcut, err := s.Store.CreateShortcut(ctx, &store.Shortcut{
CreatorID: userID,
@ -151,9 +147,6 @@ func (s *APIV1Service) registerShortcutRoutes(g *echo.Group) {
name := strings.ToLower(*patch.Name)
patch.Name = &name
}
if patch.Link != nil && !validateLink(*patch.Link) {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid link: %s", *patch.Link))
}
shortcutUpdate := &store.UpdateShortcut{
ID: shortcutID,
@ -369,7 +362,3 @@ func convertShortcutFromStore(shortcut *store.Shortcut) *Shortcut {
Tags: tags,
}
}
func validateLink(link string) bool {
return util.HasPrefixes(link, "http://", "https://")
}

View File

@ -24,6 +24,7 @@ const ShortcutView = (props: Props) => {
const faviconStore = useFaviconStore();
const [favicon, setFavicon] = useState<string | undefined>(undefined);
const havePermission = user.role === "ADMIN" || shortcut.creatorId === user.id;
const shortifyLink = absolutifyLink(`/s/${shortcut.name}`);
useEffect(() => {
faviconStore.getOrFetchUrlFavicon(shortcut.link).then((url) => {
@ -33,8 +34,8 @@ const ShortcutView = (props: Props) => {
});
}, [shortcut.link]);
const handleCopyButtonClick = (shortcut: Shortcut) => {
copy(absolutifyLink(`/s/${shortcut.name}`));
const handleCopyButtonClick = () => {
copy(shortifyLink);
toast.success("Shortcut link copied to clipboard.");
};
@ -60,11 +61,11 @@ const ShortcutView = (props: Props) => {
<Icon.Globe2 className="w-5 h-auto text-gray-500" />
)}
</div>
<button className="items-center cursor-pointer hover:opacity-80" onClick={() => handleCopyButtonClick(shortcut)}>
<button className="items-center cursor-pointer hover:opacity-80" onClick={() => handleCopyButtonClick()}>
<span className="text-gray-400">s/</span>
{shortcut.name}
</button>
<a className="hidden group-hover:block ml-1 cursor-pointer hover:opacity-80" target="_blank" href={shortcut.link}>
<a className="hidden group-hover:block ml-1 cursor-pointer hover:opacity-80" target="_blank" href={shortifyLink}>
<Icon.ExternalLink className="w-4 h-auto text-gray-500" />
</a>
</div>