mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-27 12:53:57 +01:00
Add ContextUser
to http request context (#18798)
This PR adds a middleware which sets a ContextUser (like GetUserByParams before) in a single place which can be used by other methods. For routes which represent a repo or org the respective middlewares set the field too. Also fix a bug in modules/context/org.go during refactoring.
This commit is contained in:
parent
f36701c702
commit
59b867dc2d
23 changed files with 247 additions and 323 deletions
|
@ -133,7 +133,7 @@ func TestUnknowUser(t *testing.T) {
|
||||||
|
|
||||||
var apiError api.APIError
|
var apiError api.APIError
|
||||||
DecodeJSON(t, resp, &apiError)
|
DecodeJSON(t, resp, &apiError)
|
||||||
assert.Equal(t, "GetUserByName", apiError.Message)
|
assert.Equal(t, "user redirect does not exist [name: unknow]", apiError.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnknowOrganization(t *testing.T) {
|
func TestUnknowOrganization(t *testing.T) {
|
||||||
|
|
|
@ -67,8 +67,9 @@ type Context struct {
|
||||||
IsSigned bool
|
IsSigned bool
|
||||||
IsBasicAuth bool
|
IsBasicAuth bool
|
||||||
|
|
||||||
Repo *Repository
|
ContextUser *user_model.User
|
||||||
Org *Organization
|
Repo *Repository
|
||||||
|
Org *Organization
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrHTMLEscapeArgs runs Tr but pre-escapes all arguments with html.EscapeString.
|
// TrHTMLEscapeArgs runs Tr but pre-escapes all arguments with html.EscapeString.
|
||||||
|
|
|
@ -53,7 +53,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
|
||||||
var err error
|
var err error
|
||||||
ctx.Org.Organization, err = models.GetOrgByName(orgName)
|
ctx.Org.Organization, err = models.GetOrgByName(orgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if user_model.IsErrUserNotExist(err) {
|
if models.IsErrOrgNotExist(err) {
|
||||||
redirectUserID, err := user_model.LookupUserRedirect(orgName)
|
redirectUserID, err := user_model.LookupUserRedirect(orgName)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
RedirectToUser(ctx, orgName, redirectUserID)
|
RedirectToUser(ctx, orgName, redirectUserID)
|
||||||
|
@ -68,6 +68,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
org := ctx.Org.Organization
|
org := ctx.Org.Organization
|
||||||
|
ctx.ContextUser = org.AsUser()
|
||||||
ctx.Data["Org"] = org
|
ctx.Data["Org"] = org
|
||||||
|
|
||||||
teams, err := org.LoadTeams()
|
teams, err := org.LoadTeams()
|
||||||
|
|
|
@ -439,6 +439,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.Repo.Owner = owner
|
ctx.Repo.Owner = owner
|
||||||
|
ctx.ContextUser = owner
|
||||||
ctx.Data["Username"] = ctx.Repo.Owner.Name
|
ctx.Data["Username"] = ctx.Repo.Owner.Name
|
||||||
|
|
||||||
// redirect link to wiki
|
// redirect link to wiki
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"code.gitea.io/gitea/modules/convert"
|
"code.gitea.io/gitea/modules/convert"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/routers/api/v1/user"
|
|
||||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,11 +44,8 @@ func CreateOrg(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/forbidden"
|
// "$ref": "#/responses/forbidden"
|
||||||
// "422":
|
// "422":
|
||||||
// "$ref": "#/responses/validationError"
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.CreateOrgOption)
|
form := web.GetForm(ctx).(*api.CreateOrgOption)
|
||||||
u := user.GetUserByParams(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
visibility := api.VisibleTypePublic
|
visibility := api.VisibleTypePublic
|
||||||
if form.Visibility != "" {
|
if form.Visibility != "" {
|
||||||
|
@ -67,7 +63,7 @@ func CreateOrg(ctx *context.APIContext) {
|
||||||
Visibility: visibility,
|
Visibility: visibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.CreateOrganization(org, u); err != nil {
|
if err := models.CreateOrganization(org, ctx.ContextUser); err != nil {
|
||||||
if user_model.IsErrUserAlreadyExist(err) ||
|
if user_model.IsErrUserAlreadyExist(err) ||
|
||||||
db.IsErrNameReserved(err) ||
|
db.IsErrNameReserved(err) ||
|
||||||
db.IsErrNameCharsNotAllowed(err) ||
|
db.IsErrNameCharsNotAllowed(err) ||
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/routers/api/v1/repo"
|
"code.gitea.io/gitea/routers/api/v1/repo"
|
||||||
"code.gitea.io/gitea/routers/api/v1/user"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateRepo api for creating a repository
|
// CreateRepo api for creating a repository
|
||||||
|
@ -42,11 +41,8 @@ func CreateRepo(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/error"
|
// "$ref": "#/responses/error"
|
||||||
// "422":
|
// "422":
|
||||||
// "$ref": "#/responses/validationError"
|
// "$ref": "#/responses/validationError"
|
||||||
form := web.GetForm(ctx).(*api.CreateRepoOption)
|
|
||||||
owner := user.GetUserByParams(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
repo.CreateUserRepo(ctx, owner, *form)
|
form := web.GetForm(ctx).(*api.CreateRepoOption)
|
||||||
|
|
||||||
|
repo.CreateUserRepo(ctx, ctx.ContextUser, *form)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ func CreateUser(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/forbidden"
|
// "$ref": "#/responses/forbidden"
|
||||||
// "422":
|
// "422":
|
||||||
// "$ref": "#/responses/validationError"
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.CreateUserOption)
|
form := web.GetForm(ctx).(*api.CreateUserOption)
|
||||||
|
|
||||||
u := &user_model.User{
|
u := &user_model.User{
|
||||||
|
@ -163,13 +164,10 @@ func EditUser(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/forbidden"
|
// "$ref": "#/responses/forbidden"
|
||||||
// "422":
|
// "422":
|
||||||
// "$ref": "#/responses/validationError"
|
// "$ref": "#/responses/validationError"
|
||||||
form := web.GetForm(ctx).(*api.EditUserOption)
|
|
||||||
u := user.GetUserByParams(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
parseAuthSource(ctx, u, form.SourceID, form.LoginName)
|
form := web.GetForm(ctx).(*api.EditUserOption)
|
||||||
|
|
||||||
|
parseAuthSource(ctx, ctx.ContextUser, form.SourceID, form.LoginName)
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -193,24 +191,24 @@ func EditUser(ctx *context.APIContext) {
|
||||||
ctx.Error(http.StatusBadRequest, "PasswordPwned", errors.New("PasswordPwned"))
|
ctx.Error(http.StatusBadRequest, "PasswordPwned", errors.New("PasswordPwned"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if u.Salt, err = user_model.GetUserSalt(); err != nil {
|
if ctx.ContextUser.Salt, err = user_model.GetUserSalt(); err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
|
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = u.SetPassword(form.Password); err != nil {
|
if err = ctx.ContextUser.SetPassword(form.Password); err != nil {
|
||||||
ctx.InternalServerError(err)
|
ctx.InternalServerError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if form.MustChangePassword != nil {
|
if form.MustChangePassword != nil {
|
||||||
u.MustChangePassword = *form.MustChangePassword
|
ctx.ContextUser.MustChangePassword = *form.MustChangePassword
|
||||||
}
|
}
|
||||||
|
|
||||||
u.LoginName = form.LoginName
|
ctx.ContextUser.LoginName = form.LoginName
|
||||||
|
|
||||||
if form.FullName != nil {
|
if form.FullName != nil {
|
||||||
u.FullName = *form.FullName
|
ctx.ContextUser.FullName = *form.FullName
|
||||||
}
|
}
|
||||||
var emailChanged bool
|
var emailChanged bool
|
||||||
if form.Email != nil {
|
if form.Email != nil {
|
||||||
|
@ -225,47 +223,47 @@ func EditUser(ctx *context.APIContext) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
emailChanged = !strings.EqualFold(u.Email, email)
|
emailChanged = !strings.EqualFold(ctx.ContextUser.Email, email)
|
||||||
u.Email = email
|
ctx.ContextUser.Email = email
|
||||||
}
|
}
|
||||||
if form.Website != nil {
|
if form.Website != nil {
|
||||||
u.Website = *form.Website
|
ctx.ContextUser.Website = *form.Website
|
||||||
}
|
}
|
||||||
if form.Location != nil {
|
if form.Location != nil {
|
||||||
u.Location = *form.Location
|
ctx.ContextUser.Location = *form.Location
|
||||||
}
|
}
|
||||||
if form.Description != nil {
|
if form.Description != nil {
|
||||||
u.Description = *form.Description
|
ctx.ContextUser.Description = *form.Description
|
||||||
}
|
}
|
||||||
if form.Active != nil {
|
if form.Active != nil {
|
||||||
u.IsActive = *form.Active
|
ctx.ContextUser.IsActive = *form.Active
|
||||||
}
|
}
|
||||||
if len(form.Visibility) != 0 {
|
if len(form.Visibility) != 0 {
|
||||||
u.Visibility = api.VisibilityModes[form.Visibility]
|
ctx.ContextUser.Visibility = api.VisibilityModes[form.Visibility]
|
||||||
}
|
}
|
||||||
if form.Admin != nil {
|
if form.Admin != nil {
|
||||||
u.IsAdmin = *form.Admin
|
ctx.ContextUser.IsAdmin = *form.Admin
|
||||||
}
|
}
|
||||||
if form.AllowGitHook != nil {
|
if form.AllowGitHook != nil {
|
||||||
u.AllowGitHook = *form.AllowGitHook
|
ctx.ContextUser.AllowGitHook = *form.AllowGitHook
|
||||||
}
|
}
|
||||||
if form.AllowImportLocal != nil {
|
if form.AllowImportLocal != nil {
|
||||||
u.AllowImportLocal = *form.AllowImportLocal
|
ctx.ContextUser.AllowImportLocal = *form.AllowImportLocal
|
||||||
}
|
}
|
||||||
if form.MaxRepoCreation != nil {
|
if form.MaxRepoCreation != nil {
|
||||||
u.MaxRepoCreation = *form.MaxRepoCreation
|
ctx.ContextUser.MaxRepoCreation = *form.MaxRepoCreation
|
||||||
}
|
}
|
||||||
if form.AllowCreateOrganization != nil {
|
if form.AllowCreateOrganization != nil {
|
||||||
u.AllowCreateOrganization = *form.AllowCreateOrganization
|
ctx.ContextUser.AllowCreateOrganization = *form.AllowCreateOrganization
|
||||||
}
|
}
|
||||||
if form.ProhibitLogin != nil {
|
if form.ProhibitLogin != nil {
|
||||||
u.ProhibitLogin = *form.ProhibitLogin
|
ctx.ContextUser.ProhibitLogin = *form.ProhibitLogin
|
||||||
}
|
}
|
||||||
if form.Restricted != nil {
|
if form.Restricted != nil {
|
||||||
u.IsRestricted = *form.Restricted
|
ctx.ContextUser.IsRestricted = *form.Restricted
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := user_model.UpdateUser(u, emailChanged); err != nil {
|
if err := user_model.UpdateUser(ctx.ContextUser, emailChanged); err != nil {
|
||||||
if user_model.IsErrEmailAlreadyUsed(err) ||
|
if user_model.IsErrEmailAlreadyUsed(err) ||
|
||||||
user_model.IsErrEmailCharIsNotSupported(err) ||
|
user_model.IsErrEmailCharIsNotSupported(err) ||
|
||||||
user_model.IsErrEmailInvalid(err) {
|
user_model.IsErrEmailInvalid(err) {
|
||||||
|
@ -275,9 +273,9 @@ func EditUser(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Trace("Account profile updated by admin (%s): %s", ctx.Doer.Name, u.Name)
|
log.Trace("Account profile updated by admin (%s): %s", ctx.Doer.Name, ctx.ContextUser.Name)
|
||||||
|
|
||||||
ctx.JSON(http.StatusOK, convert.ToUser(u, ctx.Doer))
|
ctx.JSON(http.StatusOK, convert.ToUser(ctx.ContextUser, ctx.Doer))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUser api for deleting a user
|
// DeleteUser api for deleting a user
|
||||||
|
@ -301,17 +299,12 @@ func DeleteUser(ctx *context.APIContext) {
|
||||||
// "422":
|
// "422":
|
||||||
// "$ref": "#/responses/validationError"
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
u := user.GetUserByParams(ctx)
|
if ctx.ContextUser.IsOrganization() {
|
||||||
if ctx.Written() {
|
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("%s is an organization not a user", ctx.ContextUser.Name))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.IsOrganization() {
|
if err := user_service.DeleteUser(ctx.ContextUser); err != nil {
|
||||||
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("%s is an organization not a user", u.Name))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := user_service.DeleteUser(u); err != nil {
|
|
||||||
if models.IsErrUserOwnRepos(err) ||
|
if models.IsErrUserOwnRepos(err) ||
|
||||||
models.IsErrUserHasOrgs(err) {
|
models.IsErrUserHasOrgs(err) {
|
||||||
ctx.Error(http.StatusUnprocessableEntity, "", err)
|
ctx.Error(http.StatusUnprocessableEntity, "", err)
|
||||||
|
@ -320,7 +313,7 @@ func DeleteUser(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Trace("Account deleted by admin(%s): %s", ctx.Doer.Name, u.Name)
|
log.Trace("Account deleted by admin(%s): %s", ctx.Doer.Name, ctx.ContextUser.Name)
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
@ -351,12 +344,10 @@ func CreatePublicKey(ctx *context.APIContext) {
|
||||||
// "$ref": "#/responses/forbidden"
|
// "$ref": "#/responses/forbidden"
|
||||||
// "422":
|
// "422":
|
||||||
// "$ref": "#/responses/validationError"
|
// "$ref": "#/responses/validationError"
|
||||||
|
|
||||||
form := web.GetForm(ctx).(*api.CreateKeyOption)
|
form := web.GetForm(ctx).(*api.CreateKeyOption)
|
||||||
u := user.GetUserByParams(ctx)
|
|
||||||
if ctx.Written() {
|
user.CreateUserPublicKey(ctx, *form, ctx.ContextUser.ID)
|
||||||
return
|
|
||||||
}
|
|
||||||
user.CreateUserPublicKey(ctx, *form, u.ID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteUserPublicKey api for deleting a user's public key
|
// DeleteUserPublicKey api for deleting a user's public key
|
||||||
|
@ -386,12 +377,7 @@ func DeleteUserPublicKey(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
u := user.GetUserByParams(ctx)
|
if err := asymkey_service.DeletePublicKey(ctx.ContextUser, ctx.ParamsInt64(":id")); err != nil {
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := asymkey_service.DeletePublicKey(u, ctx.ParamsInt64(":id")); err != nil {
|
|
||||||
if asymkey_model.IsErrKeyNotExist(err) {
|
if asymkey_model.IsErrKeyNotExist(err) {
|
||||||
ctx.NotFound()
|
ctx.NotFound()
|
||||||
} else if asymkey_model.IsErrKeyAccessDenied(err) {
|
} else if asymkey_model.IsErrKeyAccessDenied(err) {
|
||||||
|
@ -401,7 +387,7 @@ func DeleteUserPublicKey(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Trace("Key deleted by admin(%s): %s", ctx.Doer.Name, u.Name)
|
log.Trace("Key deleted by admin(%s): %s", ctx.Doer.Name, ctx.ContextUser.Name)
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,7 @@ import (
|
||||||
"code.gitea.io/gitea/routers/api/v1/settings"
|
"code.gitea.io/gitea/routers/api/v1/settings"
|
||||||
"code.gitea.io/gitea/routers/api/v1/user"
|
"code.gitea.io/gitea/routers/api/v1/user"
|
||||||
"code.gitea.io/gitea/services/auth"
|
"code.gitea.io/gitea/services/auth"
|
||||||
|
context_service "code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
|
|
||||||
_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
|
_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
|
||||||
|
@ -156,6 +157,7 @@ func repoAssignment() func(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.Repo.Owner = owner
|
ctx.Repo.Owner = owner
|
||||||
|
ctx.ContextUser = owner
|
||||||
|
|
||||||
// Get repository.
|
// Get repository.
|
||||||
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
|
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
|
||||||
|
@ -441,6 +443,7 @@ func orgAssignment(args ...bool) func(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
ctx.ContextUser = ctx.Org.Organization.AsUser()
|
||||||
}
|
}
|
||||||
|
|
||||||
if assignTeam {
|
if assignTeam {
|
||||||
|
@ -636,7 +639,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||||
Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken)
|
Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken)
|
||||||
m.Combo("/{id}").Delete(user.DeleteAccessToken)
|
m.Combo("/{id}").Delete(user.DeleteAccessToken)
|
||||||
}, reqBasicOrRevProxyAuth())
|
}, reqBasicOrRevProxyAuth())
|
||||||
})
|
}, context_service.UserAssignmentAPI())
|
||||||
})
|
})
|
||||||
|
|
||||||
m.Group("/users", func() {
|
m.Group("/users", func() {
|
||||||
|
@ -653,7 +656,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||||
m.Get("/starred", user.GetStarredRepos)
|
m.Get("/starred", user.GetStarredRepos)
|
||||||
|
|
||||||
m.Get("/subscriptions", user.GetWatchedRepos)
|
m.Get("/subscriptions", user.GetWatchedRepos)
|
||||||
})
|
}, context_service.UserAssignmentAPI())
|
||||||
}, reqToken())
|
}, reqToken())
|
||||||
|
|
||||||
m.Group("/user", func() {
|
m.Group("/user", func() {
|
||||||
|
@ -669,7 +672,11 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||||
m.Get("/followers", user.ListMyFollowers)
|
m.Get("/followers", user.ListMyFollowers)
|
||||||
m.Group("/following", func() {
|
m.Group("/following", func() {
|
||||||
m.Get("", user.ListMyFollowing)
|
m.Get("", user.ListMyFollowing)
|
||||||
m.Combo("/{username}").Get(user.CheckMyFollowing).Put(user.Follow).Delete(user.Unfollow)
|
m.Group("/{username}", func() {
|
||||||
|
m.Get("", user.CheckMyFollowing)
|
||||||
|
m.Put("", user.Follow)
|
||||||
|
m.Delete("", user.Unfollow)
|
||||||
|
}, context_service.UserAssignmentAPI())
|
||||||
})
|
})
|
||||||
|
|
||||||
m.Group("/keys", func() {
|
m.Group("/keys", func() {
|
||||||
|
@ -1005,7 +1012,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||||
m.Group("/users/{username}/orgs", func() {
|
m.Group("/users/{username}/orgs", func() {
|
||||||
m.Get("", org.ListUserOrgs)
|
m.Get("", org.ListUserOrgs)
|
||||||
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
|
m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions)
|
||||||
})
|
}, context_service.UserAssignmentAPI())
|
||||||
m.Post("/orgs", reqToken(), bind(api.CreateOrgOption{}), org.Create)
|
m.Post("/orgs", reqToken(), bind(api.CreateOrgOption{}), org.Create)
|
||||||
m.Get("/orgs", org.GetAll)
|
m.Get("/orgs", org.GetAll)
|
||||||
m.Group("/orgs/{org}", func() {
|
m.Group("/orgs/{org}", func() {
|
||||||
|
@ -1083,7 +1090,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||||
m.Get("/orgs", org.ListUserOrgs)
|
m.Get("/orgs", org.ListUserOrgs)
|
||||||
m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg)
|
m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg)
|
||||||
m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
|
m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
|
||||||
})
|
}, context_service.UserAssignmentAPI())
|
||||||
})
|
})
|
||||||
m.Group("/unadopted", func() {
|
m.Group("/unadopted", func() {
|
||||||
m.Get("", admin.ListUnadoptedRepositories)
|
m.Get("", admin.ListUnadoptedRepositories)
|
||||||
|
|
|
@ -99,11 +99,7 @@ func ListUserOrgs(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/OrganizationList"
|
// "$ref": "#/responses/OrganizationList"
|
||||||
|
|
||||||
u := user.GetUserByParams(ctx)
|
listUserOrgs(ctx, ctx.ContextUser)
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
listUserOrgs(ctx, u)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserOrgsPermissions get user permissions in organization
|
// GetUserOrgsPermissions get user permissions in organization
|
||||||
|
@ -132,11 +128,6 @@ func GetUserOrgsPermissions(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
var u *user_model.User
|
|
||||||
if u = user.GetUserByParams(ctx); u == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var o *user_model.User
|
var o *user_model.User
|
||||||
if o = user.GetUserByParamsName(ctx, ":org"); o == nil {
|
if o = user.GetUserByParamsName(ctx, ":org"); o == nil {
|
||||||
return
|
return
|
||||||
|
@ -144,13 +135,13 @@ func GetUserOrgsPermissions(ctx *context.APIContext) {
|
||||||
|
|
||||||
op := api.OrganizationPermissions{}
|
op := api.OrganizationPermissions{}
|
||||||
|
|
||||||
if !models.HasOrgOrUserVisible(o, u) {
|
if !models.HasOrgOrUserVisible(o, ctx.ContextUser) {
|
||||||
ctx.NotFound("HasOrgOrUserVisible", nil)
|
ctx.NotFound("HasOrgOrUserVisible", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
org := models.OrgFromUser(o)
|
org := models.OrgFromUser(o)
|
||||||
authorizeLevel, err := org.GetOrgUserMaxAuthorizeLevel(u.ID)
|
authorizeLevel, err := org.GetOrgUserMaxAuthorizeLevel(ctx.ContextUser.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetOrgUserAuthorizeLevel", err)
|
ctx.Error(http.StatusInternalServerError, "GetOrgUserAuthorizeLevel", err)
|
||||||
return
|
return
|
||||||
|
@ -169,7 +160,7 @@ func GetUserOrgsPermissions(ctx *context.APIContext) {
|
||||||
op.IsOwner = true
|
op.IsOwner = true
|
||||||
}
|
}
|
||||||
|
|
||||||
op.CanCreateRepository, err = org.CanCreateOrgRepo(u.ID)
|
op.CanCreateRepository, err = org.CanCreateOrgRepo(ctx.ContextUser.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "CanCreateOrgRepo", err)
|
ctx.Error(http.StatusInternalServerError, "CanCreateOrgRepo", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -82,11 +82,7 @@ func ListFollowers(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/UserList"
|
// "$ref": "#/responses/UserList"
|
||||||
|
|
||||||
u := GetUserByParams(ctx)
|
listUserFollowers(ctx, ctx.ContextUser)
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
listUserFollowers(ctx, u)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func listUserFollowing(ctx *context.APIContext, u *user_model.User) {
|
func listUserFollowing(ctx *context.APIContext, u *user_model.User) {
|
||||||
|
@ -148,11 +144,7 @@ func ListFollowing(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/UserList"
|
// "$ref": "#/responses/UserList"
|
||||||
|
|
||||||
u := GetUserByParams(ctx)
|
listUserFollowing(ctx, ctx.ContextUser)
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
listUserFollowing(ctx, u)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkUserFollowing(ctx *context.APIContext, u *user_model.User, followID int64) {
|
func checkUserFollowing(ctx *context.APIContext, u *user_model.User, followID int64) {
|
||||||
|
@ -180,25 +172,21 @@ func CheckMyFollowing(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
target := GetUserByParams(ctx)
|
checkUserFollowing(ctx, ctx.Doer, ctx.ContextUser.ID)
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
checkUserFollowing(ctx, ctx.Doer, target.ID)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckFollowing check if one user is following another user
|
// CheckFollowing check if one user is following another user
|
||||||
func CheckFollowing(ctx *context.APIContext) {
|
func CheckFollowing(ctx *context.APIContext) {
|
||||||
// swagger:operation GET /users/{follower}/following/{followee} user userCheckFollowing
|
// swagger:operation GET /users/{username}/following/{target} user userCheckFollowing
|
||||||
// ---
|
// ---
|
||||||
// summary: Check if one user is following another user
|
// summary: Check if one user is following another user
|
||||||
// parameters:
|
// parameters:
|
||||||
// - name: follower
|
// - name: username
|
||||||
// in: path
|
// in: path
|
||||||
// description: username of following user
|
// description: username of following user
|
||||||
// type: string
|
// type: string
|
||||||
// required: true
|
// required: true
|
||||||
// - name: followee
|
// - name: target
|
||||||
// in: path
|
// in: path
|
||||||
// description: username of followed user
|
// description: username of followed user
|
||||||
// type: string
|
// type: string
|
||||||
|
@ -209,15 +197,11 @@ func CheckFollowing(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
u := GetUserByParams(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
target := GetUserByParamsName(ctx, ":target")
|
target := GetUserByParamsName(ctx, ":target")
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
checkUserFollowing(ctx, u, target.ID)
|
checkUserFollowing(ctx, ctx.ContextUser, target.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Follow follow a user
|
// Follow follow a user
|
||||||
|
@ -235,11 +219,7 @@ func Follow(ctx *context.APIContext) {
|
||||||
// "204":
|
// "204":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
|
|
||||||
target := GetUserByParams(ctx)
|
if err := user_model.FollowUser(ctx.Doer.ID, ctx.ContextUser.ID); err != nil {
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := user_model.FollowUser(ctx.Doer.ID, target.ID); err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "FollowUser", err)
|
ctx.Error(http.StatusInternalServerError, "FollowUser", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -261,11 +241,7 @@ func Unfollow(ctx *context.APIContext) {
|
||||||
// "204":
|
// "204":
|
||||||
// "$ref": "#/responses/empty"
|
// "$ref": "#/responses/empty"
|
||||||
|
|
||||||
target := GetUserByParams(ctx)
|
if err := user_model.UnfollowUser(ctx.Doer.ID, ctx.ContextUser.ID); err != nil {
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := user_model.UnfollowUser(ctx.Doer.ID, target.ID); err != nil {
|
|
||||||
ctx.Error(http.StatusInternalServerError, "UnfollowUser", err)
|
ctx.Error(http.StatusInternalServerError, "UnfollowUser", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,11 +64,7 @@ func ListGPGKeys(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/GPGKeyList"
|
// "$ref": "#/responses/GPGKeyList"
|
||||||
|
|
||||||
user := GetUserByParams(ctx)
|
listGPGKeys(ctx, ctx.ContextUser.ID, utils.GetListOptions(ctx))
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
listGPGKeys(ctx, user.ID, utils.GetListOptions(ctx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMyGPGKeys get the GPG key list of the authenticated user
|
// ListMyGPGKeys get the GPG key list of the authenticated user
|
||||||
|
|
|
@ -151,11 +151,7 @@ func ListPublicKeys(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/PublicKeyList"
|
// "$ref": "#/responses/PublicKeyList"
|
||||||
|
|
||||||
user := GetUserByParams(ctx)
|
listPublicKeys(ctx, ctx.ContextUser)
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
listPublicKeys(ctx, user)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPublicKey get a public key
|
// GetPublicKey get a public key
|
||||||
|
|
|
@ -78,12 +78,8 @@ func ListUserRepos(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/RepositoryList"
|
// "$ref": "#/responses/RepositoryList"
|
||||||
|
|
||||||
user := GetUserByParams(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
private := ctx.IsSigned
|
private := ctx.IsSigned
|
||||||
listUserRepos(ctx, user, private)
|
listUserRepos(ctx, ctx.ContextUser, private)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMyRepos - list the repositories you own or have access to.
|
// ListMyRepos - list the repositories you own or have access to.
|
||||||
|
|
|
@ -62,15 +62,14 @@ func GetStarredRepos(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/RepositoryList"
|
// "$ref": "#/responses/RepositoryList"
|
||||||
|
|
||||||
user := GetUserByParams(ctx)
|
private := ctx.ContextUser.ID == ctx.Doer.ID
|
||||||
private := user.ID == ctx.Doer.ID
|
repos, err := getStarredRepos(ctx.ContextUser, private, utils.GetListOptions(ctx))
|
||||||
repos, err := getStarredRepos(user, private, utils.GetListOptions(ctx))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "getStarredRepos", err)
|
ctx.Error(http.StatusInternalServerError, "getStarredRepos", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.SetTotalCountHeader(int64(user.NumStars))
|
ctx.SetTotalCountHeader(int64(ctx.ContextUser.NumStars))
|
||||||
ctx.JSON(http.StatusOK, &repos)
|
ctx.JSON(http.StatusOK, &repos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,18 +98,12 @@ func GetInfo(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
u := GetUserByParams(ctx)
|
if !models.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) {
|
||||||
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !models.IsUserVisibleToViewer(u, ctx.Doer) {
|
|
||||||
// fake ErrUserNotExist error message to not leak information about existence
|
// fake ErrUserNotExist error message to not leak information about existence
|
||||||
ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.Params(":username")})
|
ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.Params(":username")})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.JSON(http.StatusOK, convert.ToUser(u, ctx.Doer))
|
ctx.JSON(http.StatusOK, convert.ToUser(ctx.ContextUser, ctx.Doer))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAuthenticatedUser get current user's information
|
// GetAuthenticatedUser get current user's information
|
||||||
|
@ -145,12 +139,7 @@ func GetUserHeatmapData(ctx *context.APIContext) {
|
||||||
// "404":
|
// "404":
|
||||||
// "$ref": "#/responses/notFound"
|
// "$ref": "#/responses/notFound"
|
||||||
|
|
||||||
user := GetUserByParams(ctx)
|
heatmap, err := models.GetUserHeatmapDataByUser(ctx.ContextUser, ctx.Doer)
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
heatmap, err := models.GetUserHeatmapDataByUser(user, ctx.Doer)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "GetUserHeatmapDataByUser", err)
|
ctx.Error(http.StatusInternalServerError, "GetUserHeatmapDataByUser", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -60,9 +60,8 @@ func GetWatchedRepos(ctx *context.APIContext) {
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/RepositoryList"
|
// "$ref": "#/responses/RepositoryList"
|
||||||
|
|
||||||
user := GetUserByParams(ctx)
|
private := ctx.ContextUser.ID == ctx.Doer.ID
|
||||||
private := user.ID == ctx.Doer.ID
|
repos, total, err := getWatchedRepos(ctx.ContextUser, private, utils.GetListOptions(ctx))
|
||||||
repos, total, err := getWatchedRepos(user, private, utils.GetListOptions(ctx))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "getWatchedRepos", err)
|
ctx.Error(http.StatusInternalServerError, "getWatchedRepos", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,19 +9,28 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
|
||||||
"github.com/gorilla/feeds"
|
"github.com/gorilla/feeds"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShowUserFeed show user activity as RSS / Atom feed
|
// ShowUserFeedRSS show user activity as RSS feed
|
||||||
func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType string) {
|
func ShowUserFeedRSS(ctx *context.Context) {
|
||||||
|
showUserFeed(ctx, "rss")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShowUserFeedAtom show user activity as Atom feed
|
||||||
|
func ShowUserFeedAtom(ctx *context.Context) {
|
||||||
|
showUserFeed(ctx, "atom")
|
||||||
|
}
|
||||||
|
|
||||||
|
// showUserFeed show user activity as RSS / Atom feed
|
||||||
|
func showUserFeed(ctx *context.Context, formatType string) {
|
||||||
actions, err := models.GetFeeds(ctx, models.GetFeedsOptions{
|
actions, err := models.GetFeeds(ctx, models.GetFeedsOptions{
|
||||||
RequestedUser: ctxUser,
|
RequestedUser: ctx.ContextUser,
|
||||||
Actor: ctx.Doer,
|
Actor: ctx.Doer,
|
||||||
IncludePrivate: false,
|
IncludePrivate: false,
|
||||||
OnlyPerformedBy: !ctxUser.IsOrganization(),
|
OnlyPerformedBy: !ctx.ContextUser.IsOrganization(),
|
||||||
IncludeDeleted: false,
|
IncludeDeleted: false,
|
||||||
Date: ctx.FormString("date"),
|
Date: ctx.FormString("date"),
|
||||||
})
|
})
|
||||||
|
@ -31,9 +40,9 @@ func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType str
|
||||||
}
|
}
|
||||||
|
|
||||||
feed := &feeds.Feed{
|
feed := &feeds.Feed{
|
||||||
Title: ctx.Tr("home.feed_of", ctxUser.DisplayName()),
|
Title: ctx.Tr("home.feed_of", ctx.ContextUser.DisplayName()),
|
||||||
Link: &feeds.Link{Href: ctxUser.HTMLURL()},
|
Link: &feeds.Link{Href: ctx.ContextUser.HTMLURL()},
|
||||||
Description: ctxUser.Description,
|
Description: ctx.ContextUser.Description,
|
||||||
Created: time.Now(),
|
Created: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"code.gitea.io/gitea/models/perm"
|
"code.gitea.io/gitea/models/perm"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
"code.gitea.io/gitea/models/unit"
|
"code.gitea.io/gitea/models/unit"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
@ -110,19 +109,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
||||||
reponame = reponame[:len(reponame)-5]
|
reponame = reponame[:len(reponame)-5]
|
||||||
}
|
}
|
||||||
|
|
||||||
owner, err := user_model.GetUserByName(username)
|
owner := ctx.ContextUser
|
||||||
if err != nil {
|
|
||||||
if user_model.IsErrUserNotExist(err) {
|
|
||||||
if redirectUserID, err := user_model.LookupUserRedirect(username); err == nil {
|
|
||||||
context.RedirectToUser(ctx, username, redirectUserID)
|
|
||||||
} else {
|
|
||||||
ctx.NotFound(fmt.Sprintf("User %s does not exist", username), nil)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx.ServerError("GetUserByName", err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !owner.IsOrganization() && !owner.IsActive {
|
if !owner.IsOrganization() && !owner.IsActive {
|
||||||
ctx.PlainText(http.StatusForbidden, "Repository cannot be accessed. You cannot push or open issues/pull-requests.")
|
ctx.PlainText(http.StatusForbidden, "Repository cannot be accessed. You cannot push or open issues/pull-requests.")
|
||||||
return
|
return
|
||||||
|
|
|
@ -756,8 +756,8 @@ func loadRepoByIDs(ctxUser *user_model.User, issueCountByRepo map[int64]int64, u
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowSSHKeys output all the ssh keys of user by uid
|
// ShowSSHKeys output all the ssh keys of user by uid
|
||||||
func ShowSSHKeys(ctx *context.Context, uid int64) {
|
func ShowSSHKeys(ctx *context.Context) {
|
||||||
keys, err := asymkey_model.ListPublicKeys(uid, db.ListOptions{})
|
keys, err := asymkey_model.ListPublicKeys(ctx.ContextUser.ID, db.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("ListPublicKeys", err)
|
ctx.ServerError("ListPublicKeys", err)
|
||||||
return
|
return
|
||||||
|
@ -772,8 +772,8 @@ func ShowSSHKeys(ctx *context.Context, uid int64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowGPGKeys output all the public GPG keys of user by uid
|
// ShowGPGKeys output all the public GPG keys of user by uid
|
||||||
func ShowGPGKeys(ctx *context.Context, uid int64) {
|
func ShowGPGKeys(ctx *context.Context) {
|
||||||
keys, err := asymkey_model.ListGPGKeys(ctx, uid, db.ListOptions{})
|
keys, err := asymkey_model.ListGPGKeys(ctx, ctx.ContextUser.ID, db.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("ListGPGKeys", err)
|
ctx.ServerError("ListGPGKeys", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -8,7 +8,6 @@ package user
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
|
@ -24,121 +23,51 @@ import (
|
||||||
"code.gitea.io/gitea/routers/web/org"
|
"code.gitea.io/gitea/routers/web/org"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetUserByName get user by name
|
|
||||||
func GetUserByName(ctx *context.Context, name string) *user_model.User {
|
|
||||||
user, err := user_model.GetUserByName(name)
|
|
||||||
if err != nil {
|
|
||||||
if user_model.IsErrUserNotExist(err) {
|
|
||||||
if redirectUserID, err := user_model.LookupUserRedirect(name); err == nil {
|
|
||||||
context.RedirectToUser(ctx, name, redirectUserID)
|
|
||||||
} else {
|
|
||||||
ctx.NotFound("GetUserByName", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx.ServerError("GetUserByName", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return user
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserByParams returns user whose name is presented in URL paramenter.
|
|
||||||
func GetUserByParams(ctx *context.Context) *user_model.User {
|
|
||||||
return GetUserByName(ctx, ctx.Params(":username"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Profile render user's profile page
|
// Profile render user's profile page
|
||||||
func Profile(ctx *context.Context) {
|
func Profile(ctx *context.Context) {
|
||||||
uname := ctx.Params(":username")
|
if strings.Contains(ctx.Req.Header.Get("Accept"), "application/rss+xml") {
|
||||||
|
feed.ShowUserFeedRSS(ctx)
|
||||||
// Special handle for FireFox requests favicon.ico.
|
return
|
||||||
if uname == "favicon.ico" {
|
}
|
||||||
ctx.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png"))
|
if strings.Contains(ctx.Req.Header.Get("Accept"), "application/atom+xml") {
|
||||||
|
feed.ShowUserFeedAtom(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasSuffix(uname, ".png") {
|
if ctx.ContextUser.IsOrganization() {
|
||||||
ctx.Error(http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isShowKeys := false
|
|
||||||
if strings.HasSuffix(uname, ".keys") {
|
|
||||||
isShowKeys = true
|
|
||||||
uname = strings.TrimSuffix(uname, ".keys")
|
|
||||||
}
|
|
||||||
|
|
||||||
isShowGPG := false
|
|
||||||
if strings.HasSuffix(uname, ".gpg") {
|
|
||||||
isShowGPG = true
|
|
||||||
uname = strings.TrimSuffix(uname, ".gpg")
|
|
||||||
}
|
|
||||||
|
|
||||||
isShowFeed, uname, showFeedType := feed.GetFeedType(uname, ctx.Req)
|
|
||||||
|
|
||||||
ctxUser := GetUserByName(ctx, uname)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctxUser.IsOrganization() {
|
|
||||||
// Show Org RSS feed
|
|
||||||
if isShowFeed {
|
|
||||||
feed.ShowUserFeed(ctx, ctxUser, showFeedType)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
org.Home(ctx)
|
org.Home(ctx)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// check view permissions
|
// check view permissions
|
||||||
if !models.IsUserVisibleToViewer(ctxUser, ctx.Doer) {
|
if !models.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) {
|
||||||
ctx.NotFound("user", fmt.Errorf(uname))
|
ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name))
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show SSH keys.
|
|
||||||
if isShowKeys {
|
|
||||||
ShowSSHKeys(ctx, ctxUser.ID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show GPG keys.
|
|
||||||
if isShowGPG {
|
|
||||||
ShowGPGKeys(ctx, ctxUser.ID)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show User RSS feed
|
|
||||||
if isShowFeed {
|
|
||||||
feed.ShowUserFeed(ctx, ctxUser, showFeedType)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// advertise feed via meta tag
|
// advertise feed via meta tag
|
||||||
ctx.Data["FeedURL"] = ctxUser.HTMLURL()
|
ctx.Data["FeedURL"] = ctx.ContextUser.HTMLURL()
|
||||||
|
|
||||||
// Show OpenID URIs
|
// Show OpenID URIs
|
||||||
openIDs, err := user_model.GetUserOpenIDs(ctxUser.ID)
|
openIDs, err := user_model.GetUserOpenIDs(ctx.ContextUser.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetUserOpenIDs", err)
|
ctx.ServerError("GetUserOpenIDs", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var isFollowing bool
|
var isFollowing bool
|
||||||
if ctx.Doer != nil && ctxUser != nil {
|
if ctx.Doer != nil {
|
||||||
isFollowing = user_model.IsFollowing(ctx.Doer.ID, ctxUser.ID)
|
isFollowing = user_model.IsFollowing(ctx.Doer.ID, ctx.ContextUser.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data["Title"] = ctxUser.DisplayName()
|
ctx.Data["Title"] = ctx.ContextUser.DisplayName()
|
||||||
ctx.Data["PageIsUserProfile"] = true
|
ctx.Data["PageIsUserProfile"] = true
|
||||||
ctx.Data["Owner"] = ctxUser
|
ctx.Data["Owner"] = ctx.ContextUser
|
||||||
ctx.Data["OpenIDs"] = openIDs
|
ctx.Data["OpenIDs"] = openIDs
|
||||||
ctx.Data["IsFollowing"] = isFollowing
|
ctx.Data["IsFollowing"] = isFollowing
|
||||||
|
|
||||||
if setting.Service.EnableUserHeatmap {
|
if setting.Service.EnableUserHeatmap {
|
||||||
data, err := models.GetUserHeatmapDataByUser(ctxUser, ctx.Doer)
|
data, err := models.GetUserHeatmapDataByUser(ctx.ContextUser, ctx.Doer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetUserHeatmapDataByUser", err)
|
ctx.ServerError("GetUserHeatmapDataByUser", err)
|
||||||
return
|
return
|
||||||
|
@ -146,13 +75,13 @@ func Profile(ctx *context.Context) {
|
||||||
ctx.Data["HeatmapData"] = data
|
ctx.Data["HeatmapData"] = data
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ctxUser.Description) != 0 {
|
if len(ctx.ContextUser.Description) != 0 {
|
||||||
content, err := markdown.RenderString(&markup.RenderContext{
|
content, err := markdown.RenderString(&markup.RenderContext{
|
||||||
URLPrefix: ctx.Repo.RepoLink,
|
URLPrefix: ctx.Repo.RepoLink,
|
||||||
Metas: map[string]string{"mode": "document"},
|
Metas: map[string]string{"mode": "document"},
|
||||||
GitRepo: ctx.Repo.GitRepo,
|
GitRepo: ctx.Repo.GitRepo,
|
||||||
Ctx: ctx,
|
Ctx: ctx,
|
||||||
}, ctxUser.Description)
|
}, ctx.ContextUser.Description)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("RenderString", err)
|
ctx.ServerError("RenderString", err)
|
||||||
return
|
return
|
||||||
|
@ -160,10 +89,10 @@ func Profile(ctx *context.Context) {
|
||||||
ctx.Data["RenderedDescription"] = content
|
ctx.Data["RenderedDescription"] = content
|
||||||
}
|
}
|
||||||
|
|
||||||
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctxUser.ID)
|
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
|
||||||
|
|
||||||
orgs, err := models.FindOrgs(models.FindOrgOptions{
|
orgs, err := models.FindOrgs(models.FindOrgOptions{
|
||||||
UserID: ctxUser.ID,
|
UserID: ctx.ContextUser.ID,
|
||||||
IncludePrivate: showPrivate,
|
IncludePrivate: showPrivate,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -226,7 +155,7 @@ func Profile(ctx *context.Context) {
|
||||||
|
|
||||||
switch tab {
|
switch tab {
|
||||||
case "followers":
|
case "followers":
|
||||||
items, err := user_model.GetUserFollowers(ctxUser, db.ListOptions{
|
items, err := user_model.GetUserFollowers(ctx.ContextUser, db.ListOptions{
|
||||||
PageSize: setting.UI.User.RepoPagingNum,
|
PageSize: setting.UI.User.RepoPagingNum,
|
||||||
Page: page,
|
Page: page,
|
||||||
})
|
})
|
||||||
|
@ -236,9 +165,9 @@ func Profile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
ctx.Data["Cards"] = items
|
ctx.Data["Cards"] = items
|
||||||
|
|
||||||
total = ctxUser.NumFollowers
|
total = ctx.ContextUser.NumFollowers
|
||||||
case "following":
|
case "following":
|
||||||
items, err := user_model.GetUserFollowing(ctxUser, db.ListOptions{
|
items, err := user_model.GetUserFollowing(ctx.ContextUser, db.ListOptions{
|
||||||
PageSize: setting.UI.User.RepoPagingNum,
|
PageSize: setting.UI.User.RepoPagingNum,
|
||||||
Page: page,
|
Page: page,
|
||||||
})
|
})
|
||||||
|
@ -248,10 +177,10 @@ func Profile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
ctx.Data["Cards"] = items
|
ctx.Data["Cards"] = items
|
||||||
|
|
||||||
total = ctxUser.NumFollowing
|
total = ctx.ContextUser.NumFollowing
|
||||||
case "activity":
|
case "activity":
|
||||||
ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
|
ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
|
||||||
RequestedUser: ctxUser,
|
RequestedUser: ctx.ContextUser,
|
||||||
Actor: ctx.Doer,
|
Actor: ctx.Doer,
|
||||||
IncludePrivate: showPrivate,
|
IncludePrivate: showPrivate,
|
||||||
OnlyPerformedBy: true,
|
OnlyPerformedBy: true,
|
||||||
|
@ -273,7 +202,7 @@ func Profile(ctx *context.Context) {
|
||||||
Keyword: keyword,
|
Keyword: keyword,
|
||||||
OrderBy: orderBy,
|
OrderBy: orderBy,
|
||||||
Private: ctx.IsSigned,
|
Private: ctx.IsSigned,
|
||||||
StarredByID: ctxUser.ID,
|
StarredByID: ctx.ContextUser.ID,
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: util.OptionalBoolFalse,
|
||||||
TopicOnly: topicOnly,
|
TopicOnly: topicOnly,
|
||||||
Language: language,
|
Language: language,
|
||||||
|
@ -305,7 +234,7 @@ func Profile(ctx *context.Context) {
|
||||||
Keyword: keyword,
|
Keyword: keyword,
|
||||||
OrderBy: orderBy,
|
OrderBy: orderBy,
|
||||||
Private: ctx.IsSigned,
|
Private: ctx.IsSigned,
|
||||||
WatchedByID: ctxUser.ID,
|
WatchedByID: ctx.ContextUser.ID,
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: util.OptionalBoolFalse,
|
||||||
TopicOnly: topicOnly,
|
TopicOnly: topicOnly,
|
||||||
Language: language,
|
Language: language,
|
||||||
|
@ -325,7 +254,7 @@ func Profile(ctx *context.Context) {
|
||||||
},
|
},
|
||||||
Actor: ctx.Doer,
|
Actor: ctx.Doer,
|
||||||
Keyword: keyword,
|
Keyword: keyword,
|
||||||
OwnerID: ctxUser.ID,
|
OwnerID: ctx.ContextUser.ID,
|
||||||
OrderBy: orderBy,
|
OrderBy: orderBy,
|
||||||
Private: ctx.IsSigned,
|
Private: ctx.IsSigned,
|
||||||
Collaborate: util.OptionalBoolFalse,
|
Collaborate: util.OptionalBoolFalse,
|
||||||
|
@ -350,24 +279,19 @@ func Profile(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
ctx.Data["Page"] = pager
|
ctx.Data["Page"] = pager
|
||||||
|
|
||||||
ctx.Data["ShowUserEmail"] = len(ctxUser.Email) > 0 && ctx.IsSigned && (!ctxUser.KeepEmailPrivate || ctxUser.ID == ctx.Doer.ID)
|
ctx.Data["ShowUserEmail"] = len(ctx.ContextUser.Email) > 0 && ctx.IsSigned && (!ctx.ContextUser.KeepEmailPrivate || ctx.ContextUser.ID == ctx.Doer.ID)
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplProfile)
|
ctx.HTML(http.StatusOK, tplProfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Action response for follow/unfollow user request
|
// Action response for follow/unfollow user request
|
||||||
func Action(ctx *context.Context) {
|
func Action(ctx *context.Context) {
|
||||||
u := GetUserByParams(ctx)
|
|
||||||
if ctx.Written() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch ctx.FormString("action") {
|
switch ctx.FormString("action") {
|
||||||
case "follow":
|
case "follow":
|
||||||
err = user_model.FollowUser(ctx.Doer.ID, u.ID)
|
err = user_model.FollowUser(ctx.Doer.ID, ctx.ContextUser.ID)
|
||||||
case "unfollow":
|
case "unfollow":
|
||||||
err = user_model.UnfollowUser(ctx.Doer.ID, u.ID)
|
err = user_model.UnfollowUser(ctx.Doer.ID, ctx.ContextUser.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -375,5 +299,5 @@ func Action(ctx *context.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// FIXME: We should check this URL and make sure that it's a valid Gitea URL
|
// FIXME: We should check this URL and make sure that it's a valid Gitea URL
|
||||||
ctx.RedirectToFirst(ctx.FormString("redirect_to"), u.HomeLink())
|
ctx.RedirectToFirst(ctx.FormString("redirect_to"), ctx.ContextUser.HomeLink())
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,12 +29,14 @@ import (
|
||||||
"code.gitea.io/gitea/routers/web/dev"
|
"code.gitea.io/gitea/routers/web/dev"
|
||||||
"code.gitea.io/gitea/routers/web/events"
|
"code.gitea.io/gitea/routers/web/events"
|
||||||
"code.gitea.io/gitea/routers/web/explore"
|
"code.gitea.io/gitea/routers/web/explore"
|
||||||
|
"code.gitea.io/gitea/routers/web/feed"
|
||||||
"code.gitea.io/gitea/routers/web/org"
|
"code.gitea.io/gitea/routers/web/org"
|
||||||
"code.gitea.io/gitea/routers/web/repo"
|
"code.gitea.io/gitea/routers/web/repo"
|
||||||
"code.gitea.io/gitea/routers/web/user"
|
"code.gitea.io/gitea/routers/web/user"
|
||||||
user_setting "code.gitea.io/gitea/routers/web/user/setting"
|
user_setting "code.gitea.io/gitea/routers/web/user/setting"
|
||||||
"code.gitea.io/gitea/routers/web/user/setting/security"
|
"code.gitea.io/gitea/routers/web/user/setting/security"
|
||||||
auth_service "code.gitea.io/gitea/services/auth"
|
auth_service "code.gitea.io/gitea/services/auth"
|
||||||
|
context_service "code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
"code.gitea.io/gitea/services/lfs"
|
"code.gitea.io/gitea/services/lfs"
|
||||||
"code.gitea.io/gitea/services/mailer"
|
"code.gitea.io/gitea/services/mailer"
|
||||||
|
@ -496,11 +498,21 @@ func RegisterRoutes(m *web.Route) {
|
||||||
// ***** END: Admin *****
|
// ***** END: Admin *****
|
||||||
|
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
m.Get("/{username}", user.Profile)
|
m.Get("/favicon.ico", func(ctx *context.Context) {
|
||||||
|
ctx.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png"))
|
||||||
|
})
|
||||||
|
m.Group("/{username}", func() {
|
||||||
|
m.Get(".png", func(ctx *context.Context) { ctx.Error(http.StatusNotFound) })
|
||||||
|
m.Get(".keys", user.ShowSSHKeys)
|
||||||
|
m.Get(".gpg", user.ShowGPGKeys)
|
||||||
|
m.Get(".rss", feed.ShowUserFeedRSS)
|
||||||
|
m.Get(".atom", feed.ShowUserFeedAtom)
|
||||||
|
m.Get("", user.Profile)
|
||||||
|
}, context_service.UserAssignmentWeb())
|
||||||
m.Get("/attachments/{uuid}", repo.GetAttachment)
|
m.Get("/attachments/{uuid}", repo.GetAttachment)
|
||||||
}, ignSignIn)
|
}, ignSignIn)
|
||||||
|
|
||||||
m.Post("/{username}", reqSignIn, user.Action)
|
m.Post("/{username}", reqSignIn, context_service.UserAssignmentWeb(), user.Action)
|
||||||
|
|
||||||
if !setting.IsProd {
|
if !setting.IsProd {
|
||||||
m.Get("/template/*", dev.TemplatePreview)
|
m.Get("/template/*", dev.TemplatePreview)
|
||||||
|
@ -1107,7 +1119,7 @@ func RegisterRoutes(m *web.Route) {
|
||||||
m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
|
m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
|
||||||
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
|
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
|
||||||
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
|
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
|
||||||
}, ignSignInAndCsrf)
|
}, ignSignInAndCsrf, context_service.UserAssignmentWeb())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
// ***** END: Repository *****
|
// ***** END: Repository *****
|
||||||
|
|
62
services/context/user.go
Normal file
62
services/context/user.go
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UserAssignmentWeb returns a middleware to handle context-user assignment for web routes
|
||||||
|
func UserAssignmentWeb() func(ctx *context.Context) {
|
||||||
|
return func(ctx *context.Context) {
|
||||||
|
userAssignment(ctx, func(status int, title string, obj interface{}) {
|
||||||
|
err, ok := obj.(error)
|
||||||
|
if !ok {
|
||||||
|
err = fmt.Errorf("%s", obj)
|
||||||
|
}
|
||||||
|
if status == http.StatusNotFound {
|
||||||
|
ctx.NotFound(title, err)
|
||||||
|
} else {
|
||||||
|
ctx.ServerError(title, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserAssignmentAPI returns a middleware to handle context-user assignment for api routes
|
||||||
|
func UserAssignmentAPI() func(ctx *context.APIContext) {
|
||||||
|
return func(ctx *context.APIContext) {
|
||||||
|
userAssignment(ctx.Context, ctx.Error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func userAssignment(ctx *context.Context, errCb func(int, string, interface{})) {
|
||||||
|
username := ctx.Params(":username")
|
||||||
|
|
||||||
|
if ctx.IsSigned && ctx.Doer.LowerName == strings.ToLower(username) {
|
||||||
|
ctx.ContextUser = ctx.Doer
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
ctx.ContextUser, err = user_model.GetUserByName(username)
|
||||||
|
if err != nil {
|
||||||
|
if user_model.IsErrUserNotExist(err) {
|
||||||
|
if redirectUserID, err := user_model.LookupUserRedirect(username); err == nil {
|
||||||
|
context.RedirectToUser(ctx, username, redirectUserID)
|
||||||
|
} else if user_model.IsErrUserRedirectNotExist(err) {
|
||||||
|
errCb(http.StatusNotFound, "GetUserByName", err)
|
||||||
|
} else {
|
||||||
|
errCb(http.StatusInternalServerError, "LookupUserRedirect", err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errCb(http.StatusInternalServerError, "GetUserByName", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12087,39 +12087,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/users/{follower}/following/{followee}": {
|
|
||||||
"get": {
|
|
||||||
"tags": [
|
|
||||||
"user"
|
|
||||||
],
|
|
||||||
"summary": "Check if one user is following another user",
|
|
||||||
"operationId": "userCheckFollowing",
|
|
||||||
"parameters": [
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "username of following user",
|
|
||||||
"name": "follower",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "string",
|
|
||||||
"description": "username of followed user",
|
|
||||||
"name": "followee",
|
|
||||||
"in": "path",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"responses": {
|
|
||||||
"204": {
|
|
||||||
"$ref": "#/responses/empty"
|
|
||||||
},
|
|
||||||
"404": {
|
|
||||||
"$ref": "#/responses/notFound"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"/users/{username}": {
|
"/users/{username}": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
|
@ -12225,6 +12192,39 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/users/{username}/following/{target}": {
|
||||||
|
"get": {
|
||||||
|
"tags": [
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"summary": "Check if one user is following another user",
|
||||||
|
"operationId": "userCheckFollowing",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "username of following user",
|
||||||
|
"name": "username",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "username of followed user",
|
||||||
|
"name": "target",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"204": {
|
||||||
|
"$ref": "#/responses/empty"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/responses/notFound"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/users/{username}/gpg_keys": {
|
"/users/{username}/gpg_keys": {
|
||||||
"get": {
|
"get": {
|
||||||
"produces": [
|
"produces": [
|
||||||
|
|
Loading…
Reference in a new issue