mirror of
https://github.com/go-gitea/gitea
synced 2025-12-07 13:28:25 +00:00
Merge branch 'main' into create-user-system-defaults
This commit is contained in:
@@ -63,8 +63,8 @@ func SearchPackages(ctx *context.Context) {
|
||||
|
||||
opts := &packages_model.PackageSearchOptions{
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Type: string(packages_model.TypeComposer),
|
||||
QueryName: ctx.FormTrim("q"),
|
||||
Type: packages_model.TypeComposer,
|
||||
Name: packages_model.SearchValue{Value: ctx.FormTrim("q")},
|
||||
Paginator: &paginator,
|
||||
}
|
||||
if ctx.FormTrim("type") != "" {
|
||||
|
||||
@@ -256,7 +256,12 @@ func setPackageTag(tag string, pv *packages_model.PackageVersion, deleteOnly boo
|
||||
}
|
||||
defer committer.Close()
|
||||
|
||||
pvs, err := packages_model.FindVersionsByPropertyNameAndValue(ctx, pv.PackageID, npm_module.TagProperty, tag)
|
||||
pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
|
||||
PackageID: pv.PackageID,
|
||||
Properties: map[string]string{
|
||||
npm_module.TagProperty: tag,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ func ServiceIndex(ctx *context.Context) {
|
||||
// SearchService https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-for-packages
|
||||
func SearchService(ctx *context.Context) {
|
||||
pvs, count, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Type: string(packages_model.TypeNuGet),
|
||||
QueryName: ctx.FormTrim("q"),
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Type: packages_model.TypeNuGet,
|
||||
Name: packages_model.SearchValue{Value: ctx.FormTrim("q")},
|
||||
Paginator: db.NewAbsoluteListOptions(
|
||||
ctx.FormInt("skip"),
|
||||
ctx.FormInt("take"),
|
||||
|
||||
@@ -41,7 +41,7 @@ func EnumeratePackages(ctx *context.Context) {
|
||||
func EnumeratePackagesLatest(ctx *context.Context) {
|
||||
pvs, _, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Type: string(packages_model.TypeRubyGems),
|
||||
Type: packages_model.TypeRubyGems,
|
||||
})
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
@@ -96,7 +96,7 @@ func ServePackageSpecification(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
pvs, err := packages_model.GetVersionsByFilename(ctx, ctx.Package.Owner.ID, packages_model.TypeRubyGems, filename[:len(filename)-10]+"gem")
|
||||
pvs, err := getVersionsByFilename(ctx, filename[:len(filename)-10]+"gem")
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
@@ -158,7 +158,7 @@ func ServePackageSpecification(ctx *context.Context) {
|
||||
func DownloadPackageFile(ctx *context.Context) {
|
||||
filename := ctx.Params("filename")
|
||||
|
||||
pvs, err := packages_model.GetVersionsByFilename(ctx, ctx.Package.Owner.ID, packages_model.TypeRubyGems, filename)
|
||||
pvs, err := getVersionsByFilename(ctx, filename)
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
@@ -283,3 +283,12 @@ func DeletePackage(ctx *context.Context) {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
}
|
||||
}
|
||||
|
||||
func getVersionsByFilename(ctx *context.Context, filename string) ([]*packages_model.PackageVersion, error) {
|
||||
pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Type: packages_model.TypeRubyGems,
|
||||
HasFileWithName: filename,
|
||||
})
|
||||
return pvs, err
|
||||
}
|
||||
|
||||
@@ -216,7 +216,6 @@ func reqToken() func(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
if ctx.IsSigned {
|
||||
ctx.RequireCSRF()
|
||||
return
|
||||
}
|
||||
ctx.Error(http.StatusUnauthorized, "reqToken", "token is required")
|
||||
@@ -584,8 +583,7 @@ func bind(obj interface{}) http.HandlerFunc {
|
||||
func buildAuthGroup() *auth.Group {
|
||||
group := auth.NewGroup(
|
||||
&auth.OAuth2{},
|
||||
&auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API
|
||||
auth.SharedSession, // FIXME: this should be removed once all UI don't reference API/v1, see https://github.com/go-gitea/gitea/pull/16052
|
||||
&auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API
|
||||
)
|
||||
if setting.Service.EnableReverseProxyAuth {
|
||||
group.Add(&auth.ReverseProxy{})
|
||||
@@ -596,11 +594,9 @@ func buildAuthGroup() *auth.Group {
|
||||
}
|
||||
|
||||
// Routes registers all v1 APIs routes to web application.
|
||||
func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||
func Routes() *web.Route {
|
||||
m := web.NewRoute()
|
||||
|
||||
m.Use(sessioner)
|
||||
|
||||
m.Use(securityHeaders())
|
||||
if setting.CORSConfig.Enabled {
|
||||
m.Use(cors.Handler(cors.Options{
|
||||
@@ -609,7 +605,7 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||
// setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
|
||||
AllowedMethods: setting.CORSConfig.Methods,
|
||||
AllowCredentials: setting.CORSConfig.AllowCredentials,
|
||||
AllowedHeaders: []string{"Authorization", "X-CSRFToken", "X-Gitea-OTP"},
|
||||
AllowedHeaders: []string{"Authorization", "X-Gitea-OTP"},
|
||||
MaxAge: int(setting.CORSConfig.MaxAge.Seconds()),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func NewAvailable(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
func getFindNotificationOptions(ctx *context.APIContext) *models.FindNotificationOptions {
|
||||
before, since, err := utils.GetQueryBeforeSince(ctx)
|
||||
before, since, err := context.GetQueryBeforeSince(ctx.Context)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||
return nil
|
||||
|
||||
@@ -56,8 +56,8 @@ func ListPackages(ctx *context.APIContext) {
|
||||
|
||||
pvs, count, err := packages.SearchVersions(ctx, &packages.PackageSearchOptions{
|
||||
OwnerID: ctx.Package.Owner.ID,
|
||||
Type: packageType,
|
||||
QueryName: query,
|
||||
Type: packages.Type(packageType),
|
||||
Name: packages.SearchValue{Value: query},
|
||||
Paginator: &listOptions,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
@@ -111,7 +112,7 @@ func SearchIssues(ctx *context.APIContext) {
|
||||
// "200":
|
||||
// "$ref": "#/responses/IssueList"
|
||||
|
||||
before, since, err := utils.GetQueryBeforeSince(ctx)
|
||||
before, since, err := context.GetQueryBeforeSince(ctx.Context)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||
return
|
||||
@@ -359,7 +360,7 @@ func ListIssues(ctx *context.APIContext) {
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/IssueList"
|
||||
before, since, err := utils.GetQueryBeforeSince(ctx)
|
||||
before, since, err := context.GetQueryBeforeSince(ctx.Context)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||
return
|
||||
@@ -405,12 +406,12 @@ func ListIssues(ctx *context.APIContext) {
|
||||
for i := range part {
|
||||
// uses names and fall back to ids
|
||||
// non existent milestones are discarded
|
||||
mile, err := models.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, part[i])
|
||||
mile, err := issues_model.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, part[i])
|
||||
if err == nil {
|
||||
mileIDs = append(mileIDs, mile.ID)
|
||||
continue
|
||||
}
|
||||
if !models.IsErrMilestoneNotExist(err) {
|
||||
if !issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoIDANDName", err)
|
||||
return
|
||||
}
|
||||
@@ -418,12 +419,12 @@ func ListIssues(ctx *context.APIContext) {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
mile, err = models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, id)
|
||||
mile, err = issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, id)
|
||||
if err == nil {
|
||||
mileIDs = append(mileIDs, mile.ID)
|
||||
continue
|
||||
}
|
||||
if models.IsErrMilestoneNotExist(err) {
|
||||
if issues_model.IsErrMilestoneNotExist(err) {
|
||||
continue
|
||||
}
|
||||
ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err)
|
||||
|
||||
@@ -58,7 +58,7 @@ func ListIssueComments(ctx *context.APIContext) {
|
||||
// "200":
|
||||
// "$ref": "#/responses/CommentList"
|
||||
|
||||
before, since, err := utils.GetQueryBeforeSince(ctx)
|
||||
before, since, err := context.GetQueryBeforeSince(ctx.Context)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||
return
|
||||
@@ -150,7 +150,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) {
|
||||
// "200":
|
||||
// "$ref": "#/responses/TimelineList"
|
||||
|
||||
before, since, err := utils.GetQueryBeforeSince(ctx)
|
||||
before, since, err := context.GetQueryBeforeSince(ctx.Context)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||
return
|
||||
@@ -253,7 +253,7 @@ func ListRepoIssueComments(ctx *context.APIContext) {
|
||||
// "200":
|
||||
// "$ref": "#/responses/CommentList"
|
||||
|
||||
before, since, err := utils.GetQueryBeforeSince(ctx)
|
||||
before, since, err := context.GetQueryBeforeSince(ctx.Context)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||
return
|
||||
|
||||
@@ -103,7 +103,7 @@ func ListTrackedTimes(ctx *context.APIContext) {
|
||||
opts.UserID = user.ID
|
||||
}
|
||||
|
||||
if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil {
|
||||
if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = context.GetQueryBeforeSince(ctx.Context); err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||
return
|
||||
}
|
||||
@@ -522,7 +522,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
var err error
|
||||
if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil {
|
||||
if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = context.GetQueryBeforeSince(ctx.Context); err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||
return
|
||||
}
|
||||
@@ -597,7 +597,7 @@ func ListMyTrackedTimes(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
var err error
|
||||
if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil {
|
||||
if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = context.GetQueryBeforeSince(ctx.Context); err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
@@ -57,7 +57,7 @@ func ListMilestones(ctx *context.APIContext) {
|
||||
// "200":
|
||||
// "$ref": "#/responses/MilestoneList"
|
||||
|
||||
milestones, total, err := models.GetMilestones(models.GetMilestonesOption{
|
||||
milestones, total, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||
ListOptions: utils.GetListOptions(ctx),
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
State: api.StateType(ctx.FormString("state")),
|
||||
@@ -146,7 +146,7 @@ func CreateMilestone(ctx *context.APIContext) {
|
||||
form.Deadline = &defaultDeadline
|
||||
}
|
||||
|
||||
milestone := &models.Milestone{
|
||||
milestone := &issues_model.Milestone{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: form.Title,
|
||||
Content: form.Description,
|
||||
@@ -158,7 +158,7 @@ func CreateMilestone(ctx *context.APIContext) {
|
||||
milestone.ClosedDateUnix = timeutil.TimeStampNow()
|
||||
}
|
||||
|
||||
if err := models.NewMilestone(milestone); err != nil {
|
||||
if err := issues_model.NewMilestone(milestone); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "NewMilestone", err)
|
||||
return
|
||||
}
|
||||
@@ -218,7 +218,7 @@ func EditMilestone(ctx *context.APIContext) {
|
||||
milestone.IsClosed = *form.State == string(api.StateClosed)
|
||||
}
|
||||
|
||||
if err := models.UpdateMilestone(milestone, oldIsClosed); err != nil {
|
||||
if err := issues_model.UpdateMilestone(milestone, oldIsClosed); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "UpdateMilestone", err)
|
||||
return
|
||||
}
|
||||
@@ -255,7 +255,7 @@ func DeleteMilestone(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := models.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, m.ID); err != nil {
|
||||
if err := issues_model.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, m.ID); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "DeleteMilestoneByRepoID", err)
|
||||
return
|
||||
}
|
||||
@@ -263,23 +263,23 @@ func DeleteMilestone(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
// getMilestoneByIDOrName get milestone by ID and if not available by name
|
||||
func getMilestoneByIDOrName(ctx *context.APIContext) *models.Milestone {
|
||||
func getMilestoneByIDOrName(ctx *context.APIContext) *issues_model.Milestone {
|
||||
mile := ctx.Params(":id")
|
||||
mileID, _ := strconv.ParseInt(mile, 0, 64)
|
||||
|
||||
if mileID != 0 {
|
||||
milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, mileID)
|
||||
milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, mileID)
|
||||
if err == nil {
|
||||
return milestone
|
||||
} else if !models.IsErrMilestoneNotExist(err) {
|
||||
} else if !issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
milestone, err := models.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, mile)
|
||||
milestone, err := issues_model.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, mile)
|
||||
if err != nil {
|
||||
if models.IsErrMilestoneNotExist(err) {
|
||||
if issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.NotFound()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
@@ -342,9 +343,9 @@ func CreatePullRequest(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
if form.Milestone > 0 {
|
||||
milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, form.Milestone)
|
||||
milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, form.Milestone)
|
||||
if err != nil {
|
||||
if models.IsErrMilestoneNotExist(err) {
|
||||
if issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.NotFound()
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err)
|
||||
|
||||
@@ -75,7 +75,7 @@ func ListPullReviews(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = pr.Issue.LoadRepo(); err != nil {
|
||||
if err = pr.Issue.LoadRepo(ctx); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "LoadRepo", err)
|
||||
return
|
||||
}
|
||||
@@ -322,7 +322,7 @@ func CreatePullReview(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
if err := pr.Issue.LoadRepo(); err != nil {
|
||||
if err := pr.Issue.LoadRepo(ctx); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "pr.Issue.LoadRepo", err)
|
||||
return
|
||||
}
|
||||
@@ -657,7 +657,7 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions
|
||||
return
|
||||
}
|
||||
|
||||
if err := pr.Issue.LoadRepo(); err != nil {
|
||||
if err := pr.Issue.LoadRepo(ctx); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "pr.Issue.LoadRepo", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -31,23 +31,6 @@ import (
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
)
|
||||
|
||||
var searchOrderByMap = map[string]map[string]db.SearchOrderBy{
|
||||
"asc": {
|
||||
"alpha": db.SearchOrderByAlphabetically,
|
||||
"created": db.SearchOrderByOldest,
|
||||
"updated": db.SearchOrderByLeastUpdated,
|
||||
"size": db.SearchOrderBySize,
|
||||
"id": db.SearchOrderByID,
|
||||
},
|
||||
"desc": {
|
||||
"alpha": db.SearchOrderByAlphabeticallyReverse,
|
||||
"created": db.SearchOrderByNewest,
|
||||
"updated": db.SearchOrderByRecentUpdated,
|
||||
"size": db.SearchOrderBySizeReverse,
|
||||
"id": db.SearchOrderByIDReverse,
|
||||
},
|
||||
}
|
||||
|
||||
// Search repositories via options
|
||||
func Search(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/search repository repoSearch
|
||||
@@ -193,7 +176,7 @@ func Search(ctx *context.APIContext) {
|
||||
if len(sortOrder) == 0 {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
if searchModeMap, ok := searchOrderByMap[sortOrder]; ok {
|
||||
if searchModeMap, ok := context.SearchOrderByMap[sortOrder]; ok {
|
||||
if orderBy, ok := searchModeMap[sortMode]; ok {
|
||||
opts.OrderBy = orderBy
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Copyright 2017 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 utils
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
)
|
||||
|
||||
// GetListOptions returns list options using the page and limit parameters
|
||||
func GetListOptions(ctx *context.APIContext) db.ListOptions {
|
||||
return db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright 2017 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 utils
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
)
|
||||
|
||||
// GetQueryBeforeSince return parsed time (unix format) from URL query's before and since
|
||||
func GetQueryBeforeSince(ctx *context.APIContext) (before, since int64, err error) {
|
||||
qCreatedBefore, err := prepareQueryArg(ctx, "before")
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
qCreatedSince, err := prepareQueryArg(ctx, "since")
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
before, err = parseTime(qCreatedBefore)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
since, err = parseTime(qCreatedSince)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
return before, since, nil
|
||||
}
|
||||
|
||||
// parseTime parse time and return unix timestamp
|
||||
func parseTime(value string) (int64, error) {
|
||||
if len(value) != 0 {
|
||||
t, err := time.Parse(time.RFC3339, value)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if !t.IsZero() {
|
||||
return t.Unix(), nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// prepareQueryArg unescape and trim a query arg
|
||||
func prepareQueryArg(ctx *context.APIContext, name string) (value string, err error) {
|
||||
value, err = url.PathUnescape(ctx.FormString(name))
|
||||
value = strings.TrimSpace(value)
|
||||
return
|
||||
}
|
||||
|
||||
// GetListOptions returns list options using the page and limit parameters
|
||||
func GetListOptions(ctx *context.APIContext) db.ListOptions {
|
||||
return db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
|
||||
}
|
||||
}
|
||||
+2
-16
@@ -48,8 +48,6 @@ import (
|
||||
"code.gitea.io/gitea/services/repository/archiver"
|
||||
"code.gitea.io/gitea/services/task"
|
||||
"code.gitea.io/gitea/services/webhook"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
)
|
||||
|
||||
func mustInit(fn func() error) {
|
||||
@@ -174,20 +172,8 @@ func NormalRoutes() *web.Route {
|
||||
r.Use(middle)
|
||||
}
|
||||
|
||||
sessioner := session.Sessioner(session.Options{
|
||||
Provider: setting.SessionConfig.Provider,
|
||||
ProviderConfig: setting.SessionConfig.ProviderConfig,
|
||||
CookieName: setting.SessionConfig.CookieName,
|
||||
CookiePath: setting.SessionConfig.CookiePath,
|
||||
Gclifetime: setting.SessionConfig.Gclifetime,
|
||||
Maxlifetime: setting.SessionConfig.Maxlifetime,
|
||||
Secure: setting.SessionConfig.Secure,
|
||||
SameSite: setting.SessionConfig.SameSite,
|
||||
Domain: setting.SessionConfig.Domain,
|
||||
})
|
||||
|
||||
r.Mount("/", web_routers.Routes(sessioner))
|
||||
r.Mount("/api/v1", apiv1.Routes(sessioner))
|
||||
r.Mount("/", web_routers.Routes())
|
||||
r.Mount("/api/v1", apiv1.Routes())
|
||||
r.Mount("/api/internal", private.Routes())
|
||||
if setting.Packages.Enabled {
|
||||
r.Mount("/api/packages", packages_router.Routes())
|
||||
|
||||
@@ -31,9 +31,9 @@ func Packages(ctx *context.Context) {
|
||||
sort := ctx.FormTrim("sort")
|
||||
|
||||
pvs, total, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
|
||||
QueryName: query,
|
||||
Type: packageType,
|
||||
Sort: sort,
|
||||
Type: packages_model.Type(packageType),
|
||||
Name: packages_model.SearchValue{Value: query},
|
||||
Sort: sort,
|
||||
Paginator: &db.ListOptions{
|
||||
PageSize: setting.UI.PackagesPagingNum,
|
||||
Page: page,
|
||||
|
||||
@@ -345,7 +345,7 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
|
||||
ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)
|
||||
}
|
||||
|
||||
// Clear whatever CSRF has right now, force to generate a new one
|
||||
// Clear whatever CSRF cookie has right now, force to generate a new one
|
||||
middleware.DeleteCSRFCookie(ctx.Resp)
|
||||
|
||||
// Register last login
|
||||
|
||||
@@ -1010,7 +1010,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model
|
||||
log.Error("Error storing session: %v", err)
|
||||
}
|
||||
|
||||
// Clear whatever CSRF has right now, force to generate a new one
|
||||
// Clear whatever CSRF cookie has right now, force to generate a new one
|
||||
middleware.DeleteCSRFCookie(ctx.Resp)
|
||||
|
||||
// Register last login
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package explore
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// TopicSearch search for creating topic
|
||||
func TopicSearch(ctx *context.Context) {
|
||||
opts := &repo_model.FindTopicOptions{
|
||||
Keyword: ctx.FormString("q"),
|
||||
ListOptions: db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
|
||||
},
|
||||
}
|
||||
|
||||
topics, total, err := repo_model.FindTopics(opts)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
topicResponses := make([]*api.TopicResponse, len(topics))
|
||||
for i, topic := range topics {
|
||||
topicResponses[i] = convert.ToTopicResponse(topic)
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(total)
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"topics": topicResponses,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package misc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"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"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"mvdan.cc/xurls/v2"
|
||||
)
|
||||
|
||||
// Markdown render markdown document to HTML
|
||||
func Markdown(ctx *context.Context) {
|
||||
// swagger:operation POST /markdown miscellaneous renderMarkdown
|
||||
// ---
|
||||
// summary: Render a markdown document as HTML
|
||||
// parameters:
|
||||
// - name: body
|
||||
// in: body
|
||||
// schema:
|
||||
// "$ref": "#/definitions/MarkdownOption"
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
// - text/html
|
||||
// responses:
|
||||
// "200":
|
||||
// "$ref": "#/responses/MarkdownRender"
|
||||
// "422":
|
||||
// "$ref": "#/responses/validationError"
|
||||
|
||||
form := web.GetForm(ctx).(*api.MarkdownOption)
|
||||
|
||||
if ctx.HasAPIError() {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", ctx.GetErrMsg())
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.Text) == 0 {
|
||||
_, _ = ctx.Write([]byte(""))
|
||||
return
|
||||
}
|
||||
|
||||
switch form.Mode {
|
||||
case "comment":
|
||||
fallthrough
|
||||
case "gfm":
|
||||
urlPrefix := form.Context
|
||||
meta := map[string]string{}
|
||||
if !strings.HasPrefix(setting.AppSubURL+"/", urlPrefix) {
|
||||
// check if urlPrefix is already set to a URL
|
||||
linkRegex, _ := xurls.StrictMatchingScheme("https?://")
|
||||
m := linkRegex.FindStringIndex(urlPrefix)
|
||||
if m == nil {
|
||||
urlPrefix = util.URLJoin(setting.AppURL, form.Context)
|
||||
}
|
||||
}
|
||||
if ctx.Repo != nil && ctx.Repo.Repository != nil {
|
||||
// "gfm" = Github Flavored Markdown - set this to render as a document
|
||||
if form.Mode == "gfm" {
|
||||
meta = ctx.Repo.Repository.ComposeDocumentMetas()
|
||||
} else {
|
||||
meta = ctx.Repo.Repository.ComposeMetas()
|
||||
}
|
||||
}
|
||||
if form.Mode == "gfm" {
|
||||
meta["mode"] = "document"
|
||||
}
|
||||
|
||||
if err := markdown.Render(&markup.RenderContext{
|
||||
Ctx: ctx,
|
||||
URLPrefix: urlPrefix,
|
||||
Metas: meta,
|
||||
IsWiki: form.Wiki,
|
||||
}, strings.NewReader(form.Text), ctx.Resp); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
default:
|
||||
if err := markdown.RenderRaw(&markup.RenderContext{
|
||||
Ctx: ctx,
|
||||
URLPrefix: form.Context,
|
||||
}, strings.NewReader(form.Text), ctx.Resp); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
@@ -20,7 +21,9 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/routers/utils"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
@@ -329,6 +332,51 @@ func TeamRepositories(ctx *context.Context) {
|
||||
ctx.HTML(http.StatusOK, tplTeamRepositories)
|
||||
}
|
||||
|
||||
// SearchTeam api for searching teams
|
||||
func SearchTeam(ctx *context.Context) {
|
||||
listOptions := db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
|
||||
}
|
||||
|
||||
opts := &organization.SearchTeamOptions{
|
||||
UserID: ctx.Doer.ID,
|
||||
Keyword: ctx.FormTrim("q"),
|
||||
OrgID: ctx.Org.Organization.ID,
|
||||
IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"),
|
||||
ListOptions: listOptions,
|
||||
}
|
||||
|
||||
teams, maxResults, err := organization.SearchTeam(opts)
|
||||
if err != nil {
|
||||
log.Error("SearchTeam failed: %v", err)
|
||||
ctx.JSON(http.StatusInternalServerError, 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(http.StatusInternalServerError, map[string]interface{}{
|
||||
"ok": false,
|
||||
"error": "SearchTeam failed to get units",
|
||||
})
|
||||
return
|
||||
}
|
||||
apiTeams[i] = convert.ToTeam(teams[i])
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(maxResults)
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"ok": true,
|
||||
"data": apiTeams,
|
||||
})
|
||||
}
|
||||
|
||||
// EditTeam render team edit page
|
||||
func EditTeam(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Org.Organization.FullName
|
||||
|
||||
+390
-8
@@ -16,6 +16,7 @@ import (
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
@@ -36,6 +37,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/templates/vars"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/upload"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
@@ -401,7 +403,7 @@ func Issues(ctx *context.Context) {
|
||||
|
||||
var err error
|
||||
// Get milestones
|
||||
ctx.Data["Milestones"], _, err = models.GetMilestones(models.GetMilestonesOption{
|
||||
ctx.Data["Milestones"], _, err = issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
State: api.StateType(ctx.FormString("state")),
|
||||
})
|
||||
@@ -418,7 +420,7 @@ func Issues(ctx *context.Context) {
|
||||
// RetrieveRepoMilestonesAndAssignees find all the milestones and assignees of a repository
|
||||
func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.Repository) {
|
||||
var err error
|
||||
ctx.Data["OpenMilestones"], _, err = models.GetMilestones(models.GetMilestonesOption{
|
||||
ctx.Data["OpenMilestones"], _, err = issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||
RepoID: repo.ID,
|
||||
State: api.StateOpen,
|
||||
})
|
||||
@@ -426,7 +428,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R
|
||||
ctx.ServerError("GetMilestones", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["ClosedMilestones"], _, err = models.GetMilestones(models.GetMilestonesOption{
|
||||
ctx.Data["ClosedMilestones"], _, err = issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||
RepoID: repo.ID,
|
||||
State: api.StateClosed,
|
||||
})
|
||||
@@ -804,7 +806,7 @@ func NewIssue(ctx *context.Context) {
|
||||
|
||||
milestoneID := ctx.FormInt64("milestone")
|
||||
if milestoneID > 0 {
|
||||
milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, milestoneID)
|
||||
milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, milestoneID)
|
||||
if err != nil {
|
||||
log.Error("GetMilestoneByID: %d: %v", milestoneID, err)
|
||||
} else {
|
||||
@@ -913,7 +915,7 @@ func ValidateRepoMetas(ctx *context.Context, form forms.CreateIssueForm, isPull
|
||||
// Check milestone.
|
||||
milestoneID := form.MilestoneID
|
||||
if milestoneID > 0 {
|
||||
milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, milestoneID)
|
||||
milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, milestoneID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetMilestoneByID", err)
|
||||
return nil, nil, 0, 0
|
||||
@@ -1323,7 +1325,7 @@ func ViewIssue(ctx *context.Context) {
|
||||
ctx.ServerError("GetIssueByID", err)
|
||||
return
|
||||
}
|
||||
if err = otherIssue.LoadRepo(); err != nil {
|
||||
if err = otherIssue.LoadRepo(ctx); err != nil {
|
||||
ctx.ServerError("LoadRepo", err)
|
||||
return
|
||||
}
|
||||
@@ -1403,7 +1405,7 @@ func ViewIssue(ctx *context.Context) {
|
||||
ctx.ServerError("LoadMilestone", err)
|
||||
return
|
||||
}
|
||||
ghostMilestone := &models.Milestone{
|
||||
ghostMilestone := &issues_model.Milestone{
|
||||
ID: -1,
|
||||
Name: ctx.Tr("repo.issues.deleted_milestone"),
|
||||
}
|
||||
@@ -1762,6 +1764,20 @@ func getActionIssues(ctx *context.Context) []*models.Issue {
|
||||
return issues
|
||||
}
|
||||
|
||||
// GetIssueInfo get an issue of a repository
|
||||
func GetIssueInfo(ctx *context.Context) {
|
||||
issue, err := models.GetIssueWithAttrsByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
||||
if err != nil {
|
||||
if models.IsErrIssueNotExist(err) {
|
||||
ctx.Error(http.StatusNotFound)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
ctx.JSON(http.StatusOK, convert.ToAPIIssue(issue))
|
||||
}
|
||||
|
||||
// UpdateIssueTitle change issue's title
|
||||
func UpdateIssueTitle(ctx *context.Context) {
|
||||
issue := GetActionIssue(ctx)
|
||||
@@ -1856,6 +1872,40 @@ func UpdateIssueContent(ctx *context.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateIssueDeadline updates an issue deadline
|
||||
func UpdateIssueDeadline(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*api.EditDeadlineOption)
|
||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
|
||||
if err != nil {
|
||||
if models.IsErrIssueNotExist(err) {
|
||||
ctx.NotFound("GetIssueByIndex", err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
|
||||
ctx.Error(http.StatusForbidden, "", "Not repo writer")
|
||||
return
|
||||
}
|
||||
|
||||
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, time.Local)
|
||||
deadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
||||
}
|
||||
|
||||
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.Doer); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: &deadline})
|
||||
}
|
||||
|
||||
// UpdateIssueMilestone change issue's milestone
|
||||
func UpdateIssueMilestone(ctx *context.Context) {
|
||||
issues := getActionIssues(ctx)
|
||||
@@ -1944,7 +1994,7 @@ func UpdatePullReviewRequest(ctx *context.Context) {
|
||||
}
|
||||
|
||||
for _, issue := range issues {
|
||||
if err := issue.LoadRepo(); err != nil {
|
||||
if err := issue.LoadRepo(ctx); err != nil {
|
||||
ctx.ServerError("issue.LoadRepo", err)
|
||||
return
|
||||
}
|
||||
@@ -2052,6 +2102,338 @@ func UpdatePullReviewRequest(ctx *context.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// SearchIssues searches for issues across the repositories that the user has access to
|
||||
func SearchIssues(ctx *context.Context) {
|
||||
before, since, err := context.GetQueryBeforeSince(ctx)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var isClosed util.OptionalBool
|
||||
switch ctx.FormString("state") {
|
||||
case "closed":
|
||||
isClosed = util.OptionalBoolTrue
|
||||
case "all":
|
||||
isClosed = util.OptionalBoolNone
|
||||
default:
|
||||
isClosed = util.OptionalBoolFalse
|
||||
}
|
||||
|
||||
// find repos user can access (for issue search)
|
||||
opts := &models.SearchRepoOptions{
|
||||
Private: false,
|
||||
AllPublic: true,
|
||||
TopicOnly: false,
|
||||
Collaborate: util.OptionalBoolNone,
|
||||
// This needs to be a column that is not nil in fixtures or
|
||||
// MySQL will return different results when sorting by null in some cases
|
||||
OrderBy: db.SearchOrderByAlphabetically,
|
||||
Actor: ctx.Doer,
|
||||
}
|
||||
if ctx.IsSigned {
|
||||
opts.Private = true
|
||||
opts.AllLimited = true
|
||||
}
|
||||
if ctx.FormString("owner") != "" {
|
||||
owner, err := user_model.GetUserByName(ctx.FormString("owner"))
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.Error(http.StatusBadRequest, "Owner not found", err.Error())
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserByName", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
opts.OwnerID = owner.ID
|
||||
opts.AllLimited = false
|
||||
opts.AllPublic = false
|
||||
opts.Collaborate = util.OptionalBoolFalse
|
||||
}
|
||||
if ctx.FormString("team") != "" {
|
||||
if ctx.FormString("owner") == "" {
|
||||
ctx.Error(http.StatusBadRequest, "", "Owner organisation is required for filtering on team")
|
||||
return
|
||||
}
|
||||
team, err := organization.GetTeam(opts.OwnerID, ctx.FormString("team"))
|
||||
if err != nil {
|
||||
if organization.IsErrTeamNotExist(err) {
|
||||
ctx.Error(http.StatusBadRequest, "Team not found", err.Error())
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserByName", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
opts.TeamID = team.ID
|
||||
}
|
||||
|
||||
repoIDs, _, err := models.SearchRepositoryIDs(opts)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var issues []*models.Issue
|
||||
var filteredCount int64
|
||||
|
||||
keyword := ctx.FormTrim("q")
|
||||
if strings.IndexByte(keyword, 0) >= 0 {
|
||||
keyword = ""
|
||||
}
|
||||
var issueIDs []int64
|
||||
if len(keyword) > 0 && len(repoIDs) > 0 {
|
||||
if issueIDs, err = issue_indexer.SearchIssuesByKeyword(ctx, repoIDs, keyword); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "SearchIssuesByKeyword", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var isPull util.OptionalBool
|
||||
switch ctx.FormString("type") {
|
||||
case "pulls":
|
||||
isPull = util.OptionalBoolTrue
|
||||
case "issues":
|
||||
isPull = util.OptionalBoolFalse
|
||||
default:
|
||||
isPull = util.OptionalBoolNone
|
||||
}
|
||||
|
||||
labels := ctx.FormTrim("labels")
|
||||
var includedLabelNames []string
|
||||
if len(labels) > 0 {
|
||||
includedLabelNames = strings.Split(labels, ",")
|
||||
}
|
||||
|
||||
milestones := ctx.FormTrim("milestones")
|
||||
var includedMilestones []string
|
||||
if len(milestones) > 0 {
|
||||
includedMilestones = strings.Split(milestones, ",")
|
||||
}
|
||||
|
||||
// this api is also used in UI,
|
||||
// so the default limit is set to fit UI needs
|
||||
limit := ctx.FormInt("limit")
|
||||
if limit == 0 {
|
||||
limit = setting.UI.IssuePagingNum
|
||||
} else if limit > setting.API.MaxResponseItems {
|
||||
limit = setting.API.MaxResponseItems
|
||||
}
|
||||
|
||||
// Only fetch the issues if we either don't have a keyword or the search returned issues
|
||||
// This would otherwise return all issues if no issues were found by the search.
|
||||
if len(keyword) == 0 || len(issueIDs) > 0 || len(includedLabelNames) > 0 || len(includedMilestones) > 0 {
|
||||
issuesOpt := &models.IssuesOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: limit,
|
||||
},
|
||||
RepoIDs: repoIDs,
|
||||
IsClosed: isClosed,
|
||||
IssueIDs: issueIDs,
|
||||
IncludedLabelNames: includedLabelNames,
|
||||
IncludeMilestones: includedMilestones,
|
||||
SortType: "priorityrepo",
|
||||
PriorityRepoID: ctx.FormInt64("priority_repo_id"),
|
||||
IsPull: isPull,
|
||||
UpdatedBeforeUnix: before,
|
||||
UpdatedAfterUnix: since,
|
||||
}
|
||||
|
||||
ctxUserID := int64(0)
|
||||
if ctx.IsSigned {
|
||||
ctxUserID = ctx.Doer.ID
|
||||
}
|
||||
|
||||
// Filter for: Created by User, Assigned to User, Mentioning User, Review of User Requested
|
||||
if ctx.FormBool("created") {
|
||||
issuesOpt.PosterID = ctxUserID
|
||||
}
|
||||
if ctx.FormBool("assigned") {
|
||||
issuesOpt.AssigneeID = ctxUserID
|
||||
}
|
||||
if ctx.FormBool("mentioned") {
|
||||
issuesOpt.MentionedID = ctxUserID
|
||||
}
|
||||
if ctx.FormBool("review_requested") {
|
||||
issuesOpt.ReviewRequestedID = ctxUserID
|
||||
}
|
||||
|
||||
if issues, err = models.Issues(issuesOpt); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "Issues", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
issuesOpt.ListOptions = db.ListOptions{
|
||||
Page: -1,
|
||||
}
|
||||
if filteredCount, err = models.CountIssues(issuesOpt); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "CountIssues", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(filteredCount)
|
||||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues))
|
||||
}
|
||||
|
||||
func getUserIDForFilter(ctx *context.Context, queryName string) int64 {
|
||||
userName := ctx.FormString(queryName)
|
||||
if len(userName) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
user, err := user_model.GetUserByName(userName)
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.NotFound("", err)
|
||||
return 0
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return 0
|
||||
}
|
||||
|
||||
return user.ID
|
||||
}
|
||||
|
||||
// ListIssues list the issues of a repository
|
||||
func ListIssues(ctx *context.Context) {
|
||||
before, since, err := context.GetQueryBeforeSince(ctx)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusUnprocessableEntity, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var isClosed util.OptionalBool
|
||||
switch ctx.FormString("state") {
|
||||
case "closed":
|
||||
isClosed = util.OptionalBoolTrue
|
||||
case "all":
|
||||
isClosed = util.OptionalBoolNone
|
||||
default:
|
||||
isClosed = util.OptionalBoolFalse
|
||||
}
|
||||
|
||||
var issues []*models.Issue
|
||||
var filteredCount int64
|
||||
|
||||
keyword := ctx.FormTrim("q")
|
||||
if strings.IndexByte(keyword, 0) >= 0 {
|
||||
keyword = ""
|
||||
}
|
||||
var issueIDs []int64
|
||||
var labelIDs []int64
|
||||
if len(keyword) > 0 {
|
||||
issueIDs, err = issue_indexer.SearchIssuesByKeyword(ctx, []int64{ctx.Repo.Repository.ID}, keyword)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if splitted := strings.Split(ctx.FormString("labels"), ","); len(splitted) > 0 {
|
||||
labelIDs, err = models.GetLabelIDsInRepoByNames(ctx.Repo.Repository.ID, splitted)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var mileIDs []int64
|
||||
if part := strings.Split(ctx.FormString("milestones"), ","); len(part) > 0 {
|
||||
for i := range part {
|
||||
// uses names and fall back to ids
|
||||
// non existent milestones are discarded
|
||||
mile, err := issues_model.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, part[i])
|
||||
if err == nil {
|
||||
mileIDs = append(mileIDs, mile.ID)
|
||||
continue
|
||||
}
|
||||
if !issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
id, err := strconv.ParseInt(part[i], 10, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
mile, err = issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, id)
|
||||
if err == nil {
|
||||
mileIDs = append(mileIDs, mile.ID)
|
||||
continue
|
||||
}
|
||||
if issues_model.IsErrMilestoneNotExist(err) {
|
||||
continue
|
||||
}
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
listOptions := db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
|
||||
}
|
||||
|
||||
var isPull util.OptionalBool
|
||||
switch ctx.FormString("type") {
|
||||
case "pulls":
|
||||
isPull = util.OptionalBoolTrue
|
||||
case "issues":
|
||||
isPull = util.OptionalBoolFalse
|
||||
default:
|
||||
isPull = util.OptionalBoolNone
|
||||
}
|
||||
|
||||
// FIXME: we should be more efficient here
|
||||
createdByID := getUserIDForFilter(ctx, "created_by")
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
assignedByID := getUserIDForFilter(ctx, "assigned_by")
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
mentionedByID := getUserIDForFilter(ctx, "mentioned_by")
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
// Only fetch the issues if we either don't have a keyword or the search returned issues
|
||||
// This would otherwise return all issues if no issues were found by the search.
|
||||
if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
|
||||
issuesOpt := &models.IssuesOptions{
|
||||
ListOptions: listOptions,
|
||||
RepoIDs: []int64{ctx.Repo.Repository.ID},
|
||||
IsClosed: isClosed,
|
||||
IssueIDs: issueIDs,
|
||||
LabelIDs: labelIDs,
|
||||
MilestoneIDs: mileIDs,
|
||||
IsPull: isPull,
|
||||
UpdatedBeforeUnix: before,
|
||||
UpdatedAfterUnix: since,
|
||||
PosterID: createdByID,
|
||||
AssigneeID: assignedByID,
|
||||
MentionedID: mentionedByID,
|
||||
}
|
||||
|
||||
if issues, err = models.Issues(issuesOpt); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
issuesOpt.ListOptions = db.ListOptions{
|
||||
Page: -1,
|
||||
}
|
||||
if filteredCount, err = models.CountIssues(issuesOpt); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(filteredCount)
|
||||
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues))
|
||||
}
|
||||
|
||||
// UpdateIssueStatus change issue's status
|
||||
func UpdateIssueStatus(ctx *context.Context) {
|
||||
issues := getActionIssues(ctx)
|
||||
|
||||
@@ -29,7 +29,7 @@ func AddDependency(ctx *context.Context) {
|
||||
|
||||
depID := ctx.FormInt64("newDependency")
|
||||
|
||||
if err = issue.LoadRepo(); err != nil {
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
ctx.ServerError("LoadRepo", err)
|
||||
return
|
||||
}
|
||||
@@ -88,7 +88,7 @@ func RemoveDependency(ctx *context.Context) {
|
||||
|
||||
depID := ctx.FormInt64("removeDependencyID")
|
||||
|
||||
if err = issue.LoadRepo(); err != nil {
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
ctx.ServerError("LoadRepo", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -64,18 +64,18 @@ func CancelStopwatch(c *context.Context) {
|
||||
}
|
||||
|
||||
// GetActiveStopwatch is the middleware that sets .ActiveStopwatch on context
|
||||
func GetActiveStopwatch(c *context.Context) {
|
||||
if strings.HasPrefix(c.Req.URL.Path, "/api") {
|
||||
func GetActiveStopwatch(ctx *context.Context) {
|
||||
if strings.HasPrefix(ctx.Req.URL.Path, "/api") {
|
||||
return
|
||||
}
|
||||
|
||||
if !c.IsSigned {
|
||||
if !ctx.IsSigned {
|
||||
return
|
||||
}
|
||||
|
||||
_, sw, err := models.HasUserStopwatch(c.Doer.ID)
|
||||
_, sw, err := models.HasUserStopwatch(ctx.Doer.ID)
|
||||
if err != nil {
|
||||
c.ServerError("HasUserStopwatch", err)
|
||||
ctx.ServerError("HasUserStopwatch", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -85,15 +85,15 @@ func GetActiveStopwatch(c *context.Context) {
|
||||
|
||||
issue, err := models.GetIssueByID(sw.IssueID)
|
||||
if err != nil || issue == nil {
|
||||
c.ServerError("GetIssueByID", err)
|
||||
ctx.ServerError("GetIssueByID", err)
|
||||
return
|
||||
}
|
||||
if err = issue.LoadRepo(); err != nil {
|
||||
c.ServerError("LoadRepo", err)
|
||||
if err = issue.LoadRepo(ctx); err != nil {
|
||||
ctx.ServerError("LoadRepo", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["ActiveStopwatch"] = StopwatchTmplInfo{
|
||||
ctx.Data["ActiveStopwatch"] = StopwatchTmplInfo{
|
||||
issue.Link(),
|
||||
issue.Repo.FullName(),
|
||||
issue.Index,
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
@@ -38,7 +38,7 @@ func Milestones(ctx *context.Context) {
|
||||
ctx.Data["PageIsMilestones"] = true
|
||||
|
||||
isShowClosed := ctx.FormString("state") == "closed"
|
||||
stats, err := models.GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"id": ctx.Repo.Repository.ID}))
|
||||
stats, err := issues_model.GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"id": ctx.Repo.Repository.ID}))
|
||||
if err != nil {
|
||||
ctx.ServerError("MilestoneStats", err)
|
||||
return
|
||||
@@ -60,7 +60,7 @@ func Milestones(ctx *context.Context) {
|
||||
state = structs.StateClosed
|
||||
}
|
||||
|
||||
miles, total, err := models.GetMilestones(models.GetMilestonesOption{
|
||||
miles, total, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: page,
|
||||
PageSize: setting.UI.IssuePagingNum,
|
||||
@@ -143,7 +143,7 @@ func NewMilestonePost(ctx *context.Context) {
|
||||
}
|
||||
|
||||
deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location())
|
||||
if err = models.NewMilestone(&models.Milestone{
|
||||
if err = issues_model.NewMilestone(&issues_model.Milestone{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Name: form.Title,
|
||||
Content: form.Content,
|
||||
@@ -163,9 +163,9 @@ func EditMilestone(ctx *context.Context) {
|
||||
ctx.Data["PageIsMilestones"] = true
|
||||
ctx.Data["PageIsEditMilestone"] = true
|
||||
|
||||
m, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
|
||||
m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
|
||||
if err != nil {
|
||||
if models.IsErrMilestoneNotExist(err) {
|
||||
if issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.NotFound("", nil)
|
||||
} else {
|
||||
ctx.ServerError("GetMilestoneByRepoID", err)
|
||||
@@ -203,9 +203,9 @@ func EditMilestonePost(ctx *context.Context) {
|
||||
}
|
||||
|
||||
deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location())
|
||||
m, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
|
||||
m, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
|
||||
if err != nil {
|
||||
if models.IsErrMilestoneNotExist(err) {
|
||||
if issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.NotFound("", nil)
|
||||
} else {
|
||||
ctx.ServerError("GetMilestoneByRepoID", err)
|
||||
@@ -215,7 +215,7 @@ func EditMilestonePost(ctx *context.Context) {
|
||||
m.Name = form.Title
|
||||
m.Content = form.Content
|
||||
m.DeadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
||||
if err = models.UpdateMilestone(m, m.IsClosed); err != nil {
|
||||
if err = issues_model.UpdateMilestone(m, m.IsClosed); err != nil {
|
||||
ctx.ServerError("UpdateMilestone", err)
|
||||
return
|
||||
}
|
||||
@@ -237,8 +237,8 @@ func ChangeMilestoneStatus(ctx *context.Context) {
|
||||
}
|
||||
id := ctx.ParamsInt64(":id")
|
||||
|
||||
if err := models.ChangeMilestoneStatusByRepoIDAndID(ctx.Repo.Repository.ID, id, toClose); err != nil {
|
||||
if models.IsErrMilestoneNotExist(err) {
|
||||
if err := issues_model.ChangeMilestoneStatusByRepoIDAndID(ctx.Repo.Repository.ID, id, toClose); err != nil {
|
||||
if issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.NotFound("", err)
|
||||
} else {
|
||||
ctx.ServerError("ChangeMilestoneStatusByIDAndRepoID", err)
|
||||
@@ -250,7 +250,7 @@ func ChangeMilestoneStatus(ctx *context.Context) {
|
||||
|
||||
// DeleteMilestone delete a milestone
|
||||
func DeleteMilestone(ctx *context.Context) {
|
||||
if err := models.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil {
|
||||
if err := issues_model.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil {
|
||||
ctx.Flash.Error("DeleteMilestoneByRepoID: " + err.Error())
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("repo.milestones.deletion_success"))
|
||||
@@ -264,9 +264,9 @@ func DeleteMilestone(ctx *context.Context) {
|
||||
// MilestoneIssuesAndPulls lists all the issues and pull requests of the milestone
|
||||
func MilestoneIssuesAndPulls(ctx *context.Context) {
|
||||
milestoneID := ctx.ParamsInt64(":id")
|
||||
milestone, err := models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, milestoneID)
|
||||
milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, milestoneID)
|
||||
if err != nil {
|
||||
if models.IsErrMilestoneNotExist(err) {
|
||||
if issues_model.IsErrMilestoneNotExist(err) {
|
||||
ctx.NotFound("GetMilestoneByID", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -32,10 +32,10 @@ func Packages(ctx *context.Context) {
|
||||
PageSize: setting.UI.PackagesPagingNum,
|
||||
Page: page,
|
||||
},
|
||||
OwnerID: ctx.ContextUser.ID,
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
QueryName: query,
|
||||
Type: packageType,
|
||||
OwnerID: ctx.ContextUser.ID,
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
Type: packages.Type(packageType),
|
||||
Name: packages.SearchValue{Value: query},
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchLatestVersions", err)
|
||||
|
||||
@@ -266,7 +266,7 @@ func checkPullInfo(ctx *context.Context) *models.Issue {
|
||||
ctx.ServerError("LoadPoster", err)
|
||||
return nil
|
||||
}
|
||||
if err := issue.LoadRepo(); err != nil {
|
||||
if err := issue.LoadRepo(ctx); err != nil {
|
||||
ctx.ServerError("LoadRepo", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -20,11 +20,14 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
@@ -503,3 +506,112 @@ func InitiateDownload(ctx *context.Context) {
|
||||
"complete": completed,
|
||||
})
|
||||
}
|
||||
|
||||
// SearchRepo repositories via options
|
||||
func SearchRepo(ctx *context.Context) {
|
||||
opts := &models.SearchRepoOptions{
|
||||
ListOptions: db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
|
||||
},
|
||||
Actor: ctx.Doer,
|
||||
Keyword: ctx.FormTrim("q"),
|
||||
OwnerID: ctx.FormInt64("uid"),
|
||||
PriorityOwnerID: ctx.FormInt64("priority_owner_id"),
|
||||
TeamID: ctx.FormInt64("team_id"),
|
||||
TopicOnly: ctx.FormBool("topic"),
|
||||
Collaborate: util.OptionalBoolNone,
|
||||
Private: ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private")),
|
||||
Template: util.OptionalBoolNone,
|
||||
StarredByID: ctx.FormInt64("starredBy"),
|
||||
IncludeDescription: ctx.FormBool("includeDesc"),
|
||||
}
|
||||
|
||||
if ctx.FormString("template") != "" {
|
||||
opts.Template = util.OptionalBoolOf(ctx.FormBool("template"))
|
||||
}
|
||||
|
||||
if ctx.FormBool("exclusive") {
|
||||
opts.Collaborate = util.OptionalBoolFalse
|
||||
}
|
||||
|
||||
mode := ctx.FormString("mode")
|
||||
switch mode {
|
||||
case "source":
|
||||
opts.Fork = util.OptionalBoolFalse
|
||||
opts.Mirror = util.OptionalBoolFalse
|
||||
case "fork":
|
||||
opts.Fork = util.OptionalBoolTrue
|
||||
case "mirror":
|
||||
opts.Mirror = util.OptionalBoolTrue
|
||||
case "collaborative":
|
||||
opts.Mirror = util.OptionalBoolFalse
|
||||
opts.Collaborate = util.OptionalBoolTrue
|
||||
case "":
|
||||
default:
|
||||
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid search mode: \"%s\"", mode))
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.FormString("archived") != "" {
|
||||
opts.Archived = util.OptionalBoolOf(ctx.FormBool("archived"))
|
||||
}
|
||||
|
||||
if ctx.FormString("is_private") != "" {
|
||||
opts.IsPrivate = util.OptionalBoolOf(ctx.FormBool("is_private"))
|
||||
}
|
||||
|
||||
sortMode := ctx.FormString("sort")
|
||||
if len(sortMode) > 0 {
|
||||
sortOrder := ctx.FormString("order")
|
||||
if len(sortOrder) == 0 {
|
||||
sortOrder = "asc"
|
||||
}
|
||||
if searchModeMap, ok := context.SearchOrderByMap[sortOrder]; ok {
|
||||
if orderBy, ok := searchModeMap[sortMode]; ok {
|
||||
opts.OrderBy = orderBy
|
||||
} else {
|
||||
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid sort mode: \"%s\"", sortMode))
|
||||
return
|
||||
}
|
||||
} else {
|
||||
ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid sort order: \"%s\"", sortOrder))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
repos, count, err := models.SearchRepository(opts)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, api.SearchError{
|
||||
OK: false,
|
||||
Error: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
results := make([]*api.Repository, len(repos))
|
||||
for i, repo := range repos {
|
||||
if err = repo.GetOwner(ctx); err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, api.SearchError{
|
||||
OK: false,
|
||||
Error: err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
accessMode, err := models.AccessLevel(ctx.Doer, repo)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, api.SearchError{
|
||||
OK: false,
|
||||
Error: err.Error(),
|
||||
})
|
||||
}
|
||||
results[i] = convert.ToRepo(repo, accessMode)
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(count)
|
||||
ctx.JSON(http.StatusOK, api.SearchResults{
|
||||
OK: true,
|
||||
Data: results,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"code.gitea.io/gitea/models"
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
@@ -219,13 +220,13 @@ func Milestones(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
counts, err := models.CountMilestonesByRepoCondAndKw(userRepoCond, keyword, isShowClosed)
|
||||
counts, err := issues_model.CountMilestonesByRepoCondAndKw(userRepoCond, keyword, isShowClosed)
|
||||
if err != nil {
|
||||
ctx.ServerError("CountMilestonesByRepoIDs", err)
|
||||
return
|
||||
}
|
||||
|
||||
milestones, err := models.SearchMilestones(repoCond, page, isShowClosed, sortType, keyword)
|
||||
milestones, err := issues_model.SearchMilestones(repoCond, page, isShowClosed, sortType, keyword)
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchMilestones", err)
|
||||
return
|
||||
@@ -271,17 +272,17 @@ func Milestones(ctx *context.Context) {
|
||||
i++
|
||||
}
|
||||
|
||||
milestoneStats, err := models.GetMilestonesStatsByRepoCondAndKw(repoCond, keyword)
|
||||
milestoneStats, err := issues_model.GetMilestonesStatsByRepoCondAndKw(repoCond, keyword)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetMilestoneStats", err)
|
||||
return
|
||||
}
|
||||
|
||||
var totalMilestoneStats *models.MilestonesStats
|
||||
var totalMilestoneStats *issues_model.MilestonesStats
|
||||
if len(repoIDs) == 0 {
|
||||
totalMilestoneStats = milestoneStats
|
||||
} else {
|
||||
totalMilestoneStats, err = models.GetMilestonesStatsByRepoCondAndKw(userRepoCond, keyword)
|
||||
totalMilestoneStats, err = issues_model.GetMilestonesStatsByRepoCondAndKw(userRepoCond, keyword)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetMilestoneStats", err)
|
||||
return
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -191,3 +192,8 @@ func NotificationPurgePost(c *context.Context) {
|
||||
|
||||
c.Redirect(setting.AppSubURL+"/notifications", http.StatusSeeOther)
|
||||
}
|
||||
|
||||
// NewAvailable returns the notification counts
|
||||
func NewAvailable(ctx *context.APIContext) {
|
||||
ctx.JSON(http.StatusOK, api.NotificationCount{New: models.CountUnread(ctx.Doer)})
|
||||
}
|
||||
|
||||
@@ -43,9 +43,9 @@ func ListPackages(ctx *context.Context) {
|
||||
PageSize: setting.UI.PackagesPagingNum,
|
||||
Page: page,
|
||||
},
|
||||
OwnerID: ctx.ContextUser.ID,
|
||||
Type: packageType,
|
||||
QueryName: query,
|
||||
OwnerID: ctx.ContextUser.ID,
|
||||
Type: packages_model.Type(packageType),
|
||||
Name: packages_model.SearchValue{Value: query},
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchLatestVersions", err)
|
||||
@@ -219,9 +219,12 @@ func ListPackageVersions(ctx *context.Context) {
|
||||
}
|
||||
default:
|
||||
pvs, total, err = packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
|
||||
Paginator: pagination,
|
||||
PackageID: p.ID,
|
||||
QueryVersion: query,
|
||||
Paginator: pagination,
|
||||
PackageID: p.ID,
|
||||
Version: packages_model.SearchValue{
|
||||
ExactMatch: false,
|
||||
Value: query,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("SearchVersions", err)
|
||||
@@ -256,7 +259,8 @@ func PackageSettings(ctx *context.Context) {
|
||||
ctx.Data["PackageDescriptor"] = pd
|
||||
|
||||
repos, _, _ := models.GetUserRepositories(&models.SearchRepoOptions{
|
||||
Actor: pd.Owner,
|
||||
Actor: pd.Owner,
|
||||
Private: true,
|
||||
})
|
||||
ctx.Data["Repos"] = repos
|
||||
ctx.Data["CanWritePackages"] = ctx.Package.AccessMode >= perm.AccessModeWrite || ctx.IsUserSiteAdmin()
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
)
|
||||
|
||||
// Search search users
|
||||
func Search(ctx *context.Context) {
|
||||
listOptions := db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
|
||||
}
|
||||
|
||||
users, maxResults, err := user_model.SearchUsers(&user_model.SearchUserOptions{
|
||||
Actor: ctx.Doer,
|
||||
Keyword: ctx.FormTrim("q"),
|
||||
UID: ctx.FormInt64("uid"),
|
||||
Type: user_model.UserTypeIndividual,
|
||||
ListOptions: listOptions,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
|
||||
"ok": false,
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(maxResults)
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"ok": true,
|
||||
"data": convert.ToUsers(ctx.Doer, users),
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
)
|
||||
|
||||
// GetStopwatches get all stopwatches
|
||||
func GetStopwatches(ctx *context.Context) {
|
||||
sws, err := models.GetUserStopwatches(ctx.Doer.ID, db.ListOptions{
|
||||
Page: ctx.FormInt("page"),
|
||||
PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")),
|
||||
})
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
count, err := models.CountUserStopwatches(ctx.Doer.ID)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
apiSWs, err := convert.ToStopWatches(sws)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(count)
|
||||
ctx.JSON(http.StatusOK, apiSWs)
|
||||
}
|
||||
+31
-4
@@ -20,17 +20,18 @@ import (
|
||||
"code.gitea.io/gitea/modules/public"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/validation"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/modules/web/routing"
|
||||
"code.gitea.io/gitea/routers/api/v1/misc"
|
||||
"code.gitea.io/gitea/routers/web/admin"
|
||||
"code.gitea.io/gitea/routers/web/auth"
|
||||
"code.gitea.io/gitea/routers/web/dev"
|
||||
"code.gitea.io/gitea/routers/web/events"
|
||||
"code.gitea.io/gitea/routers/web/explore"
|
||||
"code.gitea.io/gitea/routers/web/feed"
|
||||
"code.gitea.io/gitea/routers/web/misc"
|
||||
"code.gitea.io/gitea/routers/web/org"
|
||||
"code.gitea.io/gitea/routers/web/repo"
|
||||
"code.gitea.io/gitea/routers/web/user"
|
||||
@@ -45,6 +46,7 @@ import (
|
||||
_ "code.gitea.io/gitea/modules/session" // to registers all internal adapters
|
||||
|
||||
"gitea.com/go-chi/captcha"
|
||||
"gitea.com/go-chi/session"
|
||||
"github.com/NYTimes/gziphandler"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
@@ -84,7 +86,7 @@ func buildAuthGroup() *auth_service.Group {
|
||||
group := auth_service.NewGroup(
|
||||
&auth_service.OAuth2{}, // FIXME: this should be removed and only applied in download and oauth realted routers
|
||||
&auth_service.Basic{}, // FIXME: this should be removed and only applied in download and git/lfs routers
|
||||
auth_service.SharedSession,
|
||||
&auth_service.Session{},
|
||||
)
|
||||
if setting.Service.EnableReverseProxyAuth {
|
||||
group.Add(&auth_service.ReverseProxy{})
|
||||
@@ -95,7 +97,7 @@ func buildAuthGroup() *auth_service.Group {
|
||||
}
|
||||
|
||||
// Routes returns all web routes
|
||||
func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||
func Routes() *web.Route {
|
||||
routes := web.NewRoute()
|
||||
|
||||
routes.Use(web.WrapWithPrefix(public.AssetsURLPathPrefix, public.AssetsHandlerFunc(&public.Options{
|
||||
@@ -104,6 +106,17 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||
CorsHandler: CorsHandler(),
|
||||
}), "AssetsHandler"))
|
||||
|
||||
sessioner := session.Sessioner(session.Options{
|
||||
Provider: setting.SessionConfig.Provider,
|
||||
ProviderConfig: setting.SessionConfig.ProviderConfig,
|
||||
CookieName: setting.SessionConfig.CookieName,
|
||||
CookiePath: setting.SessionConfig.CookiePath,
|
||||
Gclifetime: setting.SessionConfig.Gclifetime,
|
||||
Maxlifetime: setting.SessionConfig.Maxlifetime,
|
||||
Secure: setting.SessionConfig.Secure,
|
||||
SameSite: setting.SessionConfig.SameSite,
|
||||
Domain: setting.SessionConfig.Domain,
|
||||
})
|
||||
routes.Use(sessioner)
|
||||
|
||||
routes.Use(Recovery())
|
||||
@@ -289,8 +302,13 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Get("/users", explore.Users)
|
||||
m.Get("/organizations", explore.Organizations)
|
||||
m.Get("/code", explore.Code)
|
||||
m.Get("/topics/search", explore.TopicSearch)
|
||||
}, ignExploreSignIn)
|
||||
m.Get("/issues", reqSignIn, user.Issues)
|
||||
m.Group("/issues", func() {
|
||||
m.Get("", user.Issues)
|
||||
m.Get("/search", repo.SearchIssues)
|
||||
}, reqSignIn)
|
||||
|
||||
m.Get("/pulls", reqSignIn, user.Pulls)
|
||||
m.Get("/milestones", reqSignIn, reqMilestonesDashboardPageEnabled, user.Milestones)
|
||||
|
||||
@@ -421,6 +439,8 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Post("/forgot_password", auth.ForgotPasswdPost)
|
||||
m.Post("/logout", auth.SignOut)
|
||||
m.Get("/task/{task}", user.TaskStatus)
|
||||
m.Get("/stopwatches", user.GetStopwatches, reqSignIn)
|
||||
m.Get("/search", user.Search, ignExploreSignIn)
|
||||
})
|
||||
// ***** END: User *****
|
||||
|
||||
@@ -605,6 +625,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Group("/{org}", func() {
|
||||
m.Get("/teams/new", org.NewTeam)
|
||||
m.Post("/teams/new", bindIgnErr(forms.CreateTeamForm{}), org.NewTeamPost)
|
||||
m.Get("/teams/-/search", org.SearchTeam)
|
||||
m.Get("/teams/{team}/edit", org.EditTeam)
|
||||
m.Post("/teams/{team}/edit", bindIgnErr(forms.CreateTeamForm{}), org.EditTeamPost)
|
||||
m.Post("/teams/{team}/delete", org.DeleteTeam)
|
||||
@@ -669,6 +690,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Combo("/{repoid}").Get(repo.Fork).
|
||||
Post(bindIgnErr(forms.CreateRepoForm{}), repo.ForkPost)
|
||||
}, context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader)
|
||||
m.Get("/search", repo.SearchRepo)
|
||||
}, reqSignIn)
|
||||
|
||||
m.Group("/{username}/-", func() {
|
||||
@@ -811,13 +833,16 @@ func RegisterRoutes(m *web.Route) {
|
||||
Post(bindIgnErr(forms.CreateIssueForm{}), repo.NewIssuePost)
|
||||
m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate)
|
||||
})
|
||||
m.Get("/search", repo.ListIssues)
|
||||
}, context.RepoMustNotBeArchived(), reqRepoIssueReader)
|
||||
// FIXME: should use different URLs but mostly same logic for comments of issue and pull request.
|
||||
// So they can apply their own enable/disable logic on routers.
|
||||
m.Group("/{type:issues|pulls}", func() {
|
||||
m.Group("/{index}", func() {
|
||||
m.Get("/info", repo.GetIssueInfo)
|
||||
m.Post("/title", repo.UpdateIssueTitle)
|
||||
m.Post("/content", repo.UpdateIssueContent)
|
||||
m.Post("/deadline", bindIgnErr(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline)
|
||||
m.Post("/watch", repo.IssueWatch)
|
||||
m.Post("/ref", repo.UpdateIssueRef)
|
||||
m.Group("/dependency", func() {
|
||||
@@ -865,6 +890,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Group("/comments/{id}", func() {
|
||||
m.Get("/attachments", repo.GetCommentAttachments)
|
||||
})
|
||||
m.Post("/markdown", bindIgnErr(structs.MarkdownOption{}), misc.Markdown)
|
||||
m.Group("/labels", func() {
|
||||
m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), repo.NewLabel)
|
||||
m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), repo.UpdateLabel)
|
||||
@@ -1195,6 +1221,7 @@ func RegisterRoutes(m *web.Route) {
|
||||
m.Get("", user.Notifications)
|
||||
m.Post("/status", user.NotificationStatusPost)
|
||||
m.Post("/purge", user.NotificationPurgePost)
|
||||
m.Get("/new", user.NewAvailable)
|
||||
}, reqSignIn)
|
||||
|
||||
if setting.API.EnableSwagger {
|
||||
|
||||
Reference in New Issue
Block a user