mirror of
https://github.com/go-gitea/gitea
synced 2025-12-07 13:28:25 +00:00
Merge remote-tracking branch 'upstream/master' into team-grant-all-repos
# Conflicts: # models/migrations/migrations.go # models/migrations/v90.go # models/repo.go
This commit is contained in:
@@ -13,9 +13,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
@@ -24,6 +21,11 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
"gitea.com/macaron/macaron"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -78,7 +80,7 @@ var sysStatus struct {
|
||||
}
|
||||
|
||||
func updateSystemStatus() {
|
||||
sysStatus.Uptime = base.TimeSincePro(startTime, "en")
|
||||
sysStatus.Uptime = timeutil.TimeSincePro(startTime, "en")
|
||||
|
||||
m := new(runtime.MemStats)
|
||||
runtime.ReadMemStats(m)
|
||||
@@ -196,7 +198,7 @@ func Dashboard(ctx *context.Context) {
|
||||
func SendTestMail(ctx *context.Context) {
|
||||
email := ctx.Query("email")
|
||||
// Send a test email to the user's email address and redirect back to Config
|
||||
if err := models.SendTestMail(email); err != nil {
|
||||
if err := mailer.SendTestMail(email); err != nil {
|
||||
ctx.Flash.Error(ctx.Tr("admin.config.test_mail_failed", email, err))
|
||||
} else {
|
||||
ctx.Flash.Info(ctx.Tr("admin.config.test_mail_sent", email))
|
||||
@@ -288,7 +290,7 @@ func Config(ctx *context.Context) {
|
||||
ctx.Data["LFS"] = setting.LFS
|
||||
|
||||
ctx.Data["Service"] = setting.Service
|
||||
ctx.Data["DbCfg"] = models.DbCfg
|
||||
ctx.Data["DbCfg"] = setting.Database
|
||||
ctx.Data["Webhook"] = setting.Webhook
|
||||
|
||||
ctx.Data["MailerEnabled"] = false
|
||||
@@ -332,7 +334,7 @@ func Config(ctx *context.Context) {
|
||||
ctx.Data["AccessLogTemplate"] = setting.AccessLogTemplate
|
||||
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
|
||||
ctx.Data["EnableXORMLog"] = setting.EnableXORMLog
|
||||
ctx.Data["LogSQL"] = setting.LogSQL
|
||||
ctx.Data["LogSQL"] = setting.Database.LogSQL
|
||||
|
||||
ctx.HTML(200, tplConfig)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/unknwon/com"
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -7,8 +7,6 @@ package admin
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
@@ -16,6 +14,9 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -116,8 +117,8 @@ func NewUserPost(ctx *context.Context, form auth.AdminCreateUserForm) {
|
||||
log.Trace("Account created by admin (%s): %s", ctx.User.Name, u.Name)
|
||||
|
||||
// Send email notification.
|
||||
if form.SendNotify && setting.MailService != nil {
|
||||
models.SendRegisterNotifyMail(ctx.Context, u)
|
||||
if form.SendNotify {
|
||||
mailer.SendRegisterNotifyMail(ctx.Locale, u)
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("admin.users.new_success", u.Name))
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
"code.gitea.io/gitea/routers/api/v1/user"
|
||||
)
|
||||
@@ -82,6 +81,15 @@ func GetAllOrgs(ctx *context.APIContext) {
|
||||
// summary: List all organizations
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of results to return (1-based)
|
||||
// type: integer
|
||||
// - name: limit
|
||||
// in: query
|
||||
// description: page size of results, maximum page size is 50
|
||||
// type: integer
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/OrganizationList"
|
||||
@@ -90,7 +98,9 @@ func GetAllOrgs(ctx *context.APIContext) {
|
||||
users, _, err := models.SearchUsers(&models.SearchUserOptions{
|
||||
Type: models.UserTypeOrganization,
|
||||
OrderBy: models.SearchOrderByAlphabetically,
|
||||
PageSize: -1,
|
||||
Page: ctx.QueryInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
|
||||
Private: true,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.Error(500, "SearchOrganizations", err)
|
||||
|
||||
@@ -5,9 +5,8 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/repo"
|
||||
"code.gitea.io/gitea/routers/api/v1/user"
|
||||
)
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
"code.gitea.io/gitea/routers/api/v1/user"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
)
|
||||
|
||||
func parseLoginSource(ctx *context.APIContext, u *models.User, sourceID int64, loginName string) {
|
||||
@@ -88,11 +88,10 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
|
||||
log.Trace("Account created by admin (%s): %s", ctx.User.Name, u.Name)
|
||||
|
||||
// Send email notification.
|
||||
if form.SendNotify && setting.MailService != nil {
|
||||
models.SendRegisterNotifyMail(ctx.Context.Context, u)
|
||||
if form.SendNotify {
|
||||
mailer.SendRegisterNotifyMail(ctx.Locale, u)
|
||||
}
|
||||
|
||||
ctx.JSON(201, u.APIFormat())
|
||||
ctx.JSON(201, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
|
||||
}
|
||||
|
||||
// EditUser api for modifying a user's information
|
||||
@@ -181,7 +180,7 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) {
|
||||
}
|
||||
log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
|
||||
|
||||
ctx.JSON(200, u.APIFormat())
|
||||
ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
|
||||
}
|
||||
|
||||
// DeleteUser api for deleting a user
|
||||
@@ -326,7 +325,7 @@ func GetAllUsers(ctx *context.APIContext) {
|
||||
|
||||
results := make([]*api.User, len(users))
|
||||
for i := range users {
|
||||
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
|
||||
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User.IsAdmin)
|
||||
}
|
||||
|
||||
ctx.JSON(200, &results)
|
||||
|
||||
+24
-16
@@ -43,6 +43,7 @@
|
||||
// type: apiKey
|
||||
// name: Authorization
|
||||
// in: header
|
||||
// description: API tokens must be prepended with "token" followed by a space.
|
||||
// SudoParam:
|
||||
// type: apiKey
|
||||
// name: sudo
|
||||
@@ -73,9 +74,8 @@ import (
|
||||
_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
|
||||
"code.gitea.io/gitea/routers/api/v1/user"
|
||||
|
||||
"github.com/go-macaron/binding"
|
||||
"github.com/go-macaron/cors"
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
"gitea.com/macaron/binding"
|
||||
"gitea.com/macaron/macaron"
|
||||
)
|
||||
|
||||
func sudo() macaron.Handler {
|
||||
@@ -501,12 +501,6 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Get("/swagger", misc.Swagger) //Render V1 by default
|
||||
}
|
||||
|
||||
var handlers []macaron.Handler
|
||||
if setting.EnableCORS {
|
||||
handlers = append(handlers, cors.CORS(setting.CORSConfig))
|
||||
}
|
||||
handlers = append(handlers, securityHeaders(), context.APIContexter(), sudo())
|
||||
|
||||
m.Group("/v1", func() {
|
||||
// Miscellaneous
|
||||
if setting.API.EnableSwagger {
|
||||
@@ -750,10 +744,13 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Combo("/:sha").Get(repo.GetCommitStatuses).
|
||||
Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
|
||||
}, reqRepoReader(models.UnitTypeCode))
|
||||
m.Group("/commits/:ref", func() {
|
||||
// TODO: Add m.Get("") for single commit (https://developer.github.com/v3/repos/commits/#get-a-single-commit)
|
||||
m.Get("/status", repo.GetCombinedCommitStatusByRef)
|
||||
m.Get("/statuses", repo.GetCommitStatusesByRef)
|
||||
m.Group("/commits", func() {
|
||||
m.Get("", repo.GetAllCommits)
|
||||
m.Group("/:ref", func() {
|
||||
// TODO: Add m.Get("") for single commit (https://developer.github.com/v3/repos/commits/#get-a-single-commit)
|
||||
m.Get("/status", repo.GetCombinedCommitStatusByRef)
|
||||
m.Get("/statuses", repo.GetCommitStatusesByRef)
|
||||
})
|
||||
}, reqRepoReader(models.UnitTypeCode))
|
||||
m.Group("/git", func() {
|
||||
m.Group("/commits", func() {
|
||||
@@ -774,6 +771,14 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Delete("", bind(api.DeleteFileOptions{}), repo.DeleteFile)
|
||||
}, reqRepoWriter(models.UnitTypeCode), reqToken())
|
||||
}, reqRepoReader(models.UnitTypeCode))
|
||||
m.Group("/topics", func() {
|
||||
m.Combo("").Get(repo.ListTopics).
|
||||
Put(reqToken(), reqAdmin(), bind(api.RepoTopicOptions{}), repo.UpdateTopics)
|
||||
m.Group("/:topic", func() {
|
||||
m.Combo("").Put(reqToken(), repo.AddTopic).
|
||||
Delete(reqToken(), repo.DeleteTopic)
|
||||
}, reqAdmin())
|
||||
}, reqAnyRepoReader())
|
||||
}, repoAssignment())
|
||||
})
|
||||
|
||||
@@ -797,8 +802,11 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
Put(reqToken(), reqOrgMembership(), org.PublicizeMember).
|
||||
Delete(reqToken(), reqOrgMembership(), org.ConcealMember)
|
||||
})
|
||||
m.Combo("/teams", reqToken(), reqOrgMembership()).Get(org.ListTeams).
|
||||
Post(reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
|
||||
m.Group("/teams", func() {
|
||||
m.Combo("", reqToken()).Get(org.ListTeams).
|
||||
Post(reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
|
||||
m.Get("/search", org.SearchTeam)
|
||||
}, reqOrgMembership())
|
||||
m.Group("/hooks", func() {
|
||||
m.Combo("").Get(org.ListHooks).
|
||||
Post(bind(api.CreateHookOption{}), org.CreateHook)
|
||||
@@ -852,7 +860,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Group("/topics", func() {
|
||||
m.Get("/search", repo.TopicSearch)
|
||||
})
|
||||
}, handlers...)
|
||||
}, securityHeaders(), context.APIContexter(), sudo())
|
||||
}
|
||||
|
||||
func securityHeaders() macaron.Handler {
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
// ToEmail convert models.EmailAddress to api.Email
|
||||
@@ -206,14 +206,15 @@ func ToDeployKey(apiLink string, key *models.DeployKey) *api.DeployKey {
|
||||
// ToOrganization convert models.User to api.Organization
|
||||
func ToOrganization(org *models.User) *api.Organization {
|
||||
return &api.Organization{
|
||||
ID: org.ID,
|
||||
AvatarURL: org.AvatarLink(),
|
||||
UserName: org.Name,
|
||||
FullName: org.FullName,
|
||||
Description: org.Description,
|
||||
Website: org.Website,
|
||||
Location: org.Location,
|
||||
Visibility: org.Visibility.String(),
|
||||
ID: org.ID,
|
||||
AvatarURL: org.AvatarLink(),
|
||||
UserName: org.Name,
|
||||
FullName: org.FullName,
|
||||
Description: org.Description,
|
||||
Website: org.Website,
|
||||
Location: org.Location,
|
||||
Visibility: org.Visibility.String(),
|
||||
RepoAdminChangeTeamAccess: org.RepoAdminChangeTeamAccess,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,7 +231,7 @@ func ToTeam(team *models.Team) *api.Team {
|
||||
}
|
||||
|
||||
// ToUser convert models.User to api.User
|
||||
func ToUser(user *models.User, signed, admin bool) *api.User {
|
||||
func ToUser(user *models.User, signed, authed bool) *api.User {
|
||||
result := &api.User{
|
||||
ID: user.ID,
|
||||
UserName: user.Name,
|
||||
@@ -240,7 +241,12 @@ func ToUser(user *models.User, signed, admin bool) *api.User {
|
||||
LastLogin: user.LastLoginUnix.AsTime(),
|
||||
Created: user.CreatedUnix.AsTime(),
|
||||
}
|
||||
if signed && (!user.KeepEmailPrivate || admin) {
|
||||
// hide primary email if API caller isn't user itself or an admin
|
||||
if !signed {
|
||||
result.Email = ""
|
||||
} else if user.KeepEmailPrivate && !authed {
|
||||
result.Email = user.GetEmail()
|
||||
} else {
|
||||
result.Email = user.Email
|
||||
}
|
||||
return result
|
||||
@@ -287,3 +293,14 @@ func ToCommitMeta(repo *models.Repository, tag *git.Tag) *api.CommitMeta {
|
||||
URL: util.URLJoin(repo.APIURL(), "git/commits", tag.ID.String()),
|
||||
}
|
||||
}
|
||||
|
||||
// ToTopicResponse convert from models.Topic to api.TopicResponse
|
||||
func ToTopicResponse(topic *models.Topic) *api.TopicResponse {
|
||||
return &api.TopicResponse{
|
||||
ID: topic.ID,
|
||||
Name: topic.Name,
|
||||
RepoCount: topic.RepoCount,
|
||||
Created: topic.CreatedUnix.AsTime(),
|
||||
Updated: topic.UpdatedUnix.AsTime(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,10 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/markup/markdown"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"mvdan.cc/xurls/v2"
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/go-macaron/inject"
|
||||
"gitea.com/macaron/inject"
|
||||
"gitea.com/macaron/macaron"
|
||||
"github.com/stretchr/testify/assert"
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
const AppURL = "http://localhost:3000/"
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
)
|
||||
|
||||
@@ -7,11 +7,11 @@ package org
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
"code.gitea.io/gitea/routers/api/v1/user"
|
||||
)
|
||||
|
||||
@@ -46,7 +46,7 @@ func listMembers(ctx *context.APIContext, publicOnly bool) {
|
||||
|
||||
apiMembers := make([]*api.User, len(members))
|
||||
for i, member := range members {
|
||||
apiMembers[i] = member.APIFormat()
|
||||
apiMembers[i] = convert.ToUser(member, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
|
||||
}
|
||||
ctx.JSON(200, apiMembers)
|
||||
}
|
||||
|
||||
+10
-10
@@ -6,10 +6,9 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
"code.gitea.io/gitea/routers/api/v1/user"
|
||||
)
|
||||
@@ -96,14 +95,15 @@ func Create(ctx *context.APIContext, form api.CreateOrgOption) {
|
||||
}
|
||||
|
||||
org := &models.User{
|
||||
Name: form.UserName,
|
||||
FullName: form.FullName,
|
||||
Description: form.Description,
|
||||
Website: form.Website,
|
||||
Location: form.Location,
|
||||
IsActive: true,
|
||||
Type: models.UserTypeOrganization,
|
||||
Visibility: visibility,
|
||||
Name: form.UserName,
|
||||
FullName: form.FullName,
|
||||
Description: form.Description,
|
||||
Website: form.Website,
|
||||
Location: form.Location,
|
||||
IsActive: true,
|
||||
Type: models.UserTypeOrganization,
|
||||
Visibility: visibility,
|
||||
RepoAdminChangeTeamAccess: form.RepoAdminChangeTeamAccess,
|
||||
}
|
||||
if err := models.CreateOrganization(org, ctx.User); err != nil {
|
||||
if models.IsErrUserAlreadyExist(err) ||
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
"code.gitea.io/gitea/routers/api/v1/user"
|
||||
)
|
||||
@@ -259,7 +261,7 @@ func GetTeamMembers(ctx *context.APIContext) {
|
||||
}
|
||||
members := make([]*api.User, len(team.Members))
|
||||
for i, member := range team.Members {
|
||||
members[i] = member.APIFormat()
|
||||
members[i] = convert.ToUser(member, ctx.IsSigned, ctx.User.IsAdmin)
|
||||
}
|
||||
ctx.JSON(200, members)
|
||||
}
|
||||
@@ -290,7 +292,16 @@ func GetTeamMember(ctx *context.APIContext) {
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
ctx.JSON(200, u.APIFormat())
|
||||
teamID := ctx.ParamsInt64("teamid")
|
||||
isTeamMember, err := models.IsUserInTeams(u.ID, []int64{teamID})
|
||||
if err != nil {
|
||||
ctx.Error(500, "IsUserInTeams", err)
|
||||
return
|
||||
} else if !isTeamMember {
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
|
||||
}
|
||||
|
||||
// AddTeamMember api for add a member to a team
|
||||
@@ -498,3 +509,83 @@ func RemoveTeamRepository(ctx *context.APIContext) {
|
||||
}
|
||||
ctx.Status(204)
|
||||
}
|
||||
|
||||
// SearchTeam api for searching teams
|
||||
func SearchTeam(ctx *context.APIContext) {
|
||||
// swagger:operation GET /orgs/{org}/teams/search organization teamSearch
|
||||
// ---
|
||||
// summary: Search for teams within an organization
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: org
|
||||
// in: path
|
||||
// description: name of the organization
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: q
|
||||
// in: query
|
||||
// description: keywords to search
|
||||
// type: string
|
||||
// - name: include_desc
|
||||
// in: query
|
||||
// description: include search within team description (defaults to true)
|
||||
// type: boolean
|
||||
// - name: limit
|
||||
// in: query
|
||||
// description: limit size of results
|
||||
// type: integer
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of results to return (1-based)
|
||||
// type: integer
|
||||
// responses:
|
||||
// "200":
|
||||
// description: "SearchResults of a successful search"
|
||||
// schema:
|
||||
// type: object
|
||||
// properties:
|
||||
// ok:
|
||||
// type: boolean
|
||||
// data:
|
||||
// type: array
|
||||
// items:
|
||||
// "$ref": "#/definitions/Team"
|
||||
opts := &models.SearchTeamOptions{
|
||||
UserID: ctx.User.ID,
|
||||
Keyword: strings.TrimSpace(ctx.Query("q")),
|
||||
OrgID: ctx.Org.Organization.ID,
|
||||
IncludeDesc: (ctx.Query("include_desc") == "" || ctx.QueryBool("include_desc")),
|
||||
PageSize: ctx.QueryInt("limit"),
|
||||
Page: ctx.QueryInt("page"),
|
||||
}
|
||||
|
||||
teams, _, err := models.SearchTeam(opts)
|
||||
if err != nil {
|
||||
log.Error("SearchTeam failed: %v", err)
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
"ok": false,
|
||||
"error": "SearchTeam internal failure",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
apiTeams := make([]*api.Team, len(teams))
|
||||
for i := range teams {
|
||||
if err := teams[i].GetUnits(); err != nil {
|
||||
log.Error("Team GetUnits failed: %v", err)
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
"ok": false,
|
||||
"error": "SearchTeam failed to get units",
|
||||
})
|
||||
return
|
||||
}
|
||||
apiTeams[i] = convert.ToTeam(teams[i])
|
||||
}
|
||||
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"ok": true,
|
||||
"data": apiTeams,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ package repo
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
// GetBranch get a branch of a repository
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
// ListCollaborators list a repository's collaborators
|
||||
@@ -42,7 +42,7 @@ func ListCollaborators(ctx *context.APIContext) {
|
||||
}
|
||||
users := make([]*api.User, len(collaborators))
|
||||
for i, collaborator := range collaborators {
|
||||
users[i] = collaborator.APIFormat()
|
||||
users[i] = convert.ToUser(collaborator.User, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
|
||||
}
|
||||
ctx.JSON(200, users)
|
||||
}
|
||||
|
||||
+185
-22
@@ -6,6 +6,8 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
@@ -55,25 +57,186 @@ func GetSingleCommit(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve author and committer information
|
||||
var apiAuthor, apiCommitter *api.User
|
||||
author, err := models.GetUserByEmail(commit.Author.Email)
|
||||
if err != nil && !models.IsErrUserNotExist(err) {
|
||||
ctx.ServerError("Get user by author email", err)
|
||||
json, err := toCommit(ctx, ctx.Repo.Repository, commit, nil)
|
||||
if err != nil {
|
||||
ctx.ServerError("toCommit", err)
|
||||
return
|
||||
} else if err == nil {
|
||||
apiAuthor = author.APIFormat()
|
||||
}
|
||||
// Save one query if the author is also the committer
|
||||
if commit.Committer.Email == commit.Author.Email {
|
||||
apiCommitter = apiAuthor
|
||||
|
||||
ctx.JSON(200, json)
|
||||
}
|
||||
|
||||
// GetAllCommits get all commits via
|
||||
func GetAllCommits(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/commits repository repoGetAllCommits
|
||||
// ---
|
||||
// summary: Get a list of all commits from a repository
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: sha
|
||||
// in: query
|
||||
// description: SHA or branch to start listing commits from (usually 'master')
|
||||
// type: string
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of requested commits
|
||||
// type: integer
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/CommitList"
|
||||
// "404":
|
||||
// "$ref": "#/responses/notFound"
|
||||
// "409":
|
||||
// "$ref": "#/responses/EmptyRepository"
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.JSON(409, api.APIError{
|
||||
Message: "Git Repository is empty.",
|
||||
URL: setting.API.SwaggerURL,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath())
|
||||
if err != nil {
|
||||
ctx.ServerError("OpenRepository", err)
|
||||
return
|
||||
}
|
||||
|
||||
page := ctx.QueryInt("page")
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
|
||||
sha := ctx.Query("sha")
|
||||
|
||||
var baseCommit *git.Commit
|
||||
if len(sha) == 0 {
|
||||
// no sha supplied - use default branch
|
||||
head, err := gitRepo.GetHEADBranch()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetHEADBranch", err)
|
||||
return
|
||||
}
|
||||
|
||||
baseCommit, err = gitRepo.GetBranchCommit(head.Name)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommit", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// get commit specified by sha
|
||||
baseCommit, err = gitRepo.GetCommit(sha)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommit", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Total commit count
|
||||
commitsCountTotal, err := baseCommit.CommitsCount()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommitsCount", err)
|
||||
return
|
||||
}
|
||||
|
||||
pageCount := int(math.Ceil(float64(commitsCountTotal) / float64(git.CommitsRangeSize)))
|
||||
|
||||
// Query commits
|
||||
commits, err := baseCommit.CommitsByRange(page)
|
||||
if err != nil {
|
||||
ctx.ServerError("CommitsByRange", err)
|
||||
return
|
||||
}
|
||||
|
||||
userCache := make(map[string]*models.User)
|
||||
|
||||
apiCommits := make([]*api.Commit, commits.Len())
|
||||
|
||||
i := 0
|
||||
for commitPointer := commits.Front(); commitPointer != nil; commitPointer = commitPointer.Next() {
|
||||
commit := commitPointer.Value.(*git.Commit)
|
||||
|
||||
// Create json struct
|
||||
apiCommits[i], err = toCommit(ctx, ctx.Repo.Repository, commit, userCache)
|
||||
if err != nil {
|
||||
ctx.ServerError("toCommit", err)
|
||||
return
|
||||
}
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
ctx.SetLinkHeader(int(commitsCountTotal), git.CommitsRangeSize)
|
||||
|
||||
ctx.Header().Set("X-Page", strconv.Itoa(page))
|
||||
ctx.Header().Set("X-PerPage", strconv.Itoa(git.CommitsRangeSize))
|
||||
ctx.Header().Set("X-Total", strconv.FormatInt(commitsCountTotal, 10))
|
||||
ctx.Header().Set("X-PageCount", strconv.Itoa(pageCount))
|
||||
ctx.Header().Set("X-HasMore", strconv.FormatBool(page < pageCount))
|
||||
|
||||
ctx.JSON(200, &apiCommits)
|
||||
}
|
||||
|
||||
func toCommit(ctx *context.APIContext, repo *models.Repository, commit *git.Commit, userCache map[string]*models.User) (*api.Commit, error) {
|
||||
|
||||
var apiAuthor, apiCommitter *api.User
|
||||
|
||||
// Retrieve author and committer information
|
||||
|
||||
var cacheAuthor *models.User
|
||||
var ok bool
|
||||
if userCache == nil {
|
||||
cacheAuthor = ((*models.User)(nil))
|
||||
ok = false
|
||||
} else {
|
||||
cacheAuthor, ok = userCache[commit.Author.Email]
|
||||
}
|
||||
|
||||
if ok {
|
||||
apiAuthor = cacheAuthor.APIFormat()
|
||||
} else {
|
||||
author, err := models.GetUserByEmail(commit.Author.Email)
|
||||
if err != nil && !models.IsErrUserNotExist(err) {
|
||||
return nil, err
|
||||
} else if err == nil {
|
||||
apiAuthor = author.APIFormat()
|
||||
if userCache != nil {
|
||||
userCache[commit.Author.Email] = author
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var cacheCommitter *models.User
|
||||
if userCache == nil {
|
||||
cacheCommitter = ((*models.User)(nil))
|
||||
ok = false
|
||||
} else {
|
||||
cacheCommitter, ok = userCache[commit.Committer.Email]
|
||||
}
|
||||
|
||||
if ok {
|
||||
apiCommitter = cacheCommitter.APIFormat()
|
||||
} else {
|
||||
committer, err := models.GetUserByEmail(commit.Committer.Email)
|
||||
if err != nil && !models.IsErrUserNotExist(err) {
|
||||
ctx.ServerError("Get user by committer email", err)
|
||||
return
|
||||
return nil, err
|
||||
} else if err == nil {
|
||||
apiCommitter = committer.APIFormat()
|
||||
if userCache != nil {
|
||||
userCache[commit.Committer.Email] = committer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,23 +245,23 @@ func GetSingleCommit(ctx *context.APIContext) {
|
||||
for i := 0; i < commit.ParentCount(); i++ {
|
||||
sha, _ := commit.ParentID(i)
|
||||
apiParents[i] = &api.CommitMeta{
|
||||
URL: ctx.Repo.Repository.APIURL() + "/git/commits/" + sha.String(),
|
||||
URL: repo.APIURL() + "/git/commits/" + sha.String(),
|
||||
SHA: sha.String(),
|
||||
}
|
||||
}
|
||||
|
||||
ctx.JSON(200, &api.Commit{
|
||||
return &api.Commit{
|
||||
CommitMeta: &api.CommitMeta{
|
||||
URL: setting.AppURL + ctx.Link[1:],
|
||||
URL: repo.APIURL() + "/git/commits/" + commit.ID.String(),
|
||||
SHA: commit.ID.String(),
|
||||
},
|
||||
HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commits/" + commit.ID.String(),
|
||||
HTMLURL: repo.HTMLURL() + "/commit/" + commit.ID.String(),
|
||||
RepoCommit: &api.RepoCommit{
|
||||
URL: setting.AppURL + ctx.Link[1:],
|
||||
URL: repo.APIURL() + "/git/commits/" + commit.ID.String(),
|
||||
Author: &api.CommitUser{
|
||||
Identity: api.Identity{
|
||||
Name: commit.Author.Name,
|
||||
Email: commit.Author.Email,
|
||||
Name: commit.Committer.Name,
|
||||
Email: commit.Committer.Email,
|
||||
},
|
||||
Date: commit.Author.When.Format(time.RFC3339),
|
||||
},
|
||||
@@ -109,14 +272,14 @@ func GetSingleCommit(ctx *context.APIContext) {
|
||||
},
|
||||
Date: commit.Committer.When.Format(time.RFC3339),
|
||||
},
|
||||
Message: commit.Message(),
|
||||
Message: commit.Summary(),
|
||||
Tree: &api.CommitMeta{
|
||||
URL: ctx.Repo.Repository.APIURL() + "/trees/" + commit.ID.String(),
|
||||
URL: repo.APIURL() + "/git/trees/" + commit.ID.String(),
|
||||
SHA: commit.ID.String(),
|
||||
},
|
||||
},
|
||||
Author: apiAuthor,
|
||||
Committer: apiCommitter,
|
||||
Parents: apiParents,
|
||||
})
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ package repo
|
||||
import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
|
||||
@@ -71,19 +71,22 @@ func GetGitRefs(ctx *context.APIContext) {
|
||||
getGitRefsInternal(ctx, ctx.Params("*"))
|
||||
}
|
||||
|
||||
func getGitRefsInternal(ctx *context.APIContext, filter string) {
|
||||
func getGitRefs(ctx *context.APIContext, filter string) ([]*git.Reference, string, error) {
|
||||
gitRepo, err := git.OpenRepository(ctx.Repo.Repository.RepoPath())
|
||||
if err != nil {
|
||||
ctx.Error(500, "OpenRepository", err)
|
||||
return
|
||||
return nil, "OpenRepository", err
|
||||
}
|
||||
if len(filter) > 0 {
|
||||
filter = "refs/" + filter
|
||||
}
|
||||
|
||||
refs, err := gitRepo.GetRefsFiltered(filter)
|
||||
return refs, "GetRefsFiltered", err
|
||||
}
|
||||
|
||||
func getGitRefsInternal(ctx *context.APIContext, filter string) {
|
||||
refs, lastMethodName, err := getGitRefs(ctx, filter)
|
||||
if err != nil {
|
||||
ctx.Error(500, "GetRefsFiltered", err)
|
||||
ctx.Error(500, lastMethodName, err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -130,8 +130,8 @@ func TestHook(ctx *context.APIContext) {
|
||||
convert.ToCommit(ctx.Repo.Repository, ctx.Repo.Commit),
|
||||
},
|
||||
Repo: ctx.Repo.Repository.APIFormat(models.AccessModeNone),
|
||||
Pusher: ctx.User.APIFormat(),
|
||||
Sender: ctx.User.APIFormat(),
|
||||
Pusher: convert.ToUser(ctx.User, ctx.IsSigned, false),
|
||||
Sender: convert.ToUser(ctx.User, ctx.IsSigned, false),
|
||||
}); err != nil {
|
||||
ctx.Error(500, "PrepareWebhook: ", err)
|
||||
return
|
||||
|
||||
@@ -16,9 +16,11 @@ import (
|
||||
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
issue_service "code.gitea.io/gitea/services/issue"
|
||||
milestone_service "code.gitea.io/gitea/services/milestone"
|
||||
)
|
||||
|
||||
// ListIssues list the issues of a repository
|
||||
@@ -183,9 +185,9 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
|
||||
// "201":
|
||||
// "$ref": "#/responses/Issue"
|
||||
|
||||
var deadlineUnix util.TimeStamp
|
||||
var deadlineUnix timeutil.TimeStamp
|
||||
if form.Deadline != nil && ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
||||
deadlineUnix = util.TimeStamp(form.Deadline.Unix())
|
||||
deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
|
||||
}
|
||||
|
||||
issue := &models.Issue{
|
||||
@@ -216,7 +218,7 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
|
||||
form.Labels = make([]int64, 0)
|
||||
}
|
||||
|
||||
if err := models.NewIssue(ctx.Repo.Repository, issue, form.Labels, assigneeIDs, nil); err != nil {
|
||||
if err := issue_service.NewIssue(ctx.Repo.Repository, issue, form.Labels, assigneeIDs, nil); err != nil {
|
||||
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
|
||||
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err)
|
||||
return
|
||||
@@ -310,9 +312,9 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
|
||||
}
|
||||
|
||||
// Update the deadline
|
||||
var deadlineUnix util.TimeStamp
|
||||
var deadlineUnix timeutil.TimeStamp
|
||||
if form.Deadline != nil && !form.Deadline.IsZero() && ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
||||
deadlineUnix = util.TimeStamp(form.Deadline.Unix())
|
||||
deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
|
||||
}
|
||||
|
||||
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
|
||||
@@ -345,7 +347,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
|
||||
issue.MilestoneID != *form.Milestone {
|
||||
oldMilestoneID := issue.MilestoneID
|
||||
issue.MilestoneID = *form.Milestone
|
||||
if err = models.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil {
|
||||
if err = milestone_service.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil {
|
||||
ctx.Error(500, "ChangeMilestoneAssign", err)
|
||||
return
|
||||
}
|
||||
@@ -430,12 +432,12 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) {
|
||||
return
|
||||
}
|
||||
|
||||
var deadlineUnix util.TimeStamp
|
||||
var deadlineUnix timeutil.TimeStamp
|
||||
var deadline time.Time
|
||||
if form.Deadline != nil && !form.Deadline.IsZero() {
|
||||
deadline = time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(),
|
||||
23, 59, 59, 0, form.Deadline.Location())
|
||||
deadlineUnix = util.TimeStamp(deadline.Unix())
|
||||
deadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
||||
}
|
||||
|
||||
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
|
||||
|
||||
@@ -11,8 +11,8 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
comment_service "code.gitea.io/gitea/services/comments"
|
||||
)
|
||||
|
||||
// ListIssueComments list all the comments of an issue
|
||||
@@ -190,7 +190,7 @@ func CreateIssueComment(ctx *context.APIContext, form api.CreateIssueCommentOpti
|
||||
return
|
||||
}
|
||||
|
||||
comment, err := models.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Body, nil)
|
||||
comment, err := comment_service.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Body, nil)
|
||||
if err != nil {
|
||||
ctx.Error(500, "CreateIssueComment", err)
|
||||
return
|
||||
@@ -300,7 +300,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption)
|
||||
|
||||
oldContent := comment.Content
|
||||
comment.Content = form.Body
|
||||
if err := models.UpdateComment(ctx.User, comment, oldContent); err != nil {
|
||||
if err := comment_service.UpdateComment(comment, ctx.User, oldContent); err != nil {
|
||||
ctx.Error(500, "UpdateComment", err)
|
||||
return
|
||||
}
|
||||
@@ -391,7 +391,7 @@ func deleteIssueComment(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = models.DeleteComment(ctx.User, comment); err != nil {
|
||||
if err = comment_service.DeleteComment(comment, ctx.User); err != nil {
|
||||
ctx.Error(500, "DeleteCommentByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ package repo
|
||||
import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ package repo
|
||||
import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
|
||||
@@ -10,9 +10,8 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
// appendPrivateInformation appends the owner and key type information to api.PublicKey
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,9 +9,8 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
)
|
||||
|
||||
// ListMilestones list milestones for a repository
|
||||
@@ -127,7 +126,7 @@ func CreateMilestone(ctx *context.APIContext, form api.CreateMilestoneOption) {
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: form.Title,
|
||||
Content: form.Description,
|
||||
DeadlineUnix: util.TimeStamp(form.Deadline.Unix()),
|
||||
DeadlineUnix: timeutil.TimeStamp(form.Deadline.Unix()),
|
||||
}
|
||||
|
||||
if err := models.NewMilestone(milestone); err != nil {
|
||||
@@ -187,7 +186,7 @@ func EditMilestone(ctx *context.APIContext, form api.EditMilestoneOption) {
|
||||
milestone.Content = *form.Description
|
||||
}
|
||||
if form.Deadline != nil && !form.Deadline.IsZero() {
|
||||
milestone.DeadlineUnix = util.TimeStamp(form.Deadline.Unix())
|
||||
milestone.DeadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
|
||||
}
|
||||
|
||||
if err := models.UpdateMilestone(milestone); err != nil {
|
||||
|
||||
+21
-16
@@ -15,9 +15,10 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/pull"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
milestone_service "code.gitea.io/gitea/services/milestone"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
)
|
||||
|
||||
// ListPullRequests returns a list of all PRs
|
||||
@@ -247,20 +248,13 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
|
||||
return
|
||||
}
|
||||
|
||||
var deadlineUnix util.TimeStamp
|
||||
var deadlineUnix timeutil.TimeStamp
|
||||
if form.Deadline != nil {
|
||||
deadlineUnix = util.TimeStamp(form.Deadline.Unix())
|
||||
}
|
||||
|
||||
maxIndex, err := models.GetMaxIndexOfIssue(repo.ID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetPatch", err)
|
||||
return
|
||||
deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
|
||||
}
|
||||
|
||||
prIssue := &models.Issue{
|
||||
RepoID: repo.ID,
|
||||
Index: maxIndex + 1,
|
||||
Title: form.Title,
|
||||
PosterID: ctx.User.ID,
|
||||
Poster: ctx.User,
|
||||
@@ -293,7 +287,7 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
|
||||
return
|
||||
}
|
||||
|
||||
if err := models.NewPullRequest(repo, prIssue, labelIDs, []string{}, pr, patch, assigneeIDs); err != nil {
|
||||
if err := pull_service.NewPullRequest(repo, prIssue, labelIDs, []string{}, pr, patch, assigneeIDs); err != nil {
|
||||
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
|
||||
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err)
|
||||
return
|
||||
@@ -375,9 +369,9 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
|
||||
}
|
||||
|
||||
// Update Deadline
|
||||
var deadlineUnix util.TimeStamp
|
||||
var deadlineUnix timeutil.TimeStamp
|
||||
if form.Deadline != nil && !form.Deadline.IsZero() {
|
||||
deadlineUnix = util.TimeStamp(form.Deadline.Unix())
|
||||
deadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
|
||||
}
|
||||
|
||||
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
|
||||
@@ -409,7 +403,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
|
||||
issue.MilestoneID != form.Milestone {
|
||||
oldMilestoneID := issue.MilestoneID
|
||||
issue.MilestoneID = form.Milestone
|
||||
if err = models.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil {
|
||||
if err = milestone_service.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil {
|
||||
ctx.Error(500, "ChangeMilestoneAssign", err)
|
||||
return
|
||||
}
|
||||
@@ -577,6 +571,17 @@ func MergePullRequest(ctx *context.APIContext, form auth.MergePullRequestForm) {
|
||||
return
|
||||
}
|
||||
|
||||
isPass, err := pull_service.IsPullCommitStatusPass(pr)
|
||||
if err != nil {
|
||||
ctx.Error(500, "IsPullCommitStatusPass", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !isPass && !ctx.IsUserRepoAdmin() {
|
||||
ctx.Status(405)
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.Do) == 0 {
|
||||
form.Do = string(models.MergeStyleMerge)
|
||||
}
|
||||
@@ -596,7 +601,7 @@ func MergePullRequest(ctx *context.APIContext, form auth.MergePullRequestForm) {
|
||||
message += "\n\n" + form.MergeMessageField
|
||||
}
|
||||
|
||||
if err := pull.Merge(pr, ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil {
|
||||
if err := pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil {
|
||||
if models.IsErrInvalidMergeStyle(err) {
|
||||
ctx.Status(405)
|
||||
return
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
releaseservice "code.gitea.io/gitea/services/release"
|
||||
)
|
||||
|
||||
// GetRelease get a single release of a repository
|
||||
@@ -169,7 +169,7 @@ func CreateRelease(ctx *context.APIContext, form api.CreateReleaseOption) {
|
||||
IsTag: false,
|
||||
Repo: ctx.Repo.Repository,
|
||||
}
|
||||
if err := models.CreateRelease(ctx.Repo.GitRepo, rel, nil); err != nil {
|
||||
if err := releaseservice.CreateRelease(ctx.Repo.GitRepo, rel, nil); err != nil {
|
||||
if models.IsErrReleaseAlreadyExist(err) {
|
||||
ctx.Status(409)
|
||||
} else {
|
||||
@@ -192,7 +192,7 @@ func CreateRelease(ctx *context.APIContext, form api.CreateReleaseOption) {
|
||||
rel.Repo = ctx.Repo.Repository
|
||||
rel.Publisher = ctx.User
|
||||
|
||||
if err = models.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, nil); err != nil {
|
||||
if err = releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, nil); err != nil {
|
||||
ctx.ServerError("UpdateRelease", err)
|
||||
return
|
||||
}
|
||||
@@ -263,7 +263,7 @@ func EditRelease(ctx *context.APIContext, form api.EditReleaseOption) {
|
||||
if form.IsPrerelease != nil {
|
||||
rel.IsPrerelease = *form.IsPrerelease
|
||||
}
|
||||
if err := models.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, nil); err != nil {
|
||||
if err := releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, nil); err != nil {
|
||||
ctx.Error(500, "UpdateRelease", err)
|
||||
return
|
||||
}
|
||||
@@ -316,7 +316,7 @@ func DeleteRelease(ctx *context.APIContext) {
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
if err := models.DeleteReleaseByID(id, ctx.User, false); err != nil {
|
||||
if err := releaseservice.DeleteReleaseByID(id, ctx.User, false); err != nil {
|
||||
ctx.Error(500, "DeleteReleaseByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/upload"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/upload"
|
||||
)
|
||||
|
||||
// GetReleaseAttachment gets a single attachment of the release
|
||||
@@ -56,6 +56,7 @@ func GetReleaseAttachment(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
if attach.ReleaseID != releaseID {
|
||||
log.Info("User requested attachment is not in release, release_id %v, attachment_id: %v", releaseID, attachID)
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
@@ -243,13 +244,14 @@ func EditReleaseAttachment(ctx *context.APIContext, form api.EditAttachmentOptio
|
||||
|
||||
// Check if release exists an load release
|
||||
releaseID := ctx.ParamsInt64(":id")
|
||||
attachID := ctx.ParamsInt64(":attachment")
|
||||
attachID := ctx.ParamsInt64(":asset")
|
||||
attach, err := models.GetAttachmentByID(attachID)
|
||||
if err != nil {
|
||||
ctx.Error(500, "GetAttachmentByID", err)
|
||||
return
|
||||
}
|
||||
if attach.ReleaseID != releaseID {
|
||||
log.Info("User requested attachment is not in release, release_id %v, attachment_id: %v", releaseID, attachID)
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
@@ -300,13 +302,14 @@ func DeleteReleaseAttachment(ctx *context.APIContext) {
|
||||
|
||||
// Check if release exists an load release
|
||||
releaseID := ctx.ParamsInt64(":id")
|
||||
attachID := ctx.ParamsInt64(":attachment")
|
||||
attachID := ctx.ParamsInt64(":asset")
|
||||
attach, err := models.GetAttachmentByID(attachID)
|
||||
if err != nil {
|
||||
ctx.Error(500, "GetAttachmentByID", err)
|
||||
return
|
||||
}
|
||||
if attach.ReleaseID != releaseID {
|
||||
log.Info("User requested attachment is not in release, release_id %v, attachment_id: %v", releaseID, attachID)
|
||||
ctx.NotFound()
|
||||
return
|
||||
}
|
||||
|
||||
+143
-112
@@ -15,11 +15,13 @@ import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/migrations"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
mirror_service "code.gitea.io/gitea/services/mirror"
|
||||
)
|
||||
|
||||
var searchOrderByMap = map[string]map[string]models.SearchOrderBy{
|
||||
@@ -51,6 +53,14 @@ func Search(ctx *context.APIContext) {
|
||||
// in: query
|
||||
// description: keyword
|
||||
// type: string
|
||||
// - name: topic
|
||||
// in: query
|
||||
// description: Limit search to repositories with keyword as topic
|
||||
// type: boolean
|
||||
// - name: includeDesc
|
||||
// in: query
|
||||
// description: include search of keyword within repository description
|
||||
// type: boolean
|
||||
// - name: uid
|
||||
// in: query
|
||||
// description: search only for repos that the user with the given id owns or contributes to
|
||||
@@ -99,16 +109,17 @@ func Search(ctx *context.APIContext) {
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
opts := &models.SearchRepoOptions{
|
||||
Keyword: strings.Trim(ctx.Query("q"), " "),
|
||||
OwnerID: ctx.QueryInt64("uid"),
|
||||
Page: ctx.QueryInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
|
||||
TopicOnly: ctx.QueryBool("topic"),
|
||||
Collaborate: util.OptionalBoolNone,
|
||||
Private: ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")),
|
||||
UserIsAdmin: ctx.IsUserSiteAdmin(),
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
StarredByID: ctx.QueryInt64("starredBy"),
|
||||
Keyword: strings.Trim(ctx.Query("q"), " "),
|
||||
OwnerID: ctx.QueryInt64("uid"),
|
||||
Page: ctx.QueryInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.QueryInt("limit")),
|
||||
TopicOnly: ctx.QueryBool("topic"),
|
||||
Collaborate: util.OptionalBoolNone,
|
||||
Private: ctx.IsSigned && (ctx.Query("private") == "" || ctx.QueryBool("private")),
|
||||
UserIsAdmin: ctx.IsUserSiteAdmin(),
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
StarredByID: ctx.QueryInt64("starredBy"),
|
||||
IncludeDescription: ctx.QueryBool("includeDesc"),
|
||||
}
|
||||
|
||||
if ctx.QueryBool("exclusive") {
|
||||
@@ -153,7 +164,7 @@ func Search(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
var err error
|
||||
repos, count, err := models.SearchRepositoryByName(opts)
|
||||
repos, count, err := models.SearchRepository(opts)
|
||||
if err != nil {
|
||||
ctx.JSON(500, api.SearchError{
|
||||
OK: false,
|
||||
@@ -197,6 +208,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateR
|
||||
repo, err := models.CreateRepository(ctx.User, owner, models.CreateRepoOptions{
|
||||
Name: opt.Name,
|
||||
Description: opt.Description,
|
||||
IssueLabels: opt.IssueLabels,
|
||||
Gitignores: opt.Gitignores,
|
||||
License: opt.License,
|
||||
Readme: opt.Readme,
|
||||
@@ -220,6 +232,8 @@ func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateR
|
||||
return
|
||||
}
|
||||
|
||||
notification.NotifyCreateRepository(ctx.User, owner, repo)
|
||||
|
||||
ctx.JSON(201, repo.APIFormat(models.AccessModeOwner))
|
||||
}
|
||||
|
||||
@@ -410,6 +424,8 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
|
||||
|
||||
repo, err := migrations.MigrateRepository(ctx.User, ctxUser.Name, opts)
|
||||
if err == nil {
|
||||
notification.NotifyCreateRepository(ctx.User, ctxUser, repo)
|
||||
|
||||
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
|
||||
ctx.JSON(201, repo.APIFormat(models.AccessModeAdmin))
|
||||
return
|
||||
@@ -646,15 +662,48 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
})
|
||||
}
|
||||
|
||||
if opts.HasIssues != nil {
|
||||
if *opts.HasIssues {
|
||||
// We don't currently allow setting individual issue settings through the API,
|
||||
// only can enable/disable issues, so when enabling issues,
|
||||
// we either get the existing config which means it was already enabled,
|
||||
// or create a new config since it doesn't exist.
|
||||
unit, err := repo.GetUnit(models.UnitTypeIssues)
|
||||
if opts.HasIssues == nil {
|
||||
// If HasIssues setting not touched, rewrite existing repo unit
|
||||
if unit, err := repo.GetUnit(models.UnitTypeIssues); err == nil {
|
||||
units = append(units, *unit)
|
||||
} else if unit, err := repo.GetUnit(models.UnitTypeExternalTracker); err == nil {
|
||||
units = append(units, *unit)
|
||||
}
|
||||
} else if *opts.HasIssues {
|
||||
if opts.ExternalTracker != nil {
|
||||
|
||||
// Check that values are valid
|
||||
if !validation.IsValidExternalURL(opts.ExternalTracker.ExternalTrackerURL) {
|
||||
err := fmt.Errorf("External tracker URL not valid")
|
||||
ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL", err)
|
||||
return err
|
||||
}
|
||||
if len(opts.ExternalTracker.ExternalTrackerFormat) != 0 && !validation.IsValidExternalTrackerURLFormat(opts.ExternalTracker.ExternalTrackerFormat) {
|
||||
err := fmt.Errorf("External tracker URL format not valid")
|
||||
ctx.Error(http.StatusUnprocessableEntity, "Invalid external tracker URL format", err)
|
||||
return err
|
||||
}
|
||||
|
||||
units = append(units, models.RepoUnit{
|
||||
RepoID: repo.ID,
|
||||
Type: models.UnitTypeExternalTracker,
|
||||
Config: &models.ExternalTrackerConfig{
|
||||
ExternalTrackerURL: opts.ExternalTracker.ExternalTrackerURL,
|
||||
ExternalTrackerFormat: opts.ExternalTracker.ExternalTrackerFormat,
|
||||
ExternalTrackerStyle: opts.ExternalTracker.ExternalTrackerStyle,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
// Default to built-in tracker
|
||||
var config *models.IssuesConfig
|
||||
if err != nil {
|
||||
|
||||
if opts.InternalTracker != nil {
|
||||
config = &models.IssuesConfig{
|
||||
EnableTimetracker: opts.InternalTracker.EnableTimeTracker,
|
||||
AllowOnlyContributorsToTrackTime: opts.InternalTracker.AllowOnlyContributorsToTrackTime,
|
||||
EnableDependencies: opts.InternalTracker.EnableIssueDependencies,
|
||||
}
|
||||
} else if unit, err := repo.GetUnit(models.UnitTypeIssues); err != nil {
|
||||
// Unit type doesn't exist so we make a new config file with default values
|
||||
config = &models.IssuesConfig{
|
||||
EnableTimetracker: true,
|
||||
@@ -664,6 +713,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
} else {
|
||||
config = unit.IssuesConfig()
|
||||
}
|
||||
|
||||
units = append(units, models.RepoUnit{
|
||||
RepoID: repo.ID,
|
||||
Type: models.UnitTypeIssues,
|
||||
@@ -672,12 +722,31 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
}
|
||||
}
|
||||
|
||||
if opts.HasWiki != nil {
|
||||
if *opts.HasWiki {
|
||||
// We don't currently allow setting individual wiki settings through the API,
|
||||
// only can enable/disable the wiki, so when enabling the wiki,
|
||||
// we either get the existing config which means it was already enabled,
|
||||
// or create a new config since it doesn't exist.
|
||||
if opts.HasWiki == nil {
|
||||
// If HasWiki setting not touched, rewrite existing repo unit
|
||||
if unit, err := repo.GetUnit(models.UnitTypeWiki); err == nil {
|
||||
units = append(units, *unit)
|
||||
} else if unit, err := repo.GetUnit(models.UnitTypeExternalWiki); err == nil {
|
||||
units = append(units, *unit)
|
||||
}
|
||||
} else if *opts.HasWiki {
|
||||
if opts.ExternalWiki != nil {
|
||||
|
||||
// Check that values are valid
|
||||
if !validation.IsValidExternalURL(opts.ExternalWiki.ExternalWikiURL) {
|
||||
err := fmt.Errorf("External wiki URL not valid")
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", "Invalid external wiki URL")
|
||||
return err
|
||||
}
|
||||
|
||||
units = append(units, models.RepoUnit{
|
||||
RepoID: repo.ID,
|
||||
Type: models.UnitTypeExternalWiki,
|
||||
Config: &models.ExternalWikiConfig{
|
||||
ExternalWikiURL: opts.ExternalWiki.ExternalWikiURL,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
config := &models.UnitConfig{}
|
||||
units = append(units, models.RepoUnit{
|
||||
RepoID: repo.ID,
|
||||
@@ -687,48 +756,51 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
|
||||
}
|
||||
}
|
||||
|
||||
if opts.HasPullRequests != nil {
|
||||
if *opts.HasPullRequests {
|
||||
// We do allow setting individual PR settings through the API, so
|
||||
// we get the config settings and then set them
|
||||
// if those settings were provided in the opts.
|
||||
unit, err := repo.GetUnit(models.UnitTypePullRequests)
|
||||
var config *models.PullRequestsConfig
|
||||
if err != nil {
|
||||
// Unit type doesn't exist so we make a new config file with default values
|
||||
config = &models.PullRequestsConfig{
|
||||
IgnoreWhitespaceConflicts: false,
|
||||
AllowMerge: true,
|
||||
AllowRebase: true,
|
||||
AllowRebaseMerge: true,
|
||||
AllowSquash: true,
|
||||
}
|
||||
} else {
|
||||
config = unit.PullRequestsConfig()
|
||||
}
|
||||
|
||||
if opts.IgnoreWhitespaceConflicts != nil {
|
||||
config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts
|
||||
}
|
||||
if opts.AllowMerge != nil {
|
||||
config.AllowMerge = *opts.AllowMerge
|
||||
}
|
||||
if opts.AllowRebase != nil {
|
||||
config.AllowRebase = *opts.AllowRebase
|
||||
}
|
||||
if opts.AllowRebaseMerge != nil {
|
||||
config.AllowRebaseMerge = *opts.AllowRebaseMerge
|
||||
}
|
||||
if opts.AllowSquash != nil {
|
||||
config.AllowSquash = *opts.AllowSquash
|
||||
}
|
||||
|
||||
units = append(units, models.RepoUnit{
|
||||
RepoID: repo.ID,
|
||||
Type: models.UnitTypePullRequests,
|
||||
Config: config,
|
||||
})
|
||||
if opts.HasPullRequests == nil {
|
||||
// If HasPullRequest setting not touched, rewrite existing repo unit
|
||||
if unit, err := repo.GetUnit(models.UnitTypePullRequests); err == nil {
|
||||
units = append(units, *unit)
|
||||
}
|
||||
} else if *opts.HasPullRequests {
|
||||
// We do allow setting individual PR settings through the API, so
|
||||
// we get the config settings and then set them
|
||||
// if those settings were provided in the opts.
|
||||
unit, err := repo.GetUnit(models.UnitTypePullRequests)
|
||||
var config *models.PullRequestsConfig
|
||||
if err != nil {
|
||||
// Unit type doesn't exist so we make a new config file with default values
|
||||
config = &models.PullRequestsConfig{
|
||||
IgnoreWhitespaceConflicts: false,
|
||||
AllowMerge: true,
|
||||
AllowRebase: true,
|
||||
AllowRebaseMerge: true,
|
||||
AllowSquash: true,
|
||||
}
|
||||
} else {
|
||||
config = unit.PullRequestsConfig()
|
||||
}
|
||||
|
||||
if opts.IgnoreWhitespaceConflicts != nil {
|
||||
config.IgnoreWhitespaceConflicts = *opts.IgnoreWhitespaceConflicts
|
||||
}
|
||||
if opts.AllowMerge != nil {
|
||||
config.AllowMerge = *opts.AllowMerge
|
||||
}
|
||||
if opts.AllowRebase != nil {
|
||||
config.AllowRebase = *opts.AllowRebase
|
||||
}
|
||||
if opts.AllowRebaseMerge != nil {
|
||||
config.AllowRebaseMerge = *opts.AllowRebaseMerge
|
||||
}
|
||||
if opts.AllowSquash != nil {
|
||||
config.AllowSquash = *opts.AllowSquash
|
||||
}
|
||||
|
||||
units = append(units, models.RepoUnit{
|
||||
RepoID: repo.ID,
|
||||
Type: models.UnitTypePullRequests,
|
||||
Config: config,
|
||||
})
|
||||
}
|
||||
|
||||
if err := models.UpdateRepositoryUnits(repo, units); err != nil {
|
||||
@@ -842,48 +914,7 @@ func MirrorSync(ctx *context.APIContext) {
|
||||
ctx.Error(403, "MirrorSync", "Must have write access")
|
||||
}
|
||||
|
||||
go models.MirrorQueue.Add(repo.ID)
|
||||
mirror_service.StartToMirror(repo.ID)
|
||||
|
||||
ctx.Status(200)
|
||||
}
|
||||
|
||||
// TopicSearch search for creating topic
|
||||
func TopicSearch(ctx *context.Context) {
|
||||
// swagger:operation GET /topics/search repository topicSearch
|
||||
// ---
|
||||
// summary: search topics via keyword
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: q
|
||||
// in: query
|
||||
// description: keywords to search
|
||||
// required: true
|
||||
// type: string
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/Repository"
|
||||
if ctx.User == nil {
|
||||
ctx.JSON(403, map[string]interface{}{
|
||||
"message": "Only owners could change the topics.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
kw := ctx.Query("q")
|
||||
|
||||
topics, err := models.FindTopics(&models.FindTopicOptions{
|
||||
Keyword: kw,
|
||||
Limit: 10,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("SearchTopics failed: %v", err)
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
"message": "Search topics failed.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"topics": topics,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ package repo
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
// ListStargazers list a repository's stargazers
|
||||
@@ -38,7 +38,7 @@ func ListStargazers(ctx *context.APIContext) {
|
||||
}
|
||||
users := make([]*api.User, len(stargazers))
|
||||
for i, stargazer := range stargazers {
|
||||
users[i] = stargazer.APIFormat()
|
||||
users[i] = convert.ToUser(stargazer, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
|
||||
}
|
||||
ctx.JSON(200, users)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/repofiles"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
@@ -46,10 +45,7 @@ func NewCommitStatus(ctx *context.APIContext, form api.CreateStatusOption) {
|
||||
// "$ref": "#/responses/StatusList"
|
||||
sha := ctx.Params("sha")
|
||||
if len(sha) == 0 {
|
||||
sha = ctx.Params("ref")
|
||||
}
|
||||
if len(sha) == 0 {
|
||||
ctx.Error(400, "ref/sha not given", nil)
|
||||
ctx.Error(400, "sha not given", nil)
|
||||
return
|
||||
}
|
||||
status := &models.CommitStatus{
|
||||
@@ -89,6 +85,23 @@ func GetCommitStatuses(ctx *context.APIContext) {
|
||||
// description: sha of the commit
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of results
|
||||
// type: integer
|
||||
// required: false
|
||||
// - name: sort
|
||||
// in: query
|
||||
// description: type of sort
|
||||
// type: string
|
||||
// enum: [oldest, recentupdate, leastupdate, leastindex, highestindex]
|
||||
// required: false
|
||||
// - name: state
|
||||
// in: query
|
||||
// description: type of state
|
||||
// type: string
|
||||
// enum: [pending, success, error, failure, warning]
|
||||
// required: false
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/StatusList"
|
||||
@@ -118,10 +131,58 @@ func GetCommitStatusesByRef(ctx *context.APIContext) {
|
||||
// description: name of branch/tag/commit
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of results
|
||||
// type: integer
|
||||
// required: false
|
||||
// - name: sort
|
||||
// in: query
|
||||
// description: type of sort
|
||||
// type: string
|
||||
// enum: [oldest, recentupdate, leastupdate, leastindex, highestindex]
|
||||
// required: false
|
||||
// - name: state
|
||||
// in: query
|
||||
// description: type of state
|
||||
// type: string
|
||||
// enum: [pending, success, error, failure, warning]
|
||||
// required: false
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/StatusList"
|
||||
getCommitStatuses(ctx, ctx.Params("ref"))
|
||||
|
||||
filter := ctx.Params("ref")
|
||||
if len(filter) == 0 {
|
||||
ctx.Error(400, "ref not given", nil)
|
||||
return
|
||||
}
|
||||
|
||||
for _, reftype := range []string{"heads", "tags"} { //Search branches and tags
|
||||
refSHA, lastMethodName, err := searchRefCommitByType(ctx, reftype, filter)
|
||||
if err != nil {
|
||||
ctx.Error(500, lastMethodName, err)
|
||||
return
|
||||
}
|
||||
if refSHA != "" {
|
||||
filter = refSHA
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getCommitStatuses(ctx, filter) //By default filter is maybe the raw SHA
|
||||
}
|
||||
|
||||
func searchRefCommitByType(ctx *context.APIContext, refType, filter string) (string, string, error) {
|
||||
refs, lastMethodName, err := getGitRefs(ctx, refType+"/"+filter) //Search by type
|
||||
if err != nil {
|
||||
return "", lastMethodName, err
|
||||
}
|
||||
if len(refs) > 0 {
|
||||
return refs[0].Object.String(), "", nil //Return found SHA
|
||||
}
|
||||
return "", "", nil
|
||||
}
|
||||
|
||||
func getCommitStatuses(ctx *context.APIContext, sha string) {
|
||||
@@ -131,11 +192,13 @@ func getCommitStatuses(ctx *context.APIContext, sha string) {
|
||||
}
|
||||
repo := ctx.Repo.Repository
|
||||
|
||||
page := ctx.ParamsInt("page")
|
||||
|
||||
statuses, err := models.GetCommitStatuses(repo, sha, page)
|
||||
statuses, _, err := models.GetCommitStatuses(repo, sha, &models.CommitStatusOptions{
|
||||
Page: ctx.QueryInt("page"),
|
||||
SortType: ctx.QueryTrim("sort"),
|
||||
State: ctx.QueryTrim("state"),
|
||||
})
|
||||
if err != nil {
|
||||
ctx.Error(500, "GetCommitStatuses", fmt.Errorf("GetCommitStatuses[%s, %s, %d]: %v", repo.FullName(), sha, page, err))
|
||||
ctx.Error(500, "GetCommitStatuses", fmt.Errorf("GetCommitStatuses[%s, %s, %d]: %v", repo.FullName(), sha, ctx.QueryInt("page"), err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -180,6 +243,11 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) {
|
||||
// description: name of branch/tag/commit
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: page
|
||||
// in: query
|
||||
// description: page number of results
|
||||
// type: integer
|
||||
// required: false
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/Status"
|
||||
@@ -190,7 +258,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) {
|
||||
}
|
||||
repo := ctx.Repo.Repository
|
||||
|
||||
page := ctx.ParamsInt("page")
|
||||
page := ctx.QueryInt("page")
|
||||
|
||||
statuses, err := models.GetLatestCommitStatus(repo, sha, page)
|
||||
if err != nil {
|
||||
|
||||
@@ -6,8 +6,8 @@ package repo
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
// ListSubscribers list a repo's subscribers (i.e. watchers)
|
||||
@@ -38,7 +38,7 @@ func ListSubscribers(ctx *context.APIContext) {
|
||||
}
|
||||
users := make([]*api.User, len(subscribers))
|
||||
for i, subscriber := range subscribers {
|
||||
users[i] = subscriber.APIFormat()
|
||||
users[i] = convert.ToUser(subscriber, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
|
||||
}
|
||||
ctx.JSON(200, users)
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
// ListTags list all the tags of a repository
|
||||
@@ -51,7 +51,7 @@ func ListTags(ctx *context.APIContext) {
|
||||
func GetTag(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/git/tags/{sha} repository GetTag
|
||||
// ---
|
||||
// summary: Gets the tag of a repository.
|
||||
// summary: Gets the tag object of an annotated tag (not lightweight tags)
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
@@ -67,7 +67,7 @@ func GetTag(ctx *context.APIContext) {
|
||||
// required: true
|
||||
// - name: sha
|
||||
// in: path
|
||||
// description: sha of the tag
|
||||
// description: sha of the tag. The Git tags API only supports annotated tag objects, not lightweight tags.
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
// Copyright 2019 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 repo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
// ListTopics returns list of current topics for repo
|
||||
func ListTopics(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/topics repository repoListTopics
|
||||
// ---
|
||||
// summary: Get list of topics that a repository has
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/TopicNames"
|
||||
|
||||
topics, err := models.FindTopics(&models.FindTopicOptions{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("ListTopics failed: %v", err)
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
"message": "ListTopics failed.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
topicNames := make([]string, len(topics))
|
||||
for i, topic := range topics {
|
||||
topicNames[i] = topic.Name
|
||||
}
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"topics": topicNames,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateTopics updates repo with a new set of topics
|
||||
func UpdateTopics(ctx *context.APIContext, form api.RepoTopicOptions) {
|
||||
// swagger:operation PUT /repos/{owner}/{repo}/topics repository repoUpdateTopics
|
||||
// ---
|
||||
// summary: Replace list of topics for a repository
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: body
|
||||
// in: body
|
||||
// schema:
|
||||
// "$ref": "#/definitions/RepoTopicOptions"
|
||||
// responses:
|
||||
// "204":
|
||||
// "$ref": "#/responses/empty"
|
||||
|
||||
topicNames := form.Topics
|
||||
validTopics, invalidTopics := models.SanitizeAndValidateTopics(topicNames)
|
||||
|
||||
if len(validTopics) > 25 {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
||||
"invalidTopics": nil,
|
||||
"message": "Exceeding maximum number of topics per repo",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if len(invalidTopics) > 0 {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
||||
"invalidTopics": invalidTopics,
|
||||
"message": "Topic names are invalid",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
err := models.SaveTopics(ctx.Repo.Repository.ID, validTopics...)
|
||||
if err != nil {
|
||||
log.Error("SaveTopics failed: %v", err)
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
"message": "Save topics failed.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// AddTopic adds a topic name to a repo
|
||||
func AddTopic(ctx *context.APIContext) {
|
||||
// swagger:operation PUT /repos/{owner}/{repo}/topics/{topic} repository repoAddTopíc
|
||||
// ---
|
||||
// summary: Add a topic to a repository
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: topic
|
||||
// in: path
|
||||
// description: name of the topic to add
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// "204":
|
||||
// "$ref": "#/responses/empty"
|
||||
|
||||
topicName := strings.TrimSpace(strings.ToLower(ctx.Params(":topic")))
|
||||
|
||||
if !models.ValidateTopic(topicName) {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", "Topic name is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
// Prevent adding more topics than allowed to repo
|
||||
topics, err := models.FindTopics(&models.FindTopicOptions{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("AddTopic failed: %v", err)
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
"message": "ListTopics failed.",
|
||||
})
|
||||
return
|
||||
}
|
||||
if len(topics) >= 25 {
|
||||
ctx.JSON(http.StatusUnprocessableEntity, map[string]interface{}{
|
||||
"message": "Exceeding maximum allowed topics per repo.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
_, err = models.AddTopic(ctx.Repo.Repository.ID, topicName)
|
||||
if err != nil {
|
||||
log.Error("AddTopic failed: %v", err)
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
"message": "AddTopic failed.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// DeleteTopic removes topic name from repo
|
||||
func DeleteTopic(ctx *context.APIContext) {
|
||||
// swagger:operation DELETE /repos/{owner}/{repo}/topics/{topic} repository repoDeleteTopic
|
||||
// ---
|
||||
// summary: Delete a topic from a repository
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: owner
|
||||
// in: path
|
||||
// description: owner of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: repo
|
||||
// in: path
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: topic
|
||||
// in: path
|
||||
// description: name of the topic to delete
|
||||
// type: string
|
||||
// required: true
|
||||
// responses:
|
||||
// "204":
|
||||
// "$ref": "#/responses/empty"
|
||||
topicName := strings.TrimSpace(strings.ToLower(ctx.Params(":topic")))
|
||||
|
||||
if !models.ValidateTopic(topicName) {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", "Topic name is invalid")
|
||||
return
|
||||
}
|
||||
|
||||
topic, err := models.DeleteTopic(ctx.Repo.Repository.ID, topicName)
|
||||
if err != nil {
|
||||
log.Error("DeleteTopic failed: %v", err)
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
"message": "DeleteTopic failed.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if topic == nil {
|
||||
ctx.NotFound()
|
||||
}
|
||||
|
||||
ctx.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// TopicSearch search for creating topic
|
||||
func TopicSearch(ctx *context.Context) {
|
||||
// swagger:operation GET /topics/search repository topicSearch
|
||||
// ---
|
||||
// summary: search topics via keyword
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - name: q
|
||||
// in: query
|
||||
// description: keywords to search
|
||||
// required: true
|
||||
// type: string
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/TopicListResponse"
|
||||
if ctx.User == nil {
|
||||
ctx.JSON(http.StatusForbidden, map[string]interface{}{
|
||||
"message": "Only owners could change the topics.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
kw := ctx.Query("q")
|
||||
|
||||
topics, err := models.FindTopics(&models.FindTopicOptions{
|
||||
Keyword: kw,
|
||||
Limit: 10,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("SearchTopics failed: %v", err)
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
"message": "Search topics failed.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
topicResponses := make([]*api.TopicResponse, len(topics))
|
||||
for i, topic := range topics {
|
||||
topicResponses[i] = convert.ToTopicResponse(topic)
|
||||
}
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"topics": topicResponses,
|
||||
})
|
||||
}
|
||||
@@ -117,4 +117,7 @@ type swaggerParameterBodies struct {
|
||||
|
||||
// in:body
|
||||
DeleteFileOptions api.DeleteFileOptions
|
||||
|
||||
// in:body
|
||||
RepoTopicOptions api.RepoTopicOptions
|
||||
}
|
||||
|
||||
@@ -190,6 +190,35 @@ type swaggerCommit struct {
|
||||
Body api.Commit `json:"body"`
|
||||
}
|
||||
|
||||
// CommitList
|
||||
// swagger:response CommitList
|
||||
type swaggerCommitList struct {
|
||||
// The current page
|
||||
Page int `json:"X-Page"`
|
||||
|
||||
// Commits per page
|
||||
PerPage int `json:"X-PerPage"`
|
||||
|
||||
// Total commit count
|
||||
Total int `json:"X-Total"`
|
||||
|
||||
// Total number of pages
|
||||
PageCount int `json:"X-PageCount"`
|
||||
|
||||
// True if there is another page
|
||||
HasMore bool `json:"X-HasMore"`
|
||||
|
||||
//in: body
|
||||
Body []api.Commit `json:"body"`
|
||||
}
|
||||
|
||||
// EmptyRepository
|
||||
// swagger:response EmptyRepository
|
||||
type swaggerEmptyRepository struct {
|
||||
//in: body
|
||||
Body api.APIError `json:"body"`
|
||||
}
|
||||
|
||||
// FileResponse
|
||||
// swagger:response FileResponse
|
||||
type swaggerFileResponse struct {
|
||||
@@ -217,3 +246,17 @@ type swaggerFileDeleteResponse struct {
|
||||
//in: body
|
||||
Body api.FileDeleteResponse `json:"body"`
|
||||
}
|
||||
|
||||
// TopicListResponse
|
||||
// swagger:response TopicListResponse
|
||||
type swaggerTopicListResponse struct {
|
||||
//in: body
|
||||
Body []api.TopicResponse `json:"body"`
|
||||
}
|
||||
|
||||
// TopicNames
|
||||
// swagger:response TopicNames
|
||||
type swaggerTopicNames struct {
|
||||
//in: body
|
||||
Body api.TopicName `json:"body"`
|
||||
}
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// ListAccessTokens list all the access tokens
|
||||
@@ -36,9 +35,6 @@ func ListAccessTokens(ctx *context.APIContext) {
|
||||
|
||||
apiTokens := make([]*api.AccessToken, len(tokens))
|
||||
for i := range tokens {
|
||||
if tokens[i].Name == "drone" {
|
||||
tokens[i].Name = "drone-legacy-use-oauth2-instead"
|
||||
}
|
||||
apiTokens[i] = &api.AccessToken{
|
||||
ID: tokens[i].ID,
|
||||
Name: tokens[i].Name,
|
||||
@@ -79,9 +75,6 @@ func CreateAccessToken(ctx *context.APIContext, form api.CreateAccessTokenOption
|
||||
UID: ctx.User.ID,
|
||||
Name: form.Name,
|
||||
}
|
||||
if t.Name == "drone" {
|
||||
t.Name = "drone-legacy-use-oauth2-instead"
|
||||
}
|
||||
if err := models.NewAccessToken(t); err != nil {
|
||||
ctx.Error(500, "NewAccessToken", err)
|
||||
return
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
func responseAPIUsers(ctx *context.APIContext, users []*models.User) {
|
||||
apiUsers := make([]*api.User, len(users))
|
||||
for i := range users {
|
||||
apiUsers[i] = users[i].APIFormat()
|
||||
apiUsers[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
|
||||
}
|
||||
ctx.JSON(200, &apiUsers)
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
)
|
||||
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
"code.gitea.io/gitea/routers/api/v1/repo"
|
||||
)
|
||||
@@ -22,13 +21,13 @@ func appendPrivateInformation(apiKey *api.PublicKey, key *models.PublicKey, defa
|
||||
apiKey.KeyType = "user"
|
||||
|
||||
if defaultUser.ID == key.OwnerID {
|
||||
apiKey.Owner = defaultUser.APIFormat()
|
||||
apiKey.Owner = convert.ToUser(defaultUser, true, true)
|
||||
} else {
|
||||
user, err := models.GetUserByID(key.OwnerID)
|
||||
if err != nil {
|
||||
return apiKey, err
|
||||
}
|
||||
apiKey.Owner = user.APIFormat()
|
||||
apiKey.Owner = convert.ToUser(user, true, true)
|
||||
}
|
||||
} else {
|
||||
apiKey.KeyType = "unknown"
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// getStarredRepos returns the repos that the user with the specified userID has
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
// Search search users
|
||||
@@ -104,11 +104,7 @@ func GetInfo(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
// Hide user e-mail when API caller isn't signed in.
|
||||
if !ctx.IsSigned {
|
||||
u.Email = ""
|
||||
}
|
||||
ctx.JSON(200, u.APIFormat())
|
||||
ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.ID == u.ID || ctx.User.IsAdmin))
|
||||
}
|
||||
|
||||
// GetAuthenticatedUser get current user's information
|
||||
@@ -121,7 +117,7 @@ func GetAuthenticatedUser(ctx *context.APIContext) {
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/User"
|
||||
ctx.JSON(200, ctx.User.APIFormat())
|
||||
ctx.JSON(200, convert.ToUser(ctx.User, ctx.IsSigned, ctx.User != nil))
|
||||
}
|
||||
|
||||
// GetUserHeatmapData is the handler to get a users heatmap
|
||||
|
||||
@@ -5,11 +5,10 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// getWatchedRepos returns the repos that the user with the specified userID is
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"code.gitea.io/gitea/routers/api/v1/convert"
|
||||
"code.gitea.io/gitea/routers/utils"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
// GetOrgHook get an organization's webhook. If there is an error, write to
|
||||
@@ -112,6 +112,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID
|
||||
Repository: com.IsSliceContainsStr(form.Events, string(models.HookEventRepository)),
|
||||
Release: com.IsSliceContainsStr(form.Events, string(models.HookEventRelease)),
|
||||
},
|
||||
BranchFilter: form.BranchFilter,
|
||||
},
|
||||
IsActive: form.Active,
|
||||
HookTaskType: models.ToHookTaskType(form.Type),
|
||||
@@ -236,6 +237,7 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *models.Webho
|
||||
w.PullRequest = com.IsSliceContainsStr(form.Events, string(models.HookEventPullRequest))
|
||||
w.Repository = com.IsSliceContainsStr(form.Events, string(models.HookEventRepository))
|
||||
w.Release = com.IsSliceContainsStr(form.Events, string(models.HookEventRelease))
|
||||
w.BranchFilter = form.BranchFilter
|
||||
|
||||
if err := w.UpdateEvent(); err != nil {
|
||||
ctx.Error(500, "UpdateEvent", err)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
)
|
||||
|
||||
// TemplatePreview render for previewing the indicated template
|
||||
@@ -18,8 +19,8 @@ func TemplatePreview(ctx *context.Context) {
|
||||
ctx.Data["AppVer"] = setting.AppVer
|
||||
ctx.Data["AppUrl"] = setting.AppURL
|
||||
ctx.Data["Code"] = "2014031910370000009fff6782aadb2162b4a997acb69d4400888e0b9274657374"
|
||||
ctx.Data["ActiveCodeLives"] = base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ResetPwdCodeLives"] = base.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["CurDbValue"] = ""
|
||||
|
||||
ctx.HTML(200, base.TplName(ctx.Params("*")))
|
||||
|
||||
+11
-10
@@ -133,18 +133,19 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
|
||||
keyword := strings.Trim(ctx.Query("q"), " ")
|
||||
topicOnly := ctx.QueryBool("topic")
|
||||
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Page: page,
|
||||
PageSize: opts.PageSize,
|
||||
OrderBy: orderBy,
|
||||
Private: opts.Private,
|
||||
Keyword: keyword,
|
||||
OwnerID: opts.OwnerID,
|
||||
AllPublic: true,
|
||||
TopicOnly: topicOnly,
|
||||
repos, count, err = models.SearchRepository(&models.SearchRepoOptions{
|
||||
Page: page,
|
||||
PageSize: opts.PageSize,
|
||||
OrderBy: orderBy,
|
||||
Private: opts.Private,
|
||||
Keyword: keyword,
|
||||
OwnerID: opts.OwnerID,
|
||||
AllPublic: true,
|
||||
TopicOnly: topicOnly,
|
||||
IncludeDescription: setting.UI.SearchRepoDescription,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
ctx.ServerError("SearchRepository", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Keyword"] = keyword
|
||||
|
||||
+12
-14
@@ -16,13 +16,14 @@ import (
|
||||
"code.gitea.io/gitea/modules/highlight"
|
||||
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/mailer"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/markup/external"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/ssh"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
mirror_service "code.gitea.io/gitea/services/mirror"
|
||||
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
"gitea.com/macaron/macaron"
|
||||
)
|
||||
|
||||
func checkRunMode() {
|
||||
@@ -47,16 +48,16 @@ func NewServices() {
|
||||
// In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology
|
||||
func initDBEngine() (err error) {
|
||||
log.Info("Beginning ORM engine initialization.")
|
||||
for i := 0; i < setting.DBConnectRetries; i++ {
|
||||
log.Info("ORM engine initialization attempt #%d/%d...", i+1, setting.DBConnectRetries)
|
||||
for i := 0; i < setting.Database.DBConnectRetries; i++ {
|
||||
log.Info("ORM engine initialization attempt #%d/%d...", i+1, setting.Database.DBConnectRetries)
|
||||
if err = models.NewEngine(migrations.Migrate); err == nil {
|
||||
break
|
||||
} else if i == setting.DBConnectRetries-1 {
|
||||
} else if i == setting.Database.DBConnectRetries-1 {
|
||||
return err
|
||||
}
|
||||
log.Debug("ORM engine initialization attempt #%d/%d failed. Error: %v", i+1, setting.DBConnectRetries, err)
|
||||
log.Info("Backing off for %d seconds", int64(setting.DBConnectBackoff/time.Second))
|
||||
time.Sleep(setting.DBConnectBackoff)
|
||||
log.Error("ORM engine initialization attempt #%d/%d failed. Error: %v", i+1, setting.Database.DBConnectRetries, err)
|
||||
log.Info("Backing off for %d seconds", int64(setting.Database.DBConnectBackoff/time.Second))
|
||||
time.Sleep(setting.Database.DBConnectBackoff)
|
||||
}
|
||||
models.HasEngine = true
|
||||
return nil
|
||||
@@ -73,7 +74,7 @@ func GlobalInit() {
|
||||
log.Trace("AppWorkPath: %s", setting.AppWorkPath)
|
||||
log.Trace("Custom path: %s", setting.CustomPath)
|
||||
log.Trace("Log path: %s", setting.LogRootPath)
|
||||
models.LoadConfigs()
|
||||
|
||||
NewServices()
|
||||
|
||||
if setting.InstallLock {
|
||||
@@ -98,16 +99,13 @@ func GlobalInit() {
|
||||
log.Fatal("Failed to initialize issue indexer: %v", err)
|
||||
}
|
||||
models.InitRepoIndexer()
|
||||
models.InitSyncMirrors()
|
||||
mirror_service.InitSyncMirrors()
|
||||
models.InitDeliverHooks()
|
||||
models.InitTestPullRequests()
|
||||
}
|
||||
if models.EnableSQLite3 {
|
||||
if setting.EnableSQLite3 {
|
||||
log.Info("SQLite3 Supported")
|
||||
}
|
||||
if models.EnableTiDB {
|
||||
log.Info("TiDB Supported")
|
||||
}
|
||||
checkRunMode()
|
||||
|
||||
if setting.InstallLock && setting.SSH.StartBuiltinServer {
|
||||
|
||||
+32
-36
@@ -11,10 +11,6 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/go-xorm/xorm"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
@@ -23,6 +19,10 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/user"
|
||||
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/unknwon/com"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -40,11 +40,7 @@ func InstallInit(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("install.install")
|
||||
ctx.Data["PageIsInstall"] = true
|
||||
|
||||
dbOpts := []string{"MySQL", "PostgreSQL", "MSSQL"}
|
||||
if models.EnableSQLite3 {
|
||||
dbOpts = append(dbOpts, "SQLite3")
|
||||
}
|
||||
ctx.Data["DbOptions"] = dbOpts
|
||||
ctx.Data["DbOptions"] = setting.SupportedDatabases
|
||||
}
|
||||
|
||||
// Install render installation page
|
||||
@@ -52,21 +48,21 @@ func Install(ctx *context.Context) {
|
||||
form := auth.InstallForm{}
|
||||
|
||||
// Database settings
|
||||
form.DbHost = models.DbCfg.Host
|
||||
form.DbUser = models.DbCfg.User
|
||||
form.DbPasswd = models.DbCfg.Passwd
|
||||
form.DbName = models.DbCfg.Name
|
||||
form.DbPath = models.DbCfg.Path
|
||||
form.Charset = models.DbCfg.Charset
|
||||
form.DbHost = setting.Database.Host
|
||||
form.DbUser = setting.Database.User
|
||||
form.DbPasswd = setting.Database.Passwd
|
||||
form.DbName = setting.Database.Name
|
||||
form.DbPath = setting.Database.Path
|
||||
form.Charset = setting.Database.Charset
|
||||
|
||||
ctx.Data["CurDbOption"] = "MySQL"
|
||||
switch models.DbCfg.Type {
|
||||
switch setting.Database.Type {
|
||||
case "postgres":
|
||||
ctx.Data["CurDbOption"] = "PostgreSQL"
|
||||
case "mssql":
|
||||
ctx.Data["CurDbOption"] = "MSSQL"
|
||||
case "sqlite3":
|
||||
if models.EnableSQLite3 {
|
||||
if setting.EnableSQLite3 {
|
||||
ctx.Data["CurDbOption"] = "SQLite3"
|
||||
}
|
||||
}
|
||||
@@ -144,18 +140,18 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
|
||||
// Pass basic check, now test configuration.
|
||||
// Test database setting.
|
||||
dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "MSSQL": "mssql", "SQLite3": "sqlite3"}
|
||||
models.DbCfg.Type = dbTypes[form.DbType]
|
||||
models.DbCfg.Host = form.DbHost
|
||||
models.DbCfg.User = form.DbUser
|
||||
models.DbCfg.Passwd = form.DbPasswd
|
||||
models.DbCfg.Name = form.DbName
|
||||
models.DbCfg.SSLMode = form.SSLMode
|
||||
models.DbCfg.Charset = form.Charset
|
||||
models.DbCfg.Path = form.DbPath
|
||||
|
||||
if (models.DbCfg.Type == "sqlite3") &&
|
||||
len(models.DbCfg.Path) == 0 {
|
||||
setting.Database.Type = setting.GetDBTypeByName(form.DbType)
|
||||
setting.Database.Host = form.DbHost
|
||||
setting.Database.User = form.DbUser
|
||||
setting.Database.Passwd = form.DbPasswd
|
||||
setting.Database.Name = form.DbName
|
||||
setting.Database.SSLMode = form.SSLMode
|
||||
setting.Database.Charset = form.Charset
|
||||
setting.Database.Path = form.DbPath
|
||||
|
||||
if (setting.Database.Type == "sqlite3") &&
|
||||
len(setting.Database.Path) == 0 {
|
||||
ctx.Data["Err_DbPath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("install.err_empty_db_path"), tplInstall, &form)
|
||||
return
|
||||
@@ -265,14 +261,14 @@ func InstallPost(ctx *context.Context, form auth.InstallForm) {
|
||||
log.Error("Failed to load custom conf '%s': %v", setting.CustomConf, err)
|
||||
}
|
||||
}
|
||||
cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type)
|
||||
cfg.Section("database").Key("HOST").SetValue(models.DbCfg.Host)
|
||||
cfg.Section("database").Key("NAME").SetValue(models.DbCfg.Name)
|
||||
cfg.Section("database").Key("USER").SetValue(models.DbCfg.User)
|
||||
cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Passwd)
|
||||
cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SSLMode)
|
||||
cfg.Section("database").Key("CHARSET").SetValue(models.DbCfg.Charset)
|
||||
cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path)
|
||||
cfg.Section("database").Key("DB_TYPE").SetValue(setting.Database.Type)
|
||||
cfg.Section("database").Key("HOST").SetValue(setting.Database.Host)
|
||||
cfg.Section("database").Key("NAME").SetValue(setting.Database.Name)
|
||||
cfg.Section("database").Key("USER").SetValue(setting.Database.User)
|
||||
cfg.Section("database").Key("PASSWD").SetValue(setting.Database.Passwd)
|
||||
cfg.Section("database").Key("SSL_MODE").SetValue(setting.Database.SSLMode)
|
||||
cfg.Section("database").Key("CHARSET").SetValue(setting.Database.Charset)
|
||||
cfg.Section("database").Key("PATH").SetValue(setting.Database.Path)
|
||||
|
||||
cfg.Section("").Key("APP_NAME").SetValue(form.AppName)
|
||||
cfg.Section("repository").Key("ROOT").SetValue(form.RepoRootPath)
|
||||
|
||||
+2
-2
@@ -7,10 +7,10 @@ package routers
|
||||
import (
|
||||
"crypto/subtle"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
// Metrics validate auth token and render prometheus metrics
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
package org
|
||||
|
||||
import (
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -19,7 +19,7 @@ const (
|
||||
tplMembers base.TplName = "org/member/members"
|
||||
)
|
||||
|
||||
// Members render orgnization users page
|
||||
// Members render organization users page
|
||||
func Members(ctx *context.Context) {
|
||||
org := ctx.Org.Organization
|
||||
ctx.Data["Title"] = org.FullName
|
||||
@@ -30,11 +30,14 @@ func Members(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
ctx.Data["Members"] = org.Members
|
||||
ctx.Data["MembersIsPublicMember"] = org.MembersIsPublic
|
||||
ctx.Data["MembersIsUserOrgOwner"] = org.Members.IsUserOrgOwner(org.ID)
|
||||
ctx.Data["MembersTwoFaStatus"] = org.Members.GetTwoFaStatus()
|
||||
|
||||
ctx.HTML(200, tplMembers)
|
||||
}
|
||||
|
||||
// MembersAction response for operation to a member of orgnization
|
||||
// MembersAction response for operation to a member of organization
|
||||
func MembersAction(ctx *context.Context) {
|
||||
uid := com.StrTo(ctx.Query("uid")).MustInt64()
|
||||
if uid == 0 {
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
userSetting "code.gitea.io/gitea/routers/user/setting"
|
||||
)
|
||||
|
||||
@@ -31,7 +30,8 @@ const (
|
||||
func Settings(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("org.settings")
|
||||
ctx.Data["PageIsSettingsOptions"] = true
|
||||
ctx.Data["CurrentVisibility"] = structs.VisibleType(ctx.Org.Organization.Visibility)
|
||||
ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility
|
||||
ctx.Data["RepoAdminChangeTeamAccess"] = ctx.Org.Organization.RepoAdminChangeTeamAccess
|
||||
ctx.HTML(200, tplSettingsOptions)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func Settings(ctx *context.Context) {
|
||||
func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
|
||||
ctx.Data["Title"] = ctx.Tr("org.settings")
|
||||
ctx.Data["PageIsSettingsOptions"] = true
|
||||
ctx.Data["CurrentVisibility"] = structs.VisibleType(ctx.Org.Organization.Visibility)
|
||||
ctx.Data["CurrentVisibility"] = ctx.Org.Organization.Visibility
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.HTML(200, tplSettingsOptions)
|
||||
@@ -84,6 +84,7 @@ func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
|
||||
org.Website = form.Website
|
||||
org.Location = form.Location
|
||||
org.Visibility = form.Visibility
|
||||
org.RepoAdminChangeTeamAccess = form.RepoAdminChangeTeamAccess
|
||||
if err := models.UpdateUser(org); err != nil {
|
||||
ctx.ServerError("UpdateUser", err)
|
||||
return
|
||||
|
||||
@@ -10,14 +10,14 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/routers/utils"
|
||||
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
+15
-6
@@ -18,7 +18,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/repofiles"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
"gitea.com/macaron/macaron"
|
||||
)
|
||||
|
||||
// HookPreReceive checks whether a individual commit is acceptable
|
||||
@@ -31,6 +31,7 @@ func HookPreReceive(ctx *macaron.Context) {
|
||||
userID := ctx.QueryInt64("userID")
|
||||
gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory")
|
||||
gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories")
|
||||
gitQuarantinePath := ctx.QueryTrim("gitQuarantinePath")
|
||||
prID := ctx.QueryInt64("prID")
|
||||
|
||||
branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
|
||||
@@ -63,11 +64,19 @@ func HookPreReceive(ctx *macaron.Context) {
|
||||
|
||||
// detect force push
|
||||
if git.EmptySHA != oldCommitID {
|
||||
env := append(os.Environ(),
|
||||
private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories,
|
||||
private.GitObjectDirectory+"="+gitObjectDirectory,
|
||||
private.GitQuarantinePath+"="+gitObjectDirectory,
|
||||
)
|
||||
env := os.Environ()
|
||||
if gitAlternativeObjectDirectories != "" {
|
||||
env = append(env,
|
||||
private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories)
|
||||
}
|
||||
if gitObjectDirectory != "" {
|
||||
env = append(env,
|
||||
private.GitObjectDirectory+"="+gitObjectDirectory)
|
||||
}
|
||||
if gitQuarantinePath != "" {
|
||||
env = append(env,
|
||||
private.GitQuarantinePath+"="+gitQuarantinePath)
|
||||
}
|
||||
|
||||
output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDirWithEnv(repo.RepoPath(), env)
|
||||
if err != nil {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
"gitea.com/macaron/macaron"
|
||||
)
|
||||
|
||||
// CheckInternalToken check internal token is set
|
||||
|
||||
@@ -7,9 +7,9 @@ package private
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
"gitea.com/macaron/macaron"
|
||||
)
|
||||
|
||||
// UpdatePublicKeyInRepo update public key and deploy key updates
|
||||
@@ -34,7 +34,7 @@ func UpdatePublicKeyInRepo(ctx *macaron.Context) {
|
||||
})
|
||||
return
|
||||
}
|
||||
deployKey.UpdatedUnix = util.TimeStampNow()
|
||||
deployKey.UpdatedUnix = timeutil.TimeStampNow()
|
||||
if err = models.UpdateDeployKeyCols(deployKey, "updated_unix"); err != nil {
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
"err": err.Error(),
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/repofiles"
|
||||
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
"gitea.com/macaron/macaron"
|
||||
)
|
||||
|
||||
// PushUpdate update public key updates
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
"gitea.com/macaron/macaron"
|
||||
)
|
||||
|
||||
// ServNoCommand returns information about the provided keyid
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
@@ -22,7 +21,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -212,7 +211,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
|
||||
if index == 0 {
|
||||
// User avatar image
|
||||
avatar := ""
|
||||
commitSince := base.TimeSinceUnix(util.TimeStamp(commit.Author.When.Unix()), ctx.Data["Lang"].(string))
|
||||
commitSince := timeutil.TimeSinceUnix(timeutil.TimeStamp(commit.Author.When.Unix()), ctx.Data["Lang"].(string))
|
||||
if commit.User != nil {
|
||||
authorName := commit.Author.Name
|
||||
if len(commit.User.FullName) > 0 {
|
||||
|
||||
+13
-4
@@ -39,6 +39,7 @@ func Branches(ctx *context.Context) {
|
||||
ctx.Data["Title"] = "Branches"
|
||||
ctx.Data["IsRepoToolbarBranches"] = true
|
||||
ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
|
||||
ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls()
|
||||
ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode)
|
||||
ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
|
||||
ctx.Data["PageIsViewCode"] = true
|
||||
@@ -161,6 +162,12 @@ func loadBranches(ctx *context.Context) []*Branch {
|
||||
return nil
|
||||
}
|
||||
|
||||
protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetProtectedBranches", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
branches := make([]*Branch, len(rawBranches))
|
||||
for i := range rawBranches {
|
||||
commit, err := rawBranches[i].GetCommit()
|
||||
@@ -169,11 +176,13 @@ func loadBranches(ctx *context.Context) []*Branch {
|
||||
return nil
|
||||
}
|
||||
|
||||
var isProtected bool
|
||||
branchName := rawBranches[i].Name
|
||||
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User)
|
||||
if err != nil {
|
||||
ctx.ServerError("IsProtectedBranch", err)
|
||||
return nil
|
||||
for _, b := range protectedBranches {
|
||||
if b.BranchName == branchName {
|
||||
isProtected = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
divergence, divergenceError := repofiles.CountDivergingCommits(ctx.Repo.Repository, branchName)
|
||||
|
||||
+18
-11
@@ -11,11 +11,12 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -217,7 +218,7 @@ func Diff(ctx *context.Context) {
|
||||
|
||||
ctx.Data["CommitStatus"] = models.CalcCommitStatus(statuses)
|
||||
|
||||
diff, err := models.GetDiffCommit(models.RepoPath(userName, repoName),
|
||||
diff, err := gitdiff.GetDiffCommit(models.RepoPath(userName, repoName),
|
||||
commitID, setting.Git.MaxGitDiffLines,
|
||||
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
|
||||
if err != nil {
|
||||
@@ -238,7 +239,18 @@ func Diff(ctx *context.Context) {
|
||||
ctx.Data["CommitID"] = commitID
|
||||
ctx.Data["Username"] = userName
|
||||
ctx.Data["Reponame"] = repoName
|
||||
ctx.Data["IsImageFile"] = commit.IsImageFile
|
||||
|
||||
var parentCommit *git.Commit
|
||||
if commit.ParentCount() > 0 {
|
||||
parentCommit, err = ctx.Repo.GitRepo.GetCommit(parents[0])
|
||||
if err != nil {
|
||||
ctx.NotFound("GetParentCommit", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
setImageCompareContext(ctx, parentCommit, commit)
|
||||
headTarget := path.Join(userName, repoName)
|
||||
setPathsCompareContext(ctx, parentCommit, commit, headTarget)
|
||||
ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID)
|
||||
ctx.Data["Commit"] = commit
|
||||
ctx.Data["Verification"] = models.ParseCommitWithSignature(commit)
|
||||
@@ -246,20 +258,15 @@ func Diff(ctx *context.Context) {
|
||||
ctx.Data["Diff"] = diff
|
||||
ctx.Data["Parents"] = parents
|
||||
ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
||||
ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", commitID)
|
||||
|
||||
note := &git.Note{}
|
||||
err = git.GetNote(ctx.Repo.GitRepo, commitID, note)
|
||||
if err == nil {
|
||||
ctx.Data["Note"] = string(templates.ToUTF8WithFallback(note.Message))
|
||||
ctx.Data["Note"] = string(charset.ToUTF8WithFallback(note.Message))
|
||||
ctx.Data["NoteCommit"] = note.Commit
|
||||
ctx.Data["NoteAuthor"] = models.ValidateCommitWithEmail(note.Commit)
|
||||
}
|
||||
|
||||
if commit.ParentCount() > 0 {
|
||||
ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", "commit", parents[0])
|
||||
}
|
||||
ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", "commit", commitID)
|
||||
ctx.Data["BranchName"], err = commit.GetBranchName()
|
||||
if err != nil {
|
||||
ctx.ServerError("commit.GetBranchName", err)
|
||||
@@ -269,10 +276,10 @@ func Diff(ctx *context.Context) {
|
||||
|
||||
// RawDiff dumps diff results of repository in given commit ID to io.Writer
|
||||
func RawDiff(ctx *context.Context) {
|
||||
if err := models.GetRawDiff(
|
||||
if err := gitdiff.GetRawDiff(
|
||||
models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name),
|
||||
ctx.Params(":sha"),
|
||||
models.RawDiffType(ctx.Params(":ext")),
|
||||
gitdiff.RawDiffType(ctx.Params(":ext")),
|
||||
ctx.Resp,
|
||||
); err != nil {
|
||||
ctx.ServerError("GetRawDiff", err)
|
||||
|
||||
+72
-12
@@ -5,6 +5,7 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
@@ -14,12 +15,52 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
)
|
||||
|
||||
const (
|
||||
tplCompare base.TplName = "repo/diff/compare"
|
||||
)
|
||||
|
||||
// setPathsCompareContext sets context data for source and raw paths
|
||||
func setPathsCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit, headTarget string) {
|
||||
sourcePath := setting.AppSubURL + "/%s/src/commit/%s"
|
||||
rawPath := setting.AppSubURL + "/%s/raw/commit/%s"
|
||||
|
||||
ctx.Data["SourcePath"] = fmt.Sprintf(sourcePath, headTarget, head.ID)
|
||||
ctx.Data["RawPath"] = fmt.Sprintf(rawPath, headTarget, head.ID)
|
||||
if base != nil {
|
||||
baseTarget := path.Join(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
|
||||
ctx.Data["BeforeSourcePath"] = fmt.Sprintf(sourcePath, baseTarget, base.ID)
|
||||
ctx.Data["BeforeRawPath"] = fmt.Sprintf(rawPath, baseTarget, base.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// setImageCompareContext sets context data that is required by image compare template
|
||||
func setImageCompareContext(ctx *context.Context, base *git.Commit, head *git.Commit) {
|
||||
ctx.Data["IsImageFileInHead"] = head.IsImageFile
|
||||
ctx.Data["IsImageFileInBase"] = base.IsImageFile
|
||||
ctx.Data["ImageInfoBase"] = func(name string) *git.ImageMetaData {
|
||||
if base == nil {
|
||||
return nil
|
||||
}
|
||||
result, err := base.ImageInfo(name)
|
||||
if err != nil {
|
||||
log.Error("ImageInfo failed: %v", err)
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
ctx.Data["ImageInfo"] = func(name string) *git.ImageMetaData {
|
||||
result, err := head.ImageInfo(name)
|
||||
if err != nil {
|
||||
log.Error("ImageInfo failed: %v", err)
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// ParseCompareInfo parse compare info between two commit for preparing comparing references
|
||||
func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *git.Repository, *git.CompareInfo, string, string) {
|
||||
baseRepo := ctx.Repo.Repository
|
||||
@@ -230,7 +271,7 @@ func PrepareCompareDiff(
|
||||
return true
|
||||
}
|
||||
|
||||
diff, err := models.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name),
|
||||
diff, err := gitdiff.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name),
|
||||
compareInfo.MergeBase, headCommitID, setting.Git.MaxGitDiffLines,
|
||||
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles)
|
||||
if err != nil {
|
||||
@@ -246,6 +287,26 @@ func PrepareCompareDiff(
|
||||
return false
|
||||
}
|
||||
|
||||
baseGitRepo := ctx.Repo.GitRepo
|
||||
baseCommitID := baseBranch
|
||||
if ctx.Data["BaseIsCommit"] == false {
|
||||
if ctx.Data["BaseIsTag"] == true {
|
||||
baseCommitID, err = baseGitRepo.GetTagCommitID(baseBranch)
|
||||
} else {
|
||||
baseCommitID, err = baseGitRepo.GetBranchCommitID(baseBranch)
|
||||
}
|
||||
if err != nil {
|
||||
ctx.ServerError("GetRefCommitID", err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
baseCommit, err := baseGitRepo.GetCommit(baseCommitID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommit", err)
|
||||
return false
|
||||
}
|
||||
|
||||
compareInfo.Commits = models.ValidateCommitsWithEmails(compareInfo.Commits)
|
||||
compareInfo.Commits = models.ParseCommitsWithSignature(compareInfo.Commits)
|
||||
compareInfo.Commits = models.ParseCommitsWithStatus(compareInfo.Commits, headRepo)
|
||||
@@ -270,12 +331,11 @@ func PrepareCompareDiff(
|
||||
ctx.Data["title"] = title
|
||||
ctx.Data["Username"] = headUser.Name
|
||||
ctx.Data["Reponame"] = headRepo.Name
|
||||
ctx.Data["IsImageFile"] = headCommit.IsImageFile
|
||||
|
||||
setImageCompareContext(ctx, baseCommit, headCommit)
|
||||
headTarget := path.Join(headUser.Name, repo.Name)
|
||||
ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", headCommitID)
|
||||
ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", compareInfo.MergeBase)
|
||||
ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", "commit", headCommitID)
|
||||
setPathsCompareContext(ctx, baseCommit, headCommit, headTarget)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -292,6 +352,13 @@ func CompareDiff(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsComparePull"] == true {
|
||||
headBranches, err := headGitRepo.GetBranches()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranches", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["HeadBranches"] = headBranches
|
||||
|
||||
pr, err := models.GetUnmergedPullRequest(headRepo.ID, ctx.Repo.Repository.ID, headBranch, baseBranch)
|
||||
if err != nil {
|
||||
if !models.IsErrPullRequestNotExist(err) {
|
||||
@@ -312,13 +379,6 @@ func CompareDiff(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
headBranches, err := headGitRepo.GetBranches()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetBranches", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["HeadBranches"] = headBranches
|
||||
}
|
||||
beforeCommitID := ctx.Data["BeforeCommitID"].(string)
|
||||
afterCommitID := ctx.Data["AfterCommitID"].(string)
|
||||
|
||||
+82
-17
@@ -8,17 +8,18 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/repofiles"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/upload"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
@@ -117,7 +118,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
|
||||
|
||||
d, _ := ioutil.ReadAll(dataRc)
|
||||
buf = append(buf, d...)
|
||||
if content, err := templates.ToUTF8WithErr(buf); err != nil {
|
||||
if content, err := charset.ToUTF8WithErr(buf); err != nil {
|
||||
log.Error("ToUTF8WithErr: %v", err)
|
||||
ctx.Data["FileContent"] = string(buf)
|
||||
} else {
|
||||
@@ -137,7 +138,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
|
||||
} else {
|
||||
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
|
||||
}
|
||||
ctx.Data["new_branch_name"] = ""
|
||||
ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
|
||||
ctx.Data["last_commit"] = ctx.Repo.CommitID
|
||||
ctx.Data["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",")
|
||||
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
|
||||
@@ -266,6 +267,10 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
||||
} else {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.fail_to_update_file", form.TreePath, err), tplEditFile, &form)
|
||||
}
|
||||
}
|
||||
|
||||
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
|
||||
} else {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
|
||||
}
|
||||
@@ -335,7 +340,7 @@ func DeleteFile(ctx *context.Context) {
|
||||
} else {
|
||||
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
|
||||
}
|
||||
ctx.Data["new_branch_name"] = ""
|
||||
ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
|
||||
|
||||
ctx.HTML(200, tplDeleteFile)
|
||||
}
|
||||
@@ -362,7 +367,7 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
||||
return
|
||||
}
|
||||
|
||||
if branchName != ctx.Repo.BranchName && !canCommit {
|
||||
if branchName == ctx.Repo.BranchName && !canCommit {
|
||||
ctx.Data["Err_NewBranchName"] = true
|
||||
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.cannot_commit_to_protected_branch", branchName), tplDeleteFile, &form)
|
||||
@@ -387,20 +392,20 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
||||
}); err != nil {
|
||||
// This is where we handle all the errors thrown by repofiles.DeleteRepoFile
|
||||
if git.IsErrNotExist(err) || models.IsErrRepoFileDoesNotExist(err) {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_deleting_no_longer_exists", ctx.Repo.TreePath), tplEditFile, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_deleting_no_longer_exists", ctx.Repo.TreePath), tplDeleteFile, &form)
|
||||
} else if models.IsErrFilenameInvalid(err) {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", ctx.Repo.TreePath), tplEditFile, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", ctx.Repo.TreePath), tplDeleteFile, &form)
|
||||
} else if models.IsErrFilePathInvalid(err) {
|
||||
ctx.Data["Err_TreePath"] = true
|
||||
if fileErr, ok := err.(models.ErrFilePathInvalid); ok {
|
||||
switch fileErr.Type {
|
||||
case git.EntryModeSymlink:
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplEditFile, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplDeleteFile, &form)
|
||||
case git.EntryModeTree:
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplEditFile, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplDeleteFile, &form)
|
||||
case git.EntryModeBlob:
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplEditFile, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplDeleteFile, &form)
|
||||
default:
|
||||
ctx.ServerError("DeleteRepoFile", err)
|
||||
}
|
||||
@@ -410,25 +415,44 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
||||
} else if git.IsErrBranchNotExist(err) {
|
||||
// For when a user deletes a file to a branch that no longer exists
|
||||
if branchErr, ok := err.(git.ErrBranchNotExist); ok {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name), tplEditFile, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name), tplDeleteFile, &form)
|
||||
} else {
|
||||
ctx.Error(500, err.Error())
|
||||
}
|
||||
} else if models.IsErrBranchAlreadyExists(err) {
|
||||
// For when a user specifies a new branch that already exists
|
||||
if branchErr, ok := err.(models.ErrBranchAlreadyExists); ok {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplEditFile, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplDeleteFile, &form)
|
||||
} else {
|
||||
ctx.Error(500, err.Error())
|
||||
}
|
||||
} else if models.IsErrCommitIDDoesNotMatch(err) {
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplEditFile, &form)
|
||||
ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_deleting", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplDeleteFile, &form)
|
||||
} else {
|
||||
ctx.ServerError("DeleteRepoFile", err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
|
||||
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName))
|
||||
treePath := filepath.Dir(ctx.Repo.TreePath)
|
||||
if treePath == "." {
|
||||
treePath = "" // the file deleted was in the root, so we return the user to the root directory
|
||||
}
|
||||
if len(treePath) > 0 {
|
||||
// Need to get the latest commit since it changed
|
||||
commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.BranchName)
|
||||
if err == nil && commit != nil {
|
||||
// We have the comment, now find what directory we can return the user to
|
||||
// (must have entries)
|
||||
treePath = GetClosestParentWithFiles(treePath, commit)
|
||||
} else {
|
||||
treePath = "" // otherwise return them to the root of the repo
|
||||
}
|
||||
}
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(treePath))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,7 +491,7 @@ func UploadFile(ctx *context.Context) {
|
||||
} else {
|
||||
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
|
||||
}
|
||||
ctx.Data["new_branch_name"] = ""
|
||||
ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
|
||||
|
||||
ctx.HTML(200, tplUploadFile)
|
||||
}
|
||||
@@ -565,7 +589,11 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
|
||||
if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
|
||||
} else {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
|
||||
}
|
||||
}
|
||||
|
||||
func cleanUploadFileName(name string) string {
|
||||
@@ -636,3 +664,40 @@ func RemoveUploadFileFromServer(ctx *context.Context, form auth.RemoveUploadFile
|
||||
log.Trace("Upload file removed: %s", form.File)
|
||||
ctx.Status(204)
|
||||
}
|
||||
|
||||
// GetUniquePatchBranchName Gets a unique branch name for a new patch branch
|
||||
// It will be in the form of <username>-patch-<num> where <num> is the first branch of this format
|
||||
// that doesn't already exist. If we exceed 1000 tries or an error is thrown, we just return "" so the user has to
|
||||
// type in the branch name themselves (will be an empty field)
|
||||
func GetUniquePatchBranchName(ctx *context.Context) string {
|
||||
prefix := ctx.User.LowerName + "-patch-"
|
||||
for i := 1; i <= 1000; i++ {
|
||||
branchName := fmt.Sprintf("%s%d", prefix, i)
|
||||
if _, err := ctx.Repo.Repository.GetBranch(branchName); err != nil {
|
||||
if git.IsErrBranchNotExist(err) {
|
||||
return branchName
|
||||
}
|
||||
log.Error("GetUniquePatchBranchName: %v", err)
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetClosestParentWithFiles Recursively gets the path of parent in a tree that has files (used when file in a tree is
|
||||
// deleted). Returns "" for the root if no parents other than the root have files. If the given treePath isn't a
|
||||
// SubTree or it has no entries, we go up one dir and see if we can return the user to that listing.
|
||||
func GetClosestParentWithFiles(treePath string, commit *git.Commit) string {
|
||||
if len(treePath) == 0 || treePath == "." {
|
||||
return ""
|
||||
}
|
||||
// see if the tree has entries
|
||||
if tree, err := commit.SubTree(treePath); err != nil {
|
||||
// failed to get tree, going up a dir
|
||||
return GetClosestParentWithFiles(filepath.Dir(treePath), commit)
|
||||
} else if entries, err := tree.ListEntries(); err != nil || len(entries) == 0 {
|
||||
// no files in this dir, going up a dir
|
||||
return GetClosestParentWithFiles(filepath.Dir(treePath), commit)
|
||||
}
|
||||
return treePath
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -37,3 +39,40 @@ func TestCleanUploadName(t *testing.T) {
|
||||
assert.EqualValues(t, cleanUploadFileName(k), v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetUniquePatchBranchName(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
test.LoadRepo(t, ctx, 1)
|
||||
test.LoadRepoCommit(t, ctx)
|
||||
test.LoadUser(t, ctx, 2)
|
||||
test.LoadGitRepo(t, ctx)
|
||||
expectedBranchName := "user2-patch-1"
|
||||
branchName := GetUniquePatchBranchName(ctx)
|
||||
assert.Equal(t, expectedBranchName, branchName)
|
||||
}
|
||||
|
||||
func TestGetClosestParentWithFiles(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "user2/repo1")
|
||||
ctx.SetParams(":id", "1")
|
||||
test.LoadRepo(t, ctx, 1)
|
||||
test.LoadRepoCommit(t, ctx)
|
||||
test.LoadUser(t, ctx, 2)
|
||||
test.LoadGitRepo(t, ctx)
|
||||
repo := ctx.Repo.Repository
|
||||
branch := repo.DefaultBranch
|
||||
gitRepo, _ := git.OpenRepository(repo.RepoPath())
|
||||
commit, _ := gitRepo.GetBranchCommit(branch)
|
||||
expectedTreePath := ""
|
||||
|
||||
expectedTreePath = "" // Should return the root dir, empty string, since there are no subdirs in this repo
|
||||
for _, deletedFile := range []string{
|
||||
"dir1/dir2/dir3/file.txt",
|
||||
"file.txt",
|
||||
} {
|
||||
treePath := GetClosestParentWithFiles(deletedFile, commit)
|
||||
assert.Equal(t, expectedTreePath, treePath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
)
|
||||
|
||||
// HTTP implmentation git smart HTTP protocol
|
||||
@@ -203,7 +203,7 @@ func HTTP(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
token.UpdatedUnix = util.TimeStampNow()
|
||||
token.UpdatedUnix = timeutil.TimeStampNow()
|
||||
if err = models.UpdateAccessToken(token); err != nil {
|
||||
ctx.ServerError("UpdateAccessToken", err)
|
||||
}
|
||||
@@ -215,7 +215,10 @@ func HTTP(ctx *context.Context) {
|
||||
// Check username and password
|
||||
authUser, err = models.UserSignIn(authUsername, authPasswd)
|
||||
if err != nil {
|
||||
if !models.IsErrUserNotExist(err) {
|
||||
if models.IsErrUserProhibitLogin(err) {
|
||||
ctx.HandleText(http.StatusForbidden, "User is not permitted to login")
|
||||
return
|
||||
} else if !models.IsErrUserNotExist(err) {
|
||||
ctx.ServerError("UserSignIn error: %v", err)
|
||||
return
|
||||
}
|
||||
@@ -424,7 +427,7 @@ func serviceRPC(h serviceHandler, service string) {
|
||||
cmd.Stdin = reqBody
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Error("Fail to serve RPC(%s): %v - %v", service, err, stderr)
|
||||
log.Error("Fail to serve RPC(%s): %v - %s", service, err, stderr.String())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
+55
-20
@@ -26,8 +26,11 @@ import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
comment_service "code.gitea.io/gitea/services/comments"
|
||||
issue_service "code.gitea.io/gitea/services/issue"
|
||||
milestone_service "code.gitea.io/gitea/services/milestone"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -569,7 +572,7 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
|
||||
Content: form.Content,
|
||||
Ref: form.Ref,
|
||||
}
|
||||
if err := models.NewIssue(repo, issue, labelIDs, assigneeIDs, attachments); err != nil {
|
||||
if err := issue_service.NewIssue(repo, issue, labelIDs, assigneeIDs, attachments); err != nil {
|
||||
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
|
||||
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error())
|
||||
return
|
||||
@@ -642,9 +645,13 @@ func ViewIssue(ctx *context.Context) {
|
||||
ctx.Data["RequireTribute"] = true
|
||||
renderAttachmentSettings(ctx)
|
||||
|
||||
err = issue.LoadAttributes()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetIssueByIndex", err)
|
||||
if err = issue.LoadAttributes(); err != nil {
|
||||
ctx.ServerError("LoadAttributes", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = filterXRefComments(ctx, issue); err != nil {
|
||||
ctx.ServerError("filterXRefComments", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -803,17 +810,7 @@ func ViewIssue(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
marked[comment.PosterID] = comment.ShowTag
|
||||
|
||||
isAdded := false
|
||||
for j := range participants {
|
||||
if comment.Poster == participants[j] {
|
||||
isAdded = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !isAdded && !issue.IsPoster(comment.Poster.ID) {
|
||||
participants = append(participants, comment.Poster)
|
||||
}
|
||||
participants = addParticipant(comment.Poster, participants)
|
||||
} else if comment.Type == models.CommentTypeLabel {
|
||||
if err = comment.LoadLabel(); err != nil {
|
||||
ctx.ServerError("LoadLabel", err)
|
||||
@@ -849,6 +846,7 @@ func ViewIssue(ctx *context.Context) {
|
||||
ctx.ServerError("LoadReview", err)
|
||||
return
|
||||
}
|
||||
participants = addParticipant(comment.Poster, participants)
|
||||
if comment.Review == nil {
|
||||
continue
|
||||
}
|
||||
@@ -1045,11 +1043,14 @@ func UpdateIssueTitle(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
oldTitle := issue.Title
|
||||
if err := issue.ChangeTitle(ctx.User, title); err != nil {
|
||||
ctx.ServerError("ChangeTitle", err)
|
||||
return
|
||||
}
|
||||
|
||||
notification.NotifyIssueChangeTitle(ctx.User, issue, oldTitle)
|
||||
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"title": issue.Title,
|
||||
})
|
||||
@@ -1092,7 +1093,7 @@ func UpdateIssueMilestone(ctx *context.Context) {
|
||||
continue
|
||||
}
|
||||
issue.MilestoneID = milestoneID
|
||||
if err := models.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil {
|
||||
if err := milestone_service.ChangeMilestoneAssign(issue, ctx.User, oldMilestoneID); err != nil {
|
||||
ctx.ServerError("ChangeMilestoneAssign", err)
|
||||
return
|
||||
}
|
||||
@@ -1300,7 +1301,7 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
|
||||
return
|
||||
}
|
||||
|
||||
comment, err := models.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Content, attachments)
|
||||
comment, err := comment_service.CreateIssueComment(ctx.User, ctx.Repo.Repository, issue, form.Content, attachments)
|
||||
if err != nil {
|
||||
ctx.ServerError("CreateIssueComment", err)
|
||||
return
|
||||
@@ -1340,7 +1341,7 @@ func UpdateCommentContent(ctx *context.Context) {
|
||||
})
|
||||
return
|
||||
}
|
||||
if err = models.UpdateComment(ctx.User, comment, oldContent); err != nil {
|
||||
if err = comment_service.UpdateComment(comment, ctx.User, oldContent); err != nil {
|
||||
ctx.ServerError("UpdateComment", err)
|
||||
return
|
||||
}
|
||||
@@ -1373,7 +1374,7 @@ func DeleteComment(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = models.DeleteComment(ctx.User, comment); err != nil {
|
||||
if err = models.DeleteComment(comment, ctx.User); err != nil {
|
||||
ctx.ServerError("DeleteCommentByID", err)
|
||||
return
|
||||
}
|
||||
@@ -1568,3 +1569,37 @@ func ChangeCommentReaction(ctx *context.Context, form auth.ReactionForm) {
|
||||
"html": html,
|
||||
})
|
||||
}
|
||||
|
||||
func addParticipant(poster *models.User, participants []*models.User) []*models.User {
|
||||
for _, part := range participants {
|
||||
if poster.ID == part.ID {
|
||||
return participants
|
||||
}
|
||||
}
|
||||
return append(participants, poster)
|
||||
}
|
||||
|
||||
func filterXRefComments(ctx *context.Context, issue *models.Issue) error {
|
||||
// Remove comments that the user has no permissions to see
|
||||
for i := 0; i < len(issue.Comments); {
|
||||
c := issue.Comments[i]
|
||||
if models.CommentTypeIsRef(c.Type) && c.RefRepoID != issue.RepoID && c.RefRepoID != 0 {
|
||||
var err error
|
||||
// Set RefRepo for description in template
|
||||
c.RefRepo, err = models.GetRepositoryByID(c.RefRepoID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
perm, err := models.GetUserRepoPermission(c.RefRepo, ctx.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !perm.CanReadIssuesOrPulls(c.RefIsPull) {
|
||||
issue.Comments = append(issue.Comments[:i], issue.Comments[i+1:]...)
|
||||
continue
|
||||
}
|
||||
}
|
||||
i++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -33,24 +33,15 @@ func InitializeLabels(ctx *context.Context, form auth.InitializeLabelsForm) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||
return
|
||||
}
|
||||
list, err := models.GetLabelTemplateFile(form.TemplateName)
|
||||
if err != nil {
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, err))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||
return
|
||||
}
|
||||
|
||||
labels := make([]*models.Label, len(list))
|
||||
for i := 0; i < len(list); i++ {
|
||||
labels[i] = &models.Label{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: list[i][0],
|
||||
Description: list[i][2],
|
||||
Color: list[i][1],
|
||||
if err := models.InitalizeLabels(ctx.Repo.Repository.ID, form.TemplateName); err != nil {
|
||||
if models.IsErrIssueLabelTemplateLoad(err) {
|
||||
originalErr := err.(models.ErrIssueLabelTemplateLoad).OriginalError
|
||||
ctx.Flash.Error(ctx.Tr("repo.issues.label_templates.fail_to_load_file", form.TemplateName, originalErr))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := models.NewLabels(labels...); err != nil {
|
||||
ctx.ServerError("NewLabels", err)
|
||||
ctx.ServerError("InitalizeLabels", err)
|
||||
return
|
||||
}
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/labels")
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/markup/markdown"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
@@ -120,7 +121,7 @@ func NewMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: form.Title,
|
||||
Content: form.Content,
|
||||
DeadlineUnix: util.TimeStamp(deadline.Unix()),
|
||||
DeadlineUnix: timeutil.TimeStamp(deadline.Unix()),
|
||||
}); err != nil {
|
||||
ctx.ServerError("NewMilestone", err)
|
||||
return
|
||||
@@ -190,7 +191,7 @@ func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
|
||||
}
|
||||
m.Name = form.Title
|
||||
m.Content = form.Content
|
||||
m.DeadlineUnix = util.TimeStamp(deadline.Unix())
|
||||
m.DeadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
||||
if err = models.UpdateMilestone(m); err != nil {
|
||||
ctx.ServerError("UpdateMilestone", err)
|
||||
return
|
||||
@@ -223,7 +224,7 @@ func ChangeMilestonStatus(ctx *context.Context) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/milestones?state=open")
|
||||
case "close":
|
||||
if !m.IsClosed {
|
||||
m.ClosedDateUnix = util.TimeStampNow()
|
||||
m.ClosedDateUnix = timeutil.TimeStampNow()
|
||||
if err = models.ChangeMilestoneStatus(m, true); err != nil {
|
||||
ctx.ServerError("ChangeMilestoneStatus", err)
|
||||
return
|
||||
@@ -253,6 +254,11 @@ func MilestoneIssuesAndPulls(ctx *context.Context) {
|
||||
milestoneID := ctx.ParamsInt64(":id")
|
||||
milestone, err := models.GetMilestoneByID(milestoneID)
|
||||
if err != nil {
|
||||
if models.IsErrMilestoneNotExist(err) {
|
||||
ctx.NotFound("GetMilestoneByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.ServerError("GetMilestoneByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
+43
-16
@@ -21,11 +21,12 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/pull"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -321,6 +322,12 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
|
||||
|
||||
setMergeTarget(ctx, pull)
|
||||
|
||||
if err = pull.LoadProtectedBranch(); err != nil {
|
||||
ctx.ServerError("GetLatestCommitStatus", err)
|
||||
return nil
|
||||
}
|
||||
ctx.Data["EnableStatusCheck"] = pull.ProtectedBranch != nil && pull.ProtectedBranch.EnableStatusCheck
|
||||
|
||||
var headGitRepo *git.Repository
|
||||
var headBranchExist bool
|
||||
// HeadRepo may be missing
|
||||
@@ -349,6 +356,18 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
|
||||
ctx.Data["LatestCommitStatuses"] = commitStatuses
|
||||
ctx.Data["LatestCommitStatus"] = models.CalcCommitStatus(commitStatuses)
|
||||
}
|
||||
|
||||
if pull.ProtectedBranch != nil && pull.ProtectedBranch.EnableStatusCheck {
|
||||
ctx.Data["is_context_required"] = func(context string) bool {
|
||||
for _, c := range pull.ProtectedBranch.StatusCheckContexts {
|
||||
if c == context {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
ctx.Data["IsRequiredStatusCheckSuccess"] = pull_service.IsCommitStatusContextSuccess(commitStatuses, pull.ProtectedBranch.StatusCheckContexts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,7 +536,7 @@ func ViewPullFiles(ctx *context.Context) {
|
||||
ctx.Data["Reponame"] = pull.HeadRepo.Name
|
||||
}
|
||||
|
||||
diff, err := models.GetDiffRangeWithWhitespaceBehavior(diffRepoPath,
|
||||
diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(diffRepoPath,
|
||||
startCommitID, endCommitID, setting.Git.MaxGitDiffLines,
|
||||
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles,
|
||||
whitespaceFlags[ctx.Data["WhitespaceBehavior"].(string)])
|
||||
@@ -534,16 +553,20 @@ func ViewPullFiles(ctx *context.Context) {
|
||||
ctx.Data["Diff"] = diff
|
||||
ctx.Data["DiffNotAvailable"] = diff.NumFiles() == 0
|
||||
|
||||
baseCommit, err := ctx.Repo.GitRepo.GetCommit(startCommitID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommit", err)
|
||||
return
|
||||
}
|
||||
commit, err := gitRepo.GetCommit(endCommitID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommit", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["IsImageFile"] = commit.IsImageFile
|
||||
ctx.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", endCommitID)
|
||||
ctx.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", "commit", startCommitID)
|
||||
ctx.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", "commit", endCommitID)
|
||||
setImageCompareContext(ctx, baseCommit, commit)
|
||||
setPathsCompareContext(ctx, baseCommit, commit, headTarget)
|
||||
|
||||
ctx.Data["RequireHighlightJS"] = true
|
||||
ctx.Data["RequireTribute"] = true
|
||||
if ctx.Data["Assignees"], err = ctx.Repo.Repository.GetAssignees(); err != nil {
|
||||
@@ -582,6 +605,17 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) {
|
||||
return
|
||||
}
|
||||
|
||||
isPass, err := pull_service.IsPullCommitStatusPass(pr)
|
||||
if err != nil {
|
||||
ctx.ServerError("IsPullCommitStatusPass", err)
|
||||
return
|
||||
}
|
||||
if !isPass && !ctx.IsUserRepoAdmin() {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_status_check"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
ctx.Flash.Error(ctx.Data["ErrorMsg"].(string))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
||||
@@ -620,7 +654,7 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = pull.Merge(pr, ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil {
|
||||
if err = pull_service.Merge(pr, ctx.User, ctx.Repo.GitRepo, models.MergeStyle(form.Do), message); err != nil {
|
||||
if models.IsErrInvalidMergeStyle(err) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.pulls.invalid_merge_option"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
|
||||
@@ -710,15 +744,8 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
|
||||
return
|
||||
}
|
||||
|
||||
maxIndex, err := models.GetMaxIndexOfIssue(repo.ID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetPatch", err)
|
||||
return
|
||||
}
|
||||
|
||||
pullIssue := &models.Issue{
|
||||
RepoID: repo.ID,
|
||||
Index: maxIndex + 1,
|
||||
Title: form.Title,
|
||||
PosterID: ctx.User.ID,
|
||||
Poster: ctx.User,
|
||||
@@ -740,7 +767,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
|
||||
// FIXME: check error in the case two people send pull request at almost same time, give nice error prompt
|
||||
// instead of 500.
|
||||
|
||||
if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch, assigneeIDs); err != nil {
|
||||
if err := pull_service.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch, assigneeIDs); err != nil {
|
||||
if models.IsErrUserDoesNotHaveAccessToRepo(err) {
|
||||
ctx.Error(400, "UserDoesNotHaveAccessToRepo", err.Error())
|
||||
return
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
comment_service "code.gitea.io/gitea/services/comments"
|
||||
pull_service "code.gitea.io/gitea/services/pull"
|
||||
)
|
||||
|
||||
// CreateCodeComment will create a code comment including an pending review if required
|
||||
@@ -53,7 +55,7 @@ func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) {
|
||||
}
|
||||
// No pending review exists
|
||||
// Create a new pending review for this issue & user
|
||||
if review, err = models.CreateReview(models.CreateReviewOptions{
|
||||
if review, err = pull_service.CreateReview(models.CreateReviewOptions{
|
||||
Type: models.ReviewTypePending,
|
||||
Reviewer: ctx.User,
|
||||
Issue: issue,
|
||||
@@ -61,13 +63,14 @@ func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) {
|
||||
ctx.ServerError("CreateCodeComment", err)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if review.ID == 0 {
|
||||
review.ID = form.Reply
|
||||
}
|
||||
//FIXME check if line, commit and treepath exist
|
||||
comment, err := models.CreateCodeComment(
|
||||
comment, err := comment_service.CreateCodeComment(
|
||||
ctx.User,
|
||||
issue.Repo,
|
||||
issue,
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/markup/markdown"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
releaseservice "code.gitea.io/gitea/services/release"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -175,7 +176,7 @@ func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
|
||||
IsTag: false,
|
||||
}
|
||||
|
||||
if err = models.CreateRelease(ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
|
||||
if err = releaseservice.CreateRelease(ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
|
||||
ctx.Data["Err_TagName"] = true
|
||||
switch {
|
||||
case models.IsErrReleaseAlreadyExist(err):
|
||||
@@ -202,7 +203,7 @@ func NewReleasePost(ctx *context.Context, form auth.NewReleaseForm) {
|
||||
rel.PublisherID = ctx.User.ID
|
||||
rel.IsTag = false
|
||||
|
||||
if err = models.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
|
||||
if err = releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
|
||||
ctx.Data["Err_TagName"] = true
|
||||
ctx.ServerError("UpdateRelease", err)
|
||||
return
|
||||
@@ -281,7 +282,7 @@ func EditReleasePost(ctx *context.Context, form auth.EditReleaseForm) {
|
||||
rel.Note = form.Content
|
||||
rel.IsDraft = len(form.Draft) > 0
|
||||
rel.IsPrerelease = form.Prerelease
|
||||
if err = models.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
|
||||
if err = releaseservice.UpdateRelease(ctx.User, ctx.Repo.GitRepo, rel, attachmentUUIDs); err != nil {
|
||||
ctx.ServerError("UpdateRelease", err)
|
||||
return
|
||||
}
|
||||
@@ -290,7 +291,7 @@ func EditReleasePost(ctx *context.Context, form auth.EditReleaseForm) {
|
||||
|
||||
// DeleteRelease delete a release
|
||||
func DeleteRelease(ctx *context.Context) {
|
||||
if err := models.DeleteReleaseByID(ctx.QueryInt64("id"), ctx.User, true); err != nil {
|
||||
if err := releaseservice.DeleteReleaseByID(ctx.QueryInt64("id"), ctx.User, true); err != nil {
|
||||
ctx.Flash.Error("DeleteReleaseByID: " + err.Error())
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("repo.release.deletion_success"))
|
||||
|
||||
@@ -17,10 +17,11 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/migrations"
|
||||
"code.gitea.io/gitea/modules/notification"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -114,6 +115,7 @@ func Create(ctx *context.Context) {
|
||||
|
||||
// Give default value for template to render.
|
||||
ctx.Data["Gitignores"] = models.Gitignores
|
||||
ctx.Data["LabelTemplates"] = models.LabelTemplates
|
||||
ctx.Data["Licenses"] = models.Licenses
|
||||
ctx.Data["Readmes"] = models.Readmes
|
||||
ctx.Data["readme"] = "Default"
|
||||
@@ -154,6 +156,7 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
|
||||
ctx.Data["Title"] = ctx.Tr("new_repo")
|
||||
|
||||
ctx.Data["Gitignores"] = models.Gitignores
|
||||
ctx.Data["LabelTemplates"] = models.LabelTemplates
|
||||
ctx.Data["Licenses"] = models.Licenses
|
||||
ctx.Data["Readmes"] = models.Readmes
|
||||
|
||||
@@ -172,12 +175,15 @@ func CreatePost(ctx *context.Context, form auth.CreateRepoForm) {
|
||||
Name: form.RepoName,
|
||||
Description: form.Description,
|
||||
Gitignores: form.Gitignores,
|
||||
IssueLabels: form.IssueLabels,
|
||||
License: form.License,
|
||||
Readme: form.Readme,
|
||||
IsPrivate: form.Private || setting.Repository.ForcePrivate,
|
||||
AutoInit: form.AutoInit,
|
||||
})
|
||||
if err == nil {
|
||||
notification.NotifyCreateRepository(ctx.User, ctxUser, repo)
|
||||
|
||||
log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name)
|
||||
ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name)
|
||||
return
|
||||
@@ -278,6 +284,8 @@ func MigratePost(ctx *context.Context, form auth.MigrateRepoForm) {
|
||||
|
||||
repo, err := migrations.MigrateRepository(ctx.User, ctxUser.Name, opts)
|
||||
if err == nil {
|
||||
notification.NotifyCreateRepository(ctx.User, ctxUser, repo)
|
||||
|
||||
log.Trace("Repository migrated [%d]: %s/%s successfully", repo.ID, ctxUser.Name, form.RepoName)
|
||||
ctx.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + form.RepoName)
|
||||
return
|
||||
|
||||
+98
-8
@@ -14,9 +14,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"mvdan.cc/xurls/v2"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
@@ -24,9 +21,14 @@ import (
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/routers/utils"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
mirror_service "code.gitea.io/gitea/services/mirror"
|
||||
|
||||
"github.com/unknwon/com"
|
||||
"mvdan.cc/xurls/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -144,7 +146,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
ctx.Repo.Mirror.EnablePrune = form.EnablePrune
|
||||
ctx.Repo.Mirror.Interval = interval
|
||||
if interval != 0 {
|
||||
ctx.Repo.Mirror.NextUpdateUnix = util.TimeStampNow().AddDuration(interval)
|
||||
ctx.Repo.Mirror.NextUpdateUnix = timeutil.TimeStampNow().AddDuration(interval)
|
||||
} else {
|
||||
ctx.Repo.Mirror.NextUpdateUnix = 0
|
||||
}
|
||||
@@ -169,6 +171,10 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
return
|
||||
}
|
||||
|
||||
if form.MirrorUsername != "" || form.MirrorPassword != "" {
|
||||
u.User = url.UserPassword(form.MirrorUsername, form.MirrorPassword)
|
||||
}
|
||||
|
||||
// Now use xurls
|
||||
address := validFormAddress.FindString(form.MirrorAddress)
|
||||
if address != form.MirrorAddress && form.MirrorAddress != "" {
|
||||
@@ -185,7 +191,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
|
||||
address = u.String()
|
||||
|
||||
if err := ctx.Repo.Mirror.SaveAddress(address); err != nil {
|
||||
if err := mirror_service.SaveAddress(ctx.Repo.Mirror, address); err != nil {
|
||||
ctx.ServerError("SaveAddress", err)
|
||||
return
|
||||
}
|
||||
@@ -199,7 +205,8 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
return
|
||||
}
|
||||
|
||||
go models.MirrorQueue.Add(repo.ID)
|
||||
mirror_service.StartToMirror(repo.ID)
|
||||
|
||||
ctx.Flash.Info(ctx.Tr("repo.settings.mirror_sync_in_progress"))
|
||||
ctx.Redirect(repo.Link() + "/settings")
|
||||
|
||||
@@ -486,6 +493,18 @@ func Collaboration(ctx *context.Context) {
|
||||
}
|
||||
ctx.Data["Collaborators"] = users
|
||||
|
||||
teams, err := ctx.Repo.Repository.GetRepoTeams()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetRepoTeams", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Teams"] = teams
|
||||
ctx.Data["Repo"] = ctx.Repo.Repository
|
||||
ctx.Data["OrgID"] = ctx.Repo.Repository.OwnerID
|
||||
ctx.Data["OrgName"] = ctx.Repo.Repository.OwnerName
|
||||
ctx.Data["Org"] = ctx.Repo.Repository.Owner
|
||||
ctx.Data["Units"] = models.Units
|
||||
|
||||
ctx.HTML(200, tplCollaboration)
|
||||
}
|
||||
|
||||
@@ -533,7 +552,7 @@ func CollaborationPost(ctx *context.Context) {
|
||||
}
|
||||
|
||||
if setting.Service.EnableNotifyMail {
|
||||
models.SendCollaboratorMail(u, ctx.User, ctx.Repo.Repository)
|
||||
mailer.SendCollaboratorMail(u, ctx.User, ctx.Repo.Repository)
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.add_collaborator_success"))
|
||||
@@ -562,6 +581,77 @@ func DeleteCollaboration(ctx *context.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// AddTeamPost response for adding a team to a repository
|
||||
func AddTeamPost(ctx *context.Context) {
|
||||
if !ctx.Repo.Owner.RepoAdminChangeTeamAccess && !ctx.Repo.IsOwner() {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.change_team_access_not_allowed"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("team")))
|
||||
if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
team, err := ctx.Repo.Owner.GetTeam(name)
|
||||
if err != nil {
|
||||
if models.IsErrTeamNotExist(err) {
|
||||
ctx.Flash.Error(ctx.Tr("form.team_not_exist"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
} else {
|
||||
ctx.ServerError("GetTeam", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if team.OrgID != ctx.Repo.Repository.OwnerID {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.team_not_in_organization"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
if models.HasTeamRepo(ctx.Repo.Repository.OwnerID, team.ID, ctx.Repo.Repository.ID) {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.add_team_duplicate"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
if err = team.AddRepository(ctx.Repo.Repository); err != nil {
|
||||
ctx.ServerError("team.AddRepository", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.add_team_success"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
}
|
||||
|
||||
// DeleteTeam response for deleting a team from a repository
|
||||
func DeleteTeam(ctx *context.Context) {
|
||||
if !ctx.Repo.Owner.RepoAdminChangeTeamAccess && !ctx.Repo.IsOwner() {
|
||||
ctx.Flash.Error(ctx.Tr("repo.settings.change_team_access_not_allowed"))
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||
return
|
||||
}
|
||||
|
||||
team, err := models.GetTeamByID(ctx.QueryInt64("id"))
|
||||
if err != nil {
|
||||
ctx.ServerError("GetTeamByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err = team.RemoveRepository(ctx.Repo.Repository.ID); err != nil {
|
||||
ctx.ServerError("team.RemoveRepositorys", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("repo.settings.remove_team_success"))
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"redirect": ctx.Repo.RepoLink + "/settings/collaboration",
|
||||
})
|
||||
}
|
||||
|
||||
// parseOwnerAndRepo get repos by owner
|
||||
func parseOwnerAndRepo(ctx *context.Context) (*models.User, *models.Repository) {
|
||||
owner, err := models.GetUserByName(ctx.Params(":username"))
|
||||
|
||||
@@ -7,6 +7,7 @@ package repo
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
@@ -125,6 +126,29 @@ func SettingsProtectedBranch(c *context.Context) {
|
||||
c.Data["whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.WhitelistUserIDs), ",")
|
||||
c.Data["merge_whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.MergeWhitelistUserIDs), ",")
|
||||
c.Data["approvals_whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.ApprovalsWhitelistUserIDs), ",")
|
||||
contexts, _ := models.FindRepoRecentCommitStatusContexts(c.Repo.Repository.ID, 7*24*time.Hour) // Find last week status check contexts
|
||||
for _, context := range protectBranch.StatusCheckContexts {
|
||||
var found bool
|
||||
for _, ctx := range contexts {
|
||||
if ctx == context {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
contexts = append(contexts, context)
|
||||
}
|
||||
}
|
||||
|
||||
c.Data["branch_status_check_contexts"] = contexts
|
||||
c.Data["is_context_required"] = func(context string) bool {
|
||||
for _, c := range protectBranch.StatusCheckContexts {
|
||||
if c == context {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if c.Repo.Owner.IsOrganization() {
|
||||
teams, err := c.Repo.Owner.TeamsWithAccessToRepo(c.Repo.Repository.ID, models.AccessModeRead)
|
||||
@@ -186,6 +210,10 @@ func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm)
|
||||
if strings.TrimSpace(f.MergeWhitelistTeams) != "" {
|
||||
mergeWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.MergeWhitelistTeams, ","))
|
||||
}
|
||||
|
||||
protectBranch.EnableStatusCheck = f.EnableStatusCheck
|
||||
protectBranch.StatusCheckContexts = f.StatusCheckContexts
|
||||
|
||||
protectBranch.RequiredApprovals = f.RequiredApprovals
|
||||
if strings.TrimSpace(f.ApprovalsWhitelistUsers) != "" {
|
||||
approvalsWhitelistUsers, _ = base.StringsToInt64s(strings.Split(f.ApprovalsWhitelistUsers, ","))
|
||||
|
||||
@@ -185,3 +185,196 @@ func TestCollaborationPost_NonExistentUser(t *testing.T) {
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||
}
|
||||
|
||||
func TestAddTeamPost(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org26/repo43")
|
||||
|
||||
ctx.Req.Form.Set("team", "team11")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org26",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
team := &models.Team{
|
||||
ID: 11,
|
||||
OrgID: 26,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 43,
|
||||
Owner: org,
|
||||
OwnerID: 26,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 26,
|
||||
LowerName: "org26",
|
||||
RepoAdminChangeTeamAccess: true,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
AddTeamPost(ctx)
|
||||
|
||||
assert.True(t, team.HasRepository(re.ID))
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.Empty(t, ctx.Flash.ErrorMsg)
|
||||
}
|
||||
|
||||
func TestAddTeamPost_NotAllowed(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org26/repo43")
|
||||
|
||||
ctx.Req.Form.Set("team", "team11")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org26",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
team := &models.Team{
|
||||
ID: 11,
|
||||
OrgID: 26,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 43,
|
||||
Owner: org,
|
||||
OwnerID: 26,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 26,
|
||||
LowerName: "org26",
|
||||
RepoAdminChangeTeamAccess: false,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
AddTeamPost(ctx)
|
||||
|
||||
assert.False(t, team.HasRepository(re.ID))
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||
|
||||
}
|
||||
|
||||
func TestAddTeamPost_AddTeamTwice(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org26/repo43")
|
||||
|
||||
ctx.Req.Form.Set("team", "team11")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org26",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
team := &models.Team{
|
||||
ID: 11,
|
||||
OrgID: 26,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 43,
|
||||
Owner: org,
|
||||
OwnerID: 26,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 26,
|
||||
LowerName: "org26",
|
||||
RepoAdminChangeTeamAccess: true,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
AddTeamPost(ctx)
|
||||
|
||||
AddTeamPost(ctx)
|
||||
assert.True(t, team.HasRepository(re.ID))
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||
}
|
||||
|
||||
func TestAddTeamPost_NonExistentTeam(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org26/repo43")
|
||||
|
||||
ctx.Req.Form.Set("team", "team-non-existent")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org26",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 43,
|
||||
Owner: org,
|
||||
OwnerID: 26,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 26,
|
||||
LowerName: "org26",
|
||||
RepoAdminChangeTeamAccess: true,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
AddTeamPost(ctx)
|
||||
assert.EqualValues(t, http.StatusFound, ctx.Resp.Status())
|
||||
assert.NotEmpty(t, ctx.Flash.ErrorMsg)
|
||||
}
|
||||
|
||||
func TestDeleteTeam(t *testing.T) {
|
||||
models.PrepareTestEnv(t)
|
||||
ctx := test.MockContext(t, "org3/team1/repo3")
|
||||
|
||||
ctx.Req.Form.Set("id", "2")
|
||||
|
||||
org := &models.User{
|
||||
LowerName: "org3",
|
||||
Type: models.UserTypeOrganization,
|
||||
}
|
||||
|
||||
team := &models.Team{
|
||||
ID: 2,
|
||||
OrgID: 3,
|
||||
}
|
||||
|
||||
re := &models.Repository{
|
||||
ID: 3,
|
||||
Owner: org,
|
||||
OwnerID: 3,
|
||||
}
|
||||
|
||||
repo := &context.Repository{
|
||||
Owner: &models.User{
|
||||
ID: 3,
|
||||
LowerName: "org3",
|
||||
RepoAdminChangeTeamAccess: true,
|
||||
},
|
||||
Repository: re,
|
||||
}
|
||||
|
||||
ctx.Repo = repo
|
||||
|
||||
DeleteTeam(ctx)
|
||||
|
||||
assert.False(t, team.HasRepository(re.ID))
|
||||
}
|
||||
|
||||
+4
-17
@@ -27,24 +27,11 @@ func TopicsPost(ctx *context.Context) {
|
||||
topics = strings.Split(topicsStr, ",")
|
||||
}
|
||||
|
||||
invalidTopics := make([]string, 0)
|
||||
i := 0
|
||||
for _, topic := range topics {
|
||||
topic = strings.TrimSpace(strings.ToLower(topic))
|
||||
// ignore empty string
|
||||
if len(topic) > 0 {
|
||||
topics[i] = topic
|
||||
i++
|
||||
}
|
||||
if !models.ValidateTopic(topic) {
|
||||
invalidTopics = append(invalidTopics, topic)
|
||||
}
|
||||
}
|
||||
topics = topics[:i]
|
||||
validTopics, invalidTopics := models.SanitizeAndValidateTopics(topics)
|
||||
|
||||
if len(topics) > 25 {
|
||||
if len(validTopics) > 25 {
|
||||
ctx.JSON(422, map[string]interface{}{
|
||||
"invalidTopics": topics[:0],
|
||||
"invalidTopics": nil,
|
||||
"message": ctx.Tr("repo.topic.count_prompt"),
|
||||
})
|
||||
return
|
||||
@@ -58,7 +45,7 @@ func TopicsPost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
err := models.SaveTopics(ctx.Repo.Repository.ID, topics...)
|
||||
err := models.SaveTopics(ctx.Repo.Repository.ID, validTopics...)
|
||||
if err != nil {
|
||||
log.Error("SaveTopics failed: %v", err)
|
||||
ctx.JSON(500, map[string]interface{}{
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/charset"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/highlight"
|
||||
@@ -23,7 +24,6 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -160,10 +160,11 @@ func renderDirectory(ctx *context.Context, treeLink string) {
|
||||
ctx.Data["FileSize"] = fileSize
|
||||
} else {
|
||||
d, _ := ioutil.ReadAll(dataRc)
|
||||
buf = templates.ToUTF8WithFallback(append(buf, d...))
|
||||
buf = charset.ToUTF8WithFallback(append(buf, d...))
|
||||
|
||||
if markup.Type(readmeFile.Name()) != "" {
|
||||
if markupType := markup.Type(readmeFile.Name()); markupType != "" {
|
||||
ctx.Data["IsMarkup"] = true
|
||||
ctx.Data["MarkupType"] = string(markupType)
|
||||
ctx.Data["FileContent"] = string(markup.Render(readmeFile.Name(), buf, treeLink, ctx.Repo.Repository.ComposeMetas()))
|
||||
} else {
|
||||
ctx.Data["IsRenderedHTML"] = true
|
||||
@@ -278,12 +279,13 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
||||
}
|
||||
|
||||
d, _ := ioutil.ReadAll(dataRc)
|
||||
buf = templates.ToUTF8WithFallback(append(buf, d...))
|
||||
buf = charset.ToUTF8WithFallback(append(buf, d...))
|
||||
|
||||
readmeExist := markup.IsReadmeFile(blob.Name())
|
||||
ctx.Data["ReadmeExist"] = readmeExist
|
||||
if markup.Type(blob.Name()) != "" {
|
||||
if markupType := markup.Type(blob.Name()); markupType != "" {
|
||||
ctx.Data["IsMarkup"] = true
|
||||
ctx.Data["MarkupType"] = markupType
|
||||
ctx.Data["FileContent"] = string(markup.Render(blob.Name(), buf, path.Dir(treeLink), ctx.Repo.Repository.ComposeMetas()))
|
||||
} else if readmeExist {
|
||||
ctx.Data["IsRenderedHTML"] = true
|
||||
@@ -293,7 +295,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
||||
} else {
|
||||
// Building code view blocks with line number on server side.
|
||||
var fileContent string
|
||||
if content, err := templates.ToUTF8WithErr(buf); err != nil {
|
||||
if content, err := charset.ToUTF8WithErr(buf); err != nil {
|
||||
log.Error("ToUTF8WithErr: %v", err)
|
||||
fileContent = string(buf)
|
||||
} else {
|
||||
@@ -317,7 +319,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
||||
|
||||
output.Reset()
|
||||
for i := 0; i < len(lines); i++ {
|
||||
output.WriteString(fmt.Sprintf(`<span id="L%d">%d</span>`, i+1, i+1))
|
||||
output.WriteString(fmt.Sprintf(`<span id="L%[1]d" data-line-number="%[1]d"></span>`, i+1))
|
||||
}
|
||||
ctx.Data["LineNums"] = gotemplate.HTML(output.String())
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -145,6 +145,7 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
|
||||
PullRequest: form.PullRequest,
|
||||
Repository: form.Repository,
|
||||
},
|
||||
BranchFilter: form.BranchFilter,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,20 +198,17 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
|
||||
}
|
||||
|
||||
// GogsHooksNewPost response for creating webhook
|
||||
func GogsHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
|
||||
newGenericWebhookPost(ctx, form, models.GOGS)
|
||||
func GogsHooksNewPost(ctx *context.Context, form auth.NewGogshookForm) {
|
||||
newGogsWebhookPost(ctx, form, models.GOGS)
|
||||
}
|
||||
|
||||
func newGenericWebhookPost(ctx *context.Context, form auth.NewWebhookForm, kind models.HookTaskType) {
|
||||
// newGogsWebhookPost response for creating gogs hook
|
||||
func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind models.HookTaskType) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
|
||||
ctx.Data["PageIsSettingsHooks"] = true
|
||||
ctx.Data["PageIsSettingsHooksNew"] = true
|
||||
ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
|
||||
|
||||
ctx.Data["HookType"] = "gitea"
|
||||
if kind == models.GOGS {
|
||||
ctx.Data["HookType"] = "gogs"
|
||||
}
|
||||
ctx.Data["HookType"] = "gogs"
|
||||
|
||||
orCtx, err := getOrgRepoCtx(ctx)
|
||||
if err != nil {
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/markup/markdown"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
@@ -54,11 +55,11 @@ func MustEnableWiki(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// PageMeta wiki page meat information
|
||||
// PageMeta wiki page meta information
|
||||
type PageMeta struct {
|
||||
Name string
|
||||
SubURL string
|
||||
UpdatedUnix util.TimeStamp
|
||||
UpdatedUnix timeutil.TimeStamp
|
||||
}
|
||||
|
||||
// findEntryForFile finds the tree entry for a target filepath.
|
||||
@@ -248,9 +249,9 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry)
|
||||
}
|
||||
|
||||
// get Commit Count
|
||||
commitsHistory, err := wikiRepo.CommitsByFileAndRange("master", pageFilename, page)
|
||||
commitsHistory, err := wikiRepo.CommitsByFileAndRangeNoFollow("master", pageFilename, page)
|
||||
if err != nil {
|
||||
ctx.ServerError("CommitsByFileAndRange", err)
|
||||
ctx.ServerError("CommitsByFileAndRangeNoFollow", err)
|
||||
return nil, nil
|
||||
}
|
||||
commitsHistory = models.ValidateCommitsWithEmails(commitsHistory)
|
||||
@@ -413,7 +414,7 @@ func WikiPages(ctx *context.Context) {
|
||||
pages = append(pages, PageMeta{
|
||||
Name: wikiName,
|
||||
SubURL: models.WikiNameToSubURL(wikiName),
|
||||
UpdatedUnix: util.TimeStamp(c.Author.When.Unix()),
|
||||
UpdatedUnix: timeutil.TimeStamp(c.Author.When.Unix()),
|
||||
})
|
||||
}
|
||||
ctx.Data["Pages"] = pages
|
||||
|
||||
+41
-22
@@ -34,17 +34,22 @@ import (
|
||||
"code.gitea.io/gitea/routers/repo"
|
||||
"code.gitea.io/gitea/routers/user"
|
||||
userSetting "code.gitea.io/gitea/routers/user/setting"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
"github.com/go-macaron/binding"
|
||||
"github.com/go-macaron/cache"
|
||||
"github.com/go-macaron/captcha"
|
||||
"github.com/go-macaron/csrf"
|
||||
"github.com/go-macaron/i18n"
|
||||
"github.com/go-macaron/session"
|
||||
"github.com/go-macaron/toolbox"
|
||||
// to registers all internal adapters
|
||||
_ "code.gitea.io/gitea/modules/session"
|
||||
|
||||
"gitea.com/macaron/binding"
|
||||
"gitea.com/macaron/cache"
|
||||
"gitea.com/macaron/captcha"
|
||||
"gitea.com/macaron/cors"
|
||||
"gitea.com/macaron/csrf"
|
||||
"gitea.com/macaron/i18n"
|
||||
"gitea.com/macaron/macaron"
|
||||
"gitea.com/macaron/session"
|
||||
"gitea.com/macaron/toolbox"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/tstranex/u2f"
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
)
|
||||
|
||||
type routerLoggerOptions struct {
|
||||
@@ -162,7 +167,7 @@ func NewMacaron() *macaron.Macaron {
|
||||
))
|
||||
|
||||
m.Use(templates.HTMLRenderer())
|
||||
models.InitMailRender(templates.Mailer())
|
||||
mailer.InitMailRender(templates.Mailer())
|
||||
|
||||
localeNames, err := options.Dir("locale")
|
||||
|
||||
@@ -181,12 +186,13 @@ func NewMacaron() *macaron.Macaron {
|
||||
}
|
||||
|
||||
m.Use(i18n.I18n(i18n.Options{
|
||||
SubURL: setting.AppSubURL,
|
||||
Files: localFiles,
|
||||
Langs: setting.Langs,
|
||||
Names: setting.Names,
|
||||
DefaultLang: "en-US",
|
||||
Redirect: false,
|
||||
SubURL: setting.AppSubURL,
|
||||
Files: localFiles,
|
||||
Langs: setting.Langs,
|
||||
Names: setting.Names,
|
||||
DefaultLang: "en-US",
|
||||
Redirect: false,
|
||||
CookieDomain: setting.SessionConfig.Domain,
|
||||
}))
|
||||
m.Use(cache.Cacher(cache.Options{
|
||||
Adapter: setting.CacheService.Adapter,
|
||||
@@ -202,8 +208,9 @@ func NewMacaron() *macaron.Macaron {
|
||||
Cookie: setting.CSRFCookieName,
|
||||
SetCookie: true,
|
||||
Secure: setting.SessionConfig.Secure,
|
||||
CookieHttpOnly: true,
|
||||
CookieHttpOnly: setting.CSRFCookieHTTPOnly,
|
||||
Header: "X-Csrf-Token",
|
||||
CookieDomain: setting.SessionConfig.Domain,
|
||||
CookiePath: setting.AppSubURL,
|
||||
}))
|
||||
m.Use(toolbox.Toolboxer(m, toolbox.Options{
|
||||
@@ -397,6 +404,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
// r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
|
||||
m.Any("/activate", user.Activate, reqSignIn)
|
||||
m.Any("/activate_email", user.ActivateEmail)
|
||||
m.Get("/avatar/:username/:size", user.Avatar)
|
||||
m.Get("/email2user", user.Email2User)
|
||||
m.Get("/recover_account", user.ResetPasswd)
|
||||
m.Post("/recover_account", user.ResetPasswdPost)
|
||||
@@ -436,17 +444,19 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Post("/delete", admin.DeleteDefaultWebhook)
|
||||
m.Get("/:type/new", repo.WebhooksNew)
|
||||
m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
|
||||
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost)
|
||||
m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
|
||||
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
|
||||
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
|
||||
m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
|
||||
m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
|
||||
m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
|
||||
m.Get("/:id", repo.WebHooksEdit)
|
||||
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
||||
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksEditPost)
|
||||
m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost)
|
||||
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
|
||||
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
||||
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
|
||||
m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
|
||||
m.Post("/msteams/:id", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
|
||||
})
|
||||
|
||||
@@ -575,7 +585,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Post("/delete", org.DeleteWebhook)
|
||||
m.Get("/:type/new", repo.WebhooksNew)
|
||||
m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
|
||||
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost)
|
||||
m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
|
||||
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
|
||||
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
|
||||
m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
|
||||
@@ -621,6 +631,10 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Combo("").Get(repo.Collaboration).Post(repo.CollaborationPost)
|
||||
m.Post("/access_mode", repo.ChangeCollaborationAccessMode)
|
||||
m.Post("/delete", repo.DeleteCollaboration)
|
||||
m.Group("/team", func() {
|
||||
m.Post("", repo.AddTeamPost)
|
||||
m.Post("/delete", repo.DeleteTeam)
|
||||
})
|
||||
})
|
||||
m.Group("/branches", func() {
|
||||
m.Combo("").Get(repo.ProtectedBranch).Post(repo.ProtectedBranchPost)
|
||||
@@ -633,7 +647,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Post("/delete", repo.DeleteWebhook)
|
||||
m.Get("/:type/new", repo.WebhooksNew)
|
||||
m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
|
||||
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.GogsHooksNewPost)
|
||||
m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost)
|
||||
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
|
||||
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
|
||||
m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
|
||||
@@ -665,7 +679,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
}, func(ctx *context.Context) {
|
||||
ctx.Data["PageIsSettings"] = true
|
||||
})
|
||||
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.UnitTypes(), context.RepoRef())
|
||||
}, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef())
|
||||
|
||||
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action)
|
||||
|
||||
@@ -946,9 +960,14 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Get("/swagger.v1.json", templates.JSONRenderer(), routers.SwaggerV1Json)
|
||||
}
|
||||
|
||||
var handlers []macaron.Handler
|
||||
if setting.EnableCORS {
|
||||
handlers = append(handlers, cors.CORS(setting.CORSConfig))
|
||||
}
|
||||
handlers = append(handlers, ignSignIn)
|
||||
m.Group("/api", func() {
|
||||
apiv1.RegisterRoutes(m)
|
||||
}, ignSignIn)
|
||||
}, handlers...)
|
||||
|
||||
m.Group("/api/internal", func() {
|
||||
// package name internal is ideal but Golang is not allowed, so we use private as package name.
|
||||
|
||||
+28
-23
@@ -19,9 +19,11 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/recaptcha"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
"github.com/go-macaron/captcha"
|
||||
"gitea.com/macaron/captcha"
|
||||
"github.com/markbates/goth"
|
||||
"github.com/tstranex/u2f"
|
||||
)
|
||||
@@ -58,8 +60,8 @@ func AutoSignIn(ctx *context.Context) (bool, error) {
|
||||
defer func() {
|
||||
if !isSucceed {
|
||||
log.Trace("auto-login cookie cleared: %s", uname)
|
||||
ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -85,7 +87,7 @@ func AutoSignIn(ctx *context.Context) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
@@ -475,9 +477,9 @@ func handleSignIn(ctx *context.Context, u *models.User, remember bool) {
|
||||
func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyRedirect bool) string {
|
||||
if remember {
|
||||
days := 86400 * setting.LogInRememberDays
|
||||
ctx.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
ctx.SetSuperSecureCookie(base.EncodeMD5(u.Rands+u.Passwd),
|
||||
setting.CookieRememberName, u.Name, days, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
setting.CookieRememberName, u.Name, days, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
}
|
||||
|
||||
_ = ctx.Session.Delete("openid_verified_uri")
|
||||
@@ -507,10 +509,10 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
|
||||
}
|
||||
}
|
||||
|
||||
ctx.SetCookie("lang", u.Language, nil, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie("lang", u.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
|
||||
// Clear whatever CSRF has right now, force to generate a new one
|
||||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
|
||||
// Register last login
|
||||
u.SetLastLogin()
|
||||
@@ -610,7 +612,7 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context
|
||||
}
|
||||
|
||||
// Clear whatever CSRF has right now, force to generate a new one
|
||||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
|
||||
// Register last login
|
||||
u.SetLastLogin()
|
||||
@@ -947,10 +949,11 @@ func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form au
|
||||
|
||||
// Send confirmation email
|
||||
if setting.Service.RegisterEmailConfirm && u.ID > 1 {
|
||||
models.SendActivateAccountMail(ctx.Context, u)
|
||||
mailer.SendActivateAccountMail(ctx.Locale, u)
|
||||
|
||||
ctx.Data["IsSendRegisterMail"] = true
|
||||
ctx.Data["Email"] = u.Email
|
||||
ctx.Data["ActiveCodeLives"] = base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.HTML(200, TplActivate)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
|
||||
@@ -968,10 +971,10 @@ func handleSignOut(ctx *context.Context) {
|
||||
_ = ctx.Session.Delete("socialId")
|
||||
_ = ctx.Session.Delete("socialName")
|
||||
_ = ctx.Session.Delete("socialEmail")
|
||||
ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie("lang", "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true) // Setting the lang cookie will trigger the middleware to reset the language ot previous state.
|
||||
ctx.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie("lang", "", -1, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true) // Setting the lang cookie will trigger the middleware to reset the language ot previous state.
|
||||
}
|
||||
|
||||
// SignOut sign out from login status
|
||||
@@ -1008,7 +1011,7 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
|
||||
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
|
||||
|
||||
//Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true
|
||||
if !setting.Service.ShowRegistrationButton {
|
||||
if setting.Service.DisableRegistration {
|
||||
ctx.Error(403)
|
||||
return
|
||||
}
|
||||
@@ -1093,10 +1096,11 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
|
||||
|
||||
// Send confirmation email, no need for social account.
|
||||
if setting.Service.RegisterEmailConfirm && u.ID > 1 {
|
||||
models.SendActivateAccountMail(ctx.Context, u)
|
||||
mailer.SendActivateAccountMail(ctx.Locale, u)
|
||||
|
||||
ctx.Data["IsSendRegisterMail"] = true
|
||||
ctx.Data["Email"] = u.Email
|
||||
ctx.Data["ActiveCodeLives"] = base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.HTML(200, TplActivate)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
|
||||
@@ -1123,8 +1127,8 @@ func Activate(ctx *context.Context) {
|
||||
if ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName) {
|
||||
ctx.Data["ResendLimited"] = true
|
||||
} else {
|
||||
ctx.Data["ActiveCodeLives"] = base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
models.SendActivateAccountMail(ctx.Context, ctx.User)
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
mailer.SendActivateAccountMail(ctx.Locale, ctx.User)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
|
||||
log.Error("Set cache(MailResendLimit) fail: %v", err)
|
||||
@@ -1224,7 +1228,7 @@ func ForgotPasswdPost(ctx *context.Context) {
|
||||
u, err := models.GetUserByEmail(email)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
ctx.Data["ResetPwdCodeLives"] = base.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["IsResetSent"] = true
|
||||
ctx.HTML(200, tplForgotPassword)
|
||||
return
|
||||
@@ -1246,12 +1250,13 @@ func ForgotPasswdPost(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
models.SendResetPasswordMail(ctx.Context, u)
|
||||
mailer.SendResetPasswordMail(ctx.Locale, u)
|
||||
|
||||
if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
|
||||
log.Error("Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
|
||||
ctx.Data["ResetPwdCodeLives"] = base.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["IsResetSent"] = true
|
||||
ctx.HTML(200, tplForgotPassword)
|
||||
}
|
||||
|
||||
@@ -17,8 +17,10 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/recaptcha"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
|
||||
"github.com/go-macaron/captcha"
|
||||
"gitea.com/macaron/captcha"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -443,10 +445,11 @@ func RegisterOpenIDPost(ctx *context.Context, cpt *captcha.Captcha, form auth.Si
|
||||
|
||||
// Send confirmation email, no need for social account.
|
||||
if setting.Service.RegisterEmailConfirm && u.ID > 1 {
|
||||
models.SendActivateAccountMail(ctx.Context, u)
|
||||
mailer.SendActivateAccountMail(ctx.Locale, u)
|
||||
|
||||
ctx.Data["IsSendRegisterMail"] = true
|
||||
ctx.Data["Email"] = u.Email
|
||||
ctx.Data["ActiveCodeLives"] = base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.HTML(200, TplActivate)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2019 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 user
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
// Avatar redirect browser to user avatar of requested size
|
||||
func Avatar(ctx *context.Context) {
|
||||
userName := ctx.Params(":username")
|
||||
size, err := strconv.Atoi(ctx.Params(":size"))
|
||||
if err != nil {
|
||||
ctx.ServerError("Invalid avatar size", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug("Asked avatar for user %v and size %v", userName, size)
|
||||
|
||||
user, err := models.GetUserByName(userName)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
ctx.ServerError("Requested avatar for invalid user", err)
|
||||
} else {
|
||||
ctx.ServerError("Retrieving user by name", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Redirect(user.RealSizedAvatarLink(size))
|
||||
}
|
||||
+15
-12
@@ -18,9 +18,9 @@ import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/keybase/go-crypto/openpgp"
|
||||
"github.com/keybase/go-crypto/openpgp/armor"
|
||||
"github.com/unknwon/com"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -181,6 +181,8 @@ func Issues(ctx *context.Context) {
|
||||
filterMode = models.FilterModeAssign
|
||||
case "created_by":
|
||||
filterMode = models.FilterModeCreate
|
||||
case "mentioned":
|
||||
filterMode = models.FilterModeMention
|
||||
case "all": // filterMode already set to All
|
||||
default:
|
||||
viewType = "all"
|
||||
@@ -499,19 +501,20 @@ func showOrgProfile(ctx *context.Context) {
|
||||
count int64
|
||||
err error
|
||||
)
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OwnerID: org.ID,
|
||||
OrderBy: orderBy,
|
||||
Private: ctx.IsSigned,
|
||||
UserIsAdmin: ctx.IsUserSiteAdmin(),
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
Page: page,
|
||||
IsProfile: true,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
repos, count, err = models.SearchRepository(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OwnerID: org.ID,
|
||||
OrderBy: orderBy,
|
||||
Private: ctx.IsSigned,
|
||||
UserIsAdmin: ctx.IsUserSiteAdmin(),
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
Page: page,
|
||||
IsProfile: true,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
IncludeDescription: setting.UI.SearchRepoDescription,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
ctx.ServerError("SearchRepository", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@ import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ package user
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/go-macaron/binding"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
@@ -17,8 +16,9 @@ import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"gitea.com/macaron/binding"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
)
|
||||
|
||||
@@ -118,7 +118,7 @@ func newAccessTokenResponse(grant *models.OAuth2Grant) (*AccessTokenResponse, *A
|
||||
}
|
||||
}
|
||||
// generate access token to access the API
|
||||
expirationDate := util.TimeStampNow().Add(setting.OAuth2.AccessTokenExpirationTime)
|
||||
expirationDate := timeutil.TimeStampNow().Add(setting.OAuth2.AccessTokenExpirationTime)
|
||||
accessToken := &models.OAuth2Token{
|
||||
GrantID: grant.ID,
|
||||
Type: models.TypeAccessToken,
|
||||
@@ -135,7 +135,7 @@ func newAccessTokenResponse(grant *models.OAuth2Grant) (*AccessTokenResponse, *A
|
||||
}
|
||||
|
||||
// generate refresh token to request an access token after it expired later
|
||||
refreshExpirationDate := util.TimeStampNow().Add(setting.OAuth2.RefreshTokenExpirationTime * 60 * 60).AsTime().Unix()
|
||||
refreshExpirationDate := timeutil.TimeStampNow().Add(setting.OAuth2.RefreshTokenExpirationTime * 60 * 60).AsTime().Unix()
|
||||
refreshToken := &models.OAuth2Token{
|
||||
GrantID: grant.ID,
|
||||
Counter: grant.Counter,
|
||||
|
||||
+27
-25
@@ -169,40 +169,42 @@ func Profile(ctx *context.Context) {
|
||||
}
|
||||
case "stars":
|
||||
ctx.Data["PageIsProfileStarList"] = true
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OrderBy: orderBy,
|
||||
Private: ctx.IsSigned,
|
||||
UserIsAdmin: ctx.IsUserSiteAdmin(),
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
Page: page,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
StarredByID: ctxUser.ID,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
TopicOnly: topicOnly,
|
||||
repos, count, err = models.SearchRepository(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OrderBy: orderBy,
|
||||
Private: ctx.IsSigned,
|
||||
UserIsAdmin: ctx.IsUserSiteAdmin(),
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
Page: page,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
StarredByID: ctxUser.ID,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
TopicOnly: topicOnly,
|
||||
IncludeDescription: setting.UI.SearchRepoDescription,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
ctx.ServerError("SearchRepository", err)
|
||||
return
|
||||
}
|
||||
|
||||
total = int(count)
|
||||
default:
|
||||
repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OwnerID: ctxUser.ID,
|
||||
OrderBy: orderBy,
|
||||
Private: ctx.IsSigned,
|
||||
UserIsAdmin: ctx.IsUserSiteAdmin(),
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
Page: page,
|
||||
IsProfile: true,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
TopicOnly: topicOnly,
|
||||
repos, count, err = models.SearchRepository(&models.SearchRepoOptions{
|
||||
Keyword: keyword,
|
||||
OwnerID: ctxUser.ID,
|
||||
OrderBy: orderBy,
|
||||
Private: ctx.IsSigned,
|
||||
UserIsAdmin: ctx.IsUserSiteAdmin(),
|
||||
UserID: ctx.Data["SignedUserID"].(int64),
|
||||
Page: page,
|
||||
IsProfile: true,
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
Collaborate: util.OptionalBoolFalse,
|
||||
TopicOnly: topicOnly,
|
||||
IncludeDescription: setting.UI.SearchRepoDescription,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchRepositoryByName", err)
|
||||
ctx.ServerError("SearchRepository", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,16 @@
|
||||
package setting
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/auth"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/services/mailer"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -23,6 +27,7 @@ func Account(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["PageIsSettingsAccount"] = true
|
||||
ctx.Data["Email"] = ctx.User.Email
|
||||
ctx.Data["EmailNotificationsPreference"] = ctx.User.EmailNotifications()
|
||||
|
||||
loadAccountData(ctx)
|
||||
|
||||
@@ -81,6 +86,25 @@ func EmailPost(ctx *context.Context, form auth.AddEmailForm) {
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
|
||||
return
|
||||
}
|
||||
// Set Email Notification Preference
|
||||
if ctx.Query("_method") == "NOTIFICATION" {
|
||||
preference := ctx.Query("preference")
|
||||
if !(preference == models.EmailNotificationsEnabled ||
|
||||
preference == models.EmailNotificationsOnMention ||
|
||||
preference == models.EmailNotificationsDisabled) {
|
||||
log.Error("Email notifications preference change returned unrecognized option %s: %s", preference, ctx.User.Name)
|
||||
ctx.ServerError("SetEmailPreference", errors.New("option unrecognized"))
|
||||
return
|
||||
}
|
||||
if err := ctx.User.SetEmailNotifications(preference); err != nil {
|
||||
log.Error("Set Email Notifications failed: %v", err)
|
||||
ctx.ServerError("SetEmailNotifications", err)
|
||||
return
|
||||
}
|
||||
log.Trace("Email notifications preference made %s: %s", preference, ctx.User.Name)
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
loadAccountData(ctx)
|
||||
@@ -107,12 +131,12 @@ func EmailPost(ctx *context.Context, form auth.AddEmailForm) {
|
||||
|
||||
// Send confirmation email
|
||||
if setting.Service.RegisterEmailConfirm {
|
||||
models.SendActivateEmailMail(ctx.Context, ctx.User, email)
|
||||
mailer.SendActivateEmailMail(ctx.Locale, ctx.User, email)
|
||||
|
||||
if err := ctx.Cache.Put("MailResendLimit_"+ctx.User.LowerName, ctx.User.LowerName, 180); err != nil {
|
||||
log.Error("Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, base.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())))
|
||||
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())))
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
"github.com/Unknwon/i18n"
|
||||
"github.com/unknwon/com"
|
||||
"github.com/unknwon/i18n"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -104,7 +104,7 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) {
|
||||
}
|
||||
|
||||
// Update the language to the one we just set
|
||||
ctx.SetCookie("lang", ctx.User.Language, nil, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
|
||||
ctx.SetCookie("lang", ctx.User.Language, nil, setting.AppSubURL, setting.SessionConfig.Domain, setting.SessionConfig.Secure, true)
|
||||
|
||||
log.Trace("User settings updated: %s", ctx.User.Name)
|
||||
ctx.Flash.Success(i18n.Tr(ctx.User.Language, "settings.update_profile_success"))
|
||||
|
||||
@@ -81,7 +81,6 @@ func twofaGenerateSecretAndQr(ctx *context.Context) bool {
|
||||
// Filter unsafe character ':' in issuer
|
||||
issuer := strings.Replace(setting.AppName+" ("+setting.Domain+")", ":", "", -1)
|
||||
if otpKey == nil {
|
||||
err = nil // clear the error, in case the URL was invalid
|
||||
otpKey, err = totp.Generate(totp.GenerateOpts{
|
||||
SecretSize: 40,
|
||||
Issuer: issuer,
|
||||
|
||||
Reference in New Issue
Block a user