mirror of
https://github.com/aykhans/slash-e.git
synced 2025-04-17 20:55:28 +00:00
feat: add public visibility
This commit is contained in:
parent
5a79304153
commit
469c841713
@ -4,6 +4,8 @@ package api
|
|||||||
type Visibility string
|
type Visibility string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// VisibilityPublic is the PUBLIC visibility.
|
||||||
|
VisibilityPublic Visibility = "PUBLIC"
|
||||||
// VisibilityWorkspace is the WORKSPACE visibility.
|
// VisibilityWorkspace is the WORKSPACE visibility.
|
||||||
VisibilityWorkspace Visibility = "WORKSPACE"
|
VisibilityWorkspace Visibility = "WORKSPACE"
|
||||||
// VisibilityPrivite is the PRIVATE visibility.
|
// VisibilityPrivite is the PRIVATE visibility.
|
||||||
@ -12,6 +14,8 @@ const (
|
|||||||
|
|
||||||
func (e Visibility) String() string {
|
func (e Visibility) String() string {
|
||||||
switch e {
|
switch e {
|
||||||
|
case VisibilityPublic:
|
||||||
|
return "PUBLIC"
|
||||||
case VisibilityWorkspace:
|
case VisibilityWorkspace:
|
||||||
return "WORKSPACE"
|
return "WORKSPACE"
|
||||||
case VisibilityPrivite:
|
case VisibilityPrivite:
|
||||||
|
@ -60,7 +60,9 @@ func aclMiddleware(s *Server, next echo.HandlerFunc) echo.HandlerFunc {
|
|||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
if common.HasPrefixes(path, "/api/ping", "/api/status", "/api/user/:id") && c.Request().Method == http.MethodGet {
|
println("path", path)
|
||||||
|
|
||||||
|
if common.HasPrefixes(path, "/api/ping", "/api/status", "/api/user/:id", "/api/workspace/:workspaceName/shortcut/:shortcutName") && c.Request().Method == http.MethodGet {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,11 +92,6 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) {
|
|||||||
|
|
||||||
g.GET("/workspace/:workspaceName/shortcut/:shortcutName", func(c echo.Context) error {
|
g.GET("/workspace/:workspaceName/shortcut/:shortcutName", func(c echo.Context) error {
|
||||||
ctx := c.Request().Context()
|
ctx := c.Request().Context()
|
||||||
userID, ok := c.Get(getUserIDContextKey()).(int)
|
|
||||||
if !ok {
|
|
||||||
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
|
|
||||||
}
|
|
||||||
|
|
||||||
workspaceName := c.Param("workspaceName")
|
workspaceName := c.Param("workspaceName")
|
||||||
shortcutName := c.Param("shortcutName")
|
shortcutName := c.Param("shortcutName")
|
||||||
if workspaceName == "" || shortcutName == "" {
|
if workspaceName == "" || shortcutName == "" {
|
||||||
@ -113,20 +108,6 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) {
|
|||||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find workspace with name %s", workspaceName)).SetInternal(err)
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find workspace with name %s", workspaceName)).SetInternal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
workspaceUser, err := s.Store.FindWordspaceUser(ctx, &api.WorkspaceUserFind{
|
|
||||||
WorkspaceID: &workspace.ID,
|
|
||||||
UserID: &userID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
if common.ErrorCode(err) == common.NotFound {
|
|
||||||
return echo.NewHTTPError(http.StatusNotFound, "workspace user not found")
|
|
||||||
}
|
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find workspace user").SetInternal(err)
|
|
||||||
}
|
|
||||||
if workspaceUser == nil {
|
|
||||||
return echo.NewHTTPError(http.StatusUnauthorized, "not workspace user")
|
|
||||||
}
|
|
||||||
|
|
||||||
shortcut, err := s.Store.FindShortcut(ctx, &api.ShortcutFind{
|
shortcut, err := s.Store.FindShortcut(ctx, &api.ShortcutFind{
|
||||||
WorkspaceID: &workspace.ID,
|
WorkspaceID: &workspace.ID,
|
||||||
Name: &shortcutName,
|
Name: &shortcutName,
|
||||||
@ -138,6 +119,27 @@ func (s *Server) registerWorkspaceRoutes(g *echo.Group) {
|
|||||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find shortcut with name %s", shortcutName)).SetInternal(err)
|
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Errorf("failed to find shortcut with name %s", shortcutName)).SetInternal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if shortcut.Visibility != api.VisibilityPublic {
|
||||||
|
userID, ok := c.Get(getUserIDContextKey()).(int)
|
||||||
|
if !ok {
|
||||||
|
return echo.NewHTTPError(http.StatusUnauthorized, "Missing user in session")
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaceUser, err := s.Store.FindWordspaceUser(ctx, &api.WorkspaceUserFind{
|
||||||
|
WorkspaceID: &workspace.ID,
|
||||||
|
UserID: &userID,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if common.ErrorCode(err) == common.NotFound {
|
||||||
|
return echo.NewHTTPError(http.StatusNotFound, "workspace user not found")
|
||||||
|
}
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find workspace user").SetInternal(err)
|
||||||
|
}
|
||||||
|
if workspaceUser == nil {
|
||||||
|
return echo.NewHTTPError(http.StatusUnauthorized, "not workspace user")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
|
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
|
||||||
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(shortcut)); err != nil {
|
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(shortcut)); err != nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode shortcut response").SetInternal(err)
|
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode shortcut response").SetInternal(err)
|
||||||
|
@ -116,7 +116,7 @@ CREATE TABLE shortcut (
|
|||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
link TEXT NOT NULL DEFAULT '',
|
link TEXT NOT NULL DEFAULT '',
|
||||||
description TEXT NOT NULL DEFAULT '',
|
description TEXT NOT NULL DEFAULT '',
|
||||||
visibility TEXT NOT NULL CHECK (visibility IN ('PRIVATE', 'WORKSPACE')) DEFAULT 'PRIVATE',
|
visibility TEXT NOT NULL CHECK (visibility IN ('PRIVATE', 'WORKSPACE', 'PUBLIC')) DEFAULT 'PRIVATE',
|
||||||
FOREIGN KEY(creator_id) REFERENCES user(id) ON DELETE CASCADE,
|
FOREIGN KEY(creator_id) REFERENCES user(id) ON DELETE CASCADE,
|
||||||
FOREIGN KEY(workspace_id) REFERENCES workspace(id) ON DELETE CASCADE
|
FOREIGN KEY(workspace_id) REFERENCES workspace(id) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
@ -9,6 +9,6 @@ VALUES
|
|||||||
(
|
(
|
||||||
11,
|
11,
|
||||||
101,
|
101,
|
||||||
'Demo',
|
'demo',
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
|
@ -16,3 +16,22 @@ VALUES
|
|||||||
'百度搜索',
|
'百度搜索',
|
||||||
'WORKSPACE'
|
'WORKSPACE'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
INSERT INTO
|
||||||
|
shortcut (
|
||||||
|
`creator_id`,
|
||||||
|
`workspace_id`,
|
||||||
|
`name`,
|
||||||
|
`link`,
|
||||||
|
`description`,
|
||||||
|
`visibility`
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(
|
||||||
|
102,
|
||||||
|
11,
|
||||||
|
'bl',
|
||||||
|
'https://bilibili.com',
|
||||||
|
'B站',
|
||||||
|
'PUBLIC'
|
||||||
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Route, Routes, useNavigate } from "react-router-dom";
|
import { Route, Routes, useLocation, useNavigate } from "react-router-dom";
|
||||||
import { userService, workspaceService } from "./services";
|
import { userService, workspaceService } from "./services";
|
||||||
import useLoading from "./hooks/useLoading";
|
import useLoading from "./hooks/useLoading";
|
||||||
import Only from "./components/common/OnlyWhen";
|
import Only from "./components/common/OnlyWhen";
|
||||||
@ -9,11 +9,27 @@ import WorkspaceDetail from "./pages/WorkspaceDetail";
|
|||||||
import UserDetail from "./pages/UserDetail";
|
import UserDetail from "./pages/UserDetail";
|
||||||
import ShortcutRedirector from "./pages/ShortcutRedirector";
|
import ShortcutRedirector from "./pages/ShortcutRedirector";
|
||||||
|
|
||||||
|
const pathnameWhitelist = [/\/.+?\/go\/.+/];
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
const pageLoadingStatus = useLoading();
|
const pageLoadingStatus = useLoading();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
let needAuth = true;
|
||||||
|
|
||||||
|
for (const regexp of pathnameWhitelist) {
|
||||||
|
if (regexp.test(location.pathname)) {
|
||||||
|
needAuth = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!needAuth) {
|
||||||
|
pageLoadingStatus.setFinish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
userService.initialState().finally(() => {
|
userService.initialState().finally(() => {
|
||||||
if (!userService.getState().user) {
|
if (!userService.getState().user) {
|
||||||
pageLoadingStatus.setFinish();
|
pageLoadingStatus.setFinish();
|
||||||
|
@ -148,7 +148,7 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
|||||||
checked={state.shortcutCreate.visibility === "PRIVATE"}
|
checked={state.shortcutCreate.visibility === "PRIVATE"}
|
||||||
/>
|
/>
|
||||||
<label htmlFor="visibility-private" className="ml-1 mr-4">
|
<label htmlFor="visibility-private" className="ml-1 mr-4">
|
||||||
Only for myself
|
Private
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
@ -158,8 +158,19 @@ const CreateShortcutDialog: React.FC<Props> = (props: Props) => {
|
|||||||
onChange={handleVisibilityInputChange}
|
onChange={handleVisibilityInputChange}
|
||||||
checked={state.shortcutCreate.visibility === "WORKSPACE"}
|
checked={state.shortcutCreate.visibility === "WORKSPACE"}
|
||||||
/>
|
/>
|
||||||
<label htmlFor="visibility-workspace" className="ml-1">
|
<label htmlFor="visibility-workspace" className="ml-1 mr-4">
|
||||||
Public in workspace
|
Workspace
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="visibility"
|
||||||
|
id="visibility-public"
|
||||||
|
value="PUBLIC"
|
||||||
|
onChange={handleVisibilityInputChange}
|
||||||
|
checked={state.shortcutCreate.visibility === "PUBLIC"}
|
||||||
|
/>
|
||||||
|
<label htmlFor="visibility-public" className="ml-1">
|
||||||
|
Public
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
2
web/src/types/modules/shortcut.d.ts
vendored
2
web/src/types/modules/shortcut.d.ts
vendored
@ -1,6 +1,6 @@
|
|||||||
type ShortcutId = number;
|
type ShortcutId = number;
|
||||||
|
|
||||||
type Visibility = "PRIVATE" | "WORKSPACE";
|
type Visibility = "PRIVATE" | "WORKSPACE" | "PUBLIC";
|
||||||
|
|
||||||
interface Shortcut {
|
interface Shortcut {
|
||||||
id: ShortcutId;
|
id: ShortcutId;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user