mirror of
https://github.com/gogs/gogs.git
synced 2026-05-28 21:30:36 +00:00
feat: add /api/web/user/sign-out and nest user info under /user/info (#8284)
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
Reference in New Issue
Block a user