feat: add /api/web/user/sign-out and nest user info under /user/info (#8284)

This commit is contained in:
ᴊᴏᴇ ᴄʜᴇɴ
2026-05-21 15:05:19 -04:00
committed by GitHub
parent 90790b2966
commit c93373baec
3 changed files with 52 additions and 7 deletions
+30 -5
View File
@@ -6,23 +6,36 @@ import (
"net/http"
"github.com/flamego/flamego"
"github.com/go-macaron/session"
"gopkg.in/macaron.v1"
"gogs.io/gogs/internal/conf"
"gogs.io/gogs/internal/context"
"gogs.io/gogs/internal/database"
)
type webAPIBridgeKey struct{}
type (
webAPIUserKey struct{}
webAPISessionKey struct{}
webAPIMacaronKey struct{}
)
func bridgeToWebAPI(webHandler http.Handler) func(c *context.Context) {
return func(c *context.Context) {
ctx := stdctx.WithValue(c.Req.Context(), webAPIBridgeKey{}, c.User)
ctx := c.Req.Context()
ctx = stdctx.WithValue(ctx, webAPIUserKey{}, c.User)
ctx = stdctx.WithValue(ctx, webAPISessionKey{}, c.Session)
ctx = stdctx.WithValue(ctx, webAPIMacaronKey{}, c.Context)
webHandler.ServeHTTP(c.Resp, c.Req.WithContext(ctx))
}
}
func webAPIInjector(c flamego.Context) {
user, _ := c.Request().Context().Value(webAPIBridgeKey{}).(*database.User)
c.Map(user)
ctx := c.Request().Context()
user, _ := ctx.Value(webAPIUserKey{}).(*database.User)
sess, _ := ctx.Value(webAPISessionKey{}).(session.Store)
mc, _ := ctx.Value(webAPIMacaronKey{}).(*macaron.Context)
c.Map(user, sess, mc)
}
func mountWebAPIRoutes(f *flamego.Flame) {
@@ -45,7 +58,10 @@ func mountWebAPIRoutes(f *flamego.Flame) {
})
f.Group("/api/web", func() {
f.Get("/user-info", userInfoHandler)
f.Group("/user", func() {
f.Get("/info", userInfoHandler)
f.Post("/sign-out", userSignOutHandler)
})
}, webAPIInjector)
}
@@ -69,3 +85,12 @@ func userInfoHandler(user *database.User) (statusCode int, resp *userInfo, err e
},
nil
}
func userSignOutHandler(sess session.Store, mc *macaron.Context) (statusCode int, resp any, err error) {
_ = sess.Flush()
_ = sess.Destory(mc)
mc.SetCookie(conf.Security.CookieUsername, "", -1, conf.Server.Subpath)
mc.SetCookie(conf.Security.CookieRememberName, "", -1, conf.Server.Subpath)
mc.SetCookie(conf.Session.CSRFCookieName, "", -1, conf.Server.Subpath)
return http.StatusNoContent, nil, nil
}
+21 -1
View File
@@ -305,12 +305,32 @@ function NavLink({ href, external, children }: { href: string; external?: boolea
function SignOutForm({ children }: { children: React.ReactNode }) {
return (
<form action={subUrl("/user/logout")} method="POST" className="inline">
<form
action={subUrl("/api/web/user/sign-out")}
method="POST"
className="inline"
onSubmit={(event) => {
event.preventDefault();
void signOut();
}}
>
{children}
</form>
);
}
async function signOut() {
try {
await fetch(subUrl("/api/web/user/sign-out"), {
method: "POST",
credentials: "same-origin",
});
} catch (err) {
console.error("signOut: request failed", err);
}
window.location.assign(subUrl("/"));
}
function MobileLink({
href,
external,
+1 -1
View File
@@ -9,7 +9,7 @@ export interface UserInfo {
export async function fetchUserInfo(): Promise<UserInfo | null> {
try {
const res = await fetch(subUrl("/api/web/user-info"), { credentials: "same-origin" });
const res = await fetch(subUrl("/api/web/user/info"), { credentials: "same-origin" });
if (res.status === 204) return null;
if (!res.ok) {
console.error(`fetchUserInfo: unexpected status ${res.status}`);