mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-03 08:02:36 +09:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d876ab1c8 | ||
|
|
f58715d903 | ||
|
|
81072af8ce | ||
|
|
1d7a855d66 | ||
|
|
3c8842d58c | ||
|
|
e786f098d5 | ||
|
|
22dec1cea6 | ||
|
|
0c5e2e2e4c | ||
|
|
158b716387 | ||
|
|
e611dbbe86 | ||
|
|
68bca621cd | ||
|
|
c4e0f717e7 | ||
|
|
e3e024876e | ||
|
|
cebc125f7f | ||
|
|
c975287149 | ||
|
|
b31068652a | ||
|
|
918e640590 | ||
|
|
9809fe27c4 | ||
|
|
ed6a2f2e2e | ||
|
|
a0435fcd63 | ||
|
|
a2e2045a96 | ||
|
|
b67a023bec | ||
|
|
b1a90f7286 | ||
|
|
45c8a3aeeb | ||
|
|
0e5126da22 | ||
|
|
cd3e52d91b | ||
|
|
319c92163f | ||
|
|
a15a644c05 |
@@ -1,44 +1,44 @@
|
|||||||
repo: go-gitea/gitea
|
repo: go-gitea/gitea
|
||||||
groups:
|
groups:
|
||||||
-
|
-
|
||||||
name: BREAKING
|
name: BREAKING
|
||||||
labels:
|
labels:
|
||||||
- kind/breaking
|
- kind/breaking
|
||||||
-
|
-
|
||||||
name: FEATURE
|
name: FEATURE
|
||||||
labels:
|
labels:
|
||||||
- kind/feature
|
- kind/feature
|
||||||
|
-
|
||||||
|
name: SECURITY
|
||||||
|
labels:
|
||||||
|
- kind/security
|
||||||
-
|
-
|
||||||
name: BUGFIXES
|
name: BUGFIXES
|
||||||
labels:
|
labels:
|
||||||
- kind/bug
|
- kind/bug
|
||||||
-
|
-
|
||||||
name: ENHANCEMENT
|
name: ENHANCEMENT
|
||||||
labels:
|
labels:
|
||||||
- kind/enhancement
|
- kind/enhancement
|
||||||
- kind/refactor
|
- kind/refactor
|
||||||
- kind/ui
|
- kind/ui
|
||||||
-
|
-
|
||||||
name: SECURITY
|
|
||||||
labels:
|
|
||||||
- kind/security
|
|
||||||
-
|
|
||||||
name: TESTING
|
name: TESTING
|
||||||
labels:
|
labels:
|
||||||
- kind/testing
|
- kind/testing
|
||||||
-
|
-
|
||||||
name: TRANSLATION
|
name: TRANSLATION
|
||||||
labels:
|
labels:
|
||||||
- kind/translation
|
- kind/translation
|
||||||
-
|
-
|
||||||
name: BUILD
|
name: BUILD
|
||||||
labels:
|
labels:
|
||||||
- kind/build
|
- kind/build
|
||||||
- kind/lint
|
- kind/lint
|
||||||
-
|
-
|
||||||
name: DOCS
|
name: DOCS
|
||||||
labels:
|
labels:
|
||||||
- kind/docs
|
- kind/docs
|
||||||
-
|
-
|
||||||
name: MISC
|
name: MISC
|
||||||
default: true
|
default: true
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ services:
|
|||||||
image: postgres:9.5
|
image: postgres:9.5
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: test
|
POSTGRES_DB: test
|
||||||
|
POSTGRES_PASSWORD: postgres
|
||||||
|
|
||||||
- name: mssql
|
- name: mssql
|
||||||
pull: default
|
pull: default
|
||||||
@@ -388,7 +389,7 @@ steps:
|
|||||||
|
|
||||||
- name: static
|
- name: static
|
||||||
pull: always
|
pull: always
|
||||||
image: techknowlogick/xgo:latest
|
image: techknowlogick/xgo:go-1.13.x
|
||||||
commands:
|
commands:
|
||||||
- export PATH=$PATH:$GOPATH/bin
|
- export PATH=$PATH:$GOPATH/bin
|
||||||
- make generate
|
- make generate
|
||||||
@@ -490,7 +491,7 @@ steps:
|
|||||||
|
|
||||||
- name: static
|
- name: static
|
||||||
pull: always
|
pull: always
|
||||||
image: techknowlogick/xgo:latest
|
image: techknowlogick/xgo:go-1.13.x
|
||||||
commands:
|
commands:
|
||||||
- export PATH=$PATH:$GOPATH/bin
|
- export PATH=$PATH:$GOPATH/bin
|
||||||
- make generate
|
- make generate
|
||||||
|
|||||||
46
CHANGELOG.md
46
CHANGELOG.md
@@ -4,6 +4,48 @@ This changelog goes through all the changes that have been made in each release
|
|||||||
without substantial changes to our git log; to see the highlights of what has
|
without substantial changes to our git log; to see the highlights of what has
|
||||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||||
|
|
||||||
|
## [1.10.6](https://github.com/go-gitea/gitea/releases/tag/v1.10.6) - 2020-03-10
|
||||||
|
|
||||||
|
This is a re-tag version of v1.10.5 and also explicitly built with Go 1.13.
|
||||||
|
|
||||||
|
WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be used.
|
||||||
|
|
||||||
|
## [1.10.5](https://github.com/go-gitea/gitea/releases/tag/v1.10.5) - 2020-03-06
|
||||||
|
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix release attachments being deleted while upgrading (#10572) (#10574)
|
||||||
|
|
||||||
|
## [1.10.4](https://github.com/go-gitea/gitea/releases/tag/v1.10.4) - 2020-02-16
|
||||||
|
|
||||||
|
* FEATURE
|
||||||
|
* Prevent empty LDAP search from deactivating all users (#9879) (#9890)
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix reply on code review (#10261) (#10227)
|
||||||
|
* Fix branch page pull request title and link error (#10092) (#10098)
|
||||||
|
* Fix milestone API state parameter unhandled (#10049) (#10053)
|
||||||
|
* Fix wiki raw view on sub path (#10002) (#10041)
|
||||||
|
* Fix RocketChat Webhook (#9908) (#9921) (#9925)
|
||||||
|
* Fix bug about wrong dependencies permissions check and other wrong permissions check (#9884) (Partial backport #9842)
|
||||||
|
* Ensure that 2fa is checked on reset-password (#9857) (#9877)
|
||||||
|
|
||||||
|
## [1.10.3](https://github.com/go-gitea/gitea/releases/tag/v1.10.3) - 2020-01-17
|
||||||
|
* SECURITY
|
||||||
|
* Hide credentials when submitting migration (#9102) (#9704)
|
||||||
|
* Never allow an empty password to validate (#9682) (#9684)
|
||||||
|
* Prevent redirect to Host (#9678) (#9680)
|
||||||
|
* Hide public repos owned by private orgs (#9609) (#9616)
|
||||||
|
* BUGFIXES
|
||||||
|
* Allow assignee on Pull Creation when Issue Unit is deactivated (#9836) (#9838)
|
||||||
|
* Fix download file wrong content-type (#9825) (#9835)
|
||||||
|
* Fix wrong identify poster on a migrated pull request when submit review (#9827) (#9831)
|
||||||
|
* Fix dump non-exist log directory (#9818) (#9820)
|
||||||
|
* Fix compare (#9808) (#9815)
|
||||||
|
* Fix missing msteam webhook on organization (#9781) (#9795)
|
||||||
|
* Fix add team on collaborator page when same name as organization (#9783)
|
||||||
|
* Fix cache problem on dashboard (#9358) (#9703)
|
||||||
|
* Send tag create and push webhook when release created on UI (#8671) (#9702)
|
||||||
|
* Branches not at ref commit ID should not be listed as Merged (#9614) (#9639)
|
||||||
|
|
||||||
## [1.10.2](https://github.com/go-gitea/gitea/releases/tag/v1.10.2) - 2020-01-02
|
## [1.10.2](https://github.com/go-gitea/gitea/releases/tag/v1.10.2) - 2020-01-02
|
||||||
* BUGFIXES
|
* BUGFIXES
|
||||||
* Allow only specific Columns to be updated on Issue via API (#9539) (#9580)
|
* Allow only specific Columns to be updated on Issue via API (#9539) (#9580)
|
||||||
@@ -68,7 +110,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
|||||||
* Add option to initialize repository with labels (#6061)
|
* Add option to initialize repository with labels (#6061)
|
||||||
* Add additional password hash algorithms (#6023)
|
* Add additional password hash algorithms (#6023)
|
||||||
* BUGFIXES
|
* BUGFIXES
|
||||||
* Allow to merge if file path contains " or \ (#8629) (#8771)
|
* Allow to merge if file path contains " or \ (#8629) (#8771)
|
||||||
* On windows set core.longpaths true (#8776) (#8786)
|
* On windows set core.longpaths true (#8776) (#8786)
|
||||||
* Fix 500 when edit hook (#8782) (#8789)
|
* Fix 500 when edit hook (#8782) (#8789)
|
||||||
* Fix Checkbox at RepoSettings Protected Branch (#8799) (#8801)
|
* Fix Checkbox at RepoSettings Protected Branch (#8799) (#8801)
|
||||||
@@ -80,7 +122,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
|||||||
* Fix require external registration password (#8885) (#8890)
|
* Fix require external registration password (#8885) (#8890)
|
||||||
* Fix password complexity check on registration (#8887) (#8888)
|
* Fix password complexity check on registration (#8887) (#8888)
|
||||||
* Update Github Migration Tests (#8896) (#8938) (#8945)
|
* Update Github Migration Tests (#8896) (#8938) (#8945)
|
||||||
* Enable punctuations ending mentions (#8889) (#8894)
|
* Enable punctuations ending mentions (#8889) (#8894)
|
||||||
* Add Close() method to gogitRepository (#8901) (#8956)
|
* Add Close() method to gogitRepository (#8901) (#8956)
|
||||||
* Hotfix for review actions and notifications (#8965)
|
* Hotfix for review actions and notifications (#8965)
|
||||||
* Expose db.SetMaxOpenConns and allow non MySQL dbs to set conn pool params (#8528) (#8618)
|
* Expose db.SetMaxOpenConns and allow non MySQL dbs to set conn pool params (#8528) (#8618)
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ var (
|
|||||||
Name: "admin-filter",
|
Name: "admin-filter",
|
||||||
Usage: "An LDAP filter specifying if a user should be given administrator privileges.",
|
Usage: "An LDAP filter specifying if a user should be given administrator privileges.",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "allow-deactivate-all",
|
||||||
|
Usage: "Allow empty search results to deactivate all users.",
|
||||||
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "username-attribute",
|
Name: "username-attribute",
|
||||||
Usage: "The attribute of the user’s LDAP record containing the user name.",
|
Usage: "The attribute of the user’s LDAP record containing the user name.",
|
||||||
@@ -231,6 +235,9 @@ func parseLdapConfig(c *cli.Context, config *models.LDAPConfig) error {
|
|||||||
if c.IsSet("admin-filter") {
|
if c.IsSet("admin-filter") {
|
||||||
config.Source.AdminFilter = c.String("admin-filter")
|
config.Source.AdminFilter = c.String("admin-filter")
|
||||||
}
|
}
|
||||||
|
if c.IsSet("allow-deactivate-all") {
|
||||||
|
config.Source.AllowDeactivateAll = c.Bool("allow-deactivate-all")
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,8 +145,10 @@ func runDump(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := z.AddDir("log", setting.LogRootPath); err != nil {
|
if com.IsExist(setting.LogRootPath) {
|
||||||
log.Fatalf("Failed to include log: %v", err)
|
if err := z.AddDir("log", setting.LogRootPath); err != nil {
|
||||||
|
log.Fatalf("Failed to include log: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = z.Close(); err != nil {
|
if err = z.Close(); err != nil {
|
||||||
|
|||||||
47
integrations/api_issue_milestone_test.go
Normal file
47
integrations/api_issue_milestone_test.go
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2020 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 integrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
|
"code.gitea.io/gitea/modules/structs"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAPIIssuesMilestone(t *testing.T) {
|
||||||
|
prepareTestEnv(t)
|
||||||
|
|
||||||
|
milestone := models.AssertExistsAndLoadBean(t, &models.Milestone{ID: 1}).(*models.Milestone)
|
||||||
|
repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: milestone.RepoID}).(*models.Repository)
|
||||||
|
owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
|
||||||
|
assert.Equal(t, int64(1), int64(milestone.NumIssues))
|
||||||
|
assert.Equal(t, structs.StateOpen, milestone.State())
|
||||||
|
|
||||||
|
session := loginUser(t, owner.Name)
|
||||||
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
|
||||||
|
// update values of issue
|
||||||
|
milestoneState := "closed"
|
||||||
|
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/milestones/%d?token=%s", owner.Name, repo.Name, milestone.ID, token)
|
||||||
|
req := NewRequestWithJSON(t, "PATCH", urlStr, structs.EditMilestoneOption{
|
||||||
|
State: &milestoneState,
|
||||||
|
})
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
var apiMilestone structs.Milestone
|
||||||
|
DecodeJSON(t, resp, &apiMilestone)
|
||||||
|
assert.EqualValues(t, "closed", apiMilestone.State)
|
||||||
|
|
||||||
|
req = NewRequest(t, "GET", urlStr)
|
||||||
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
var apiMilestone2 structs.Milestone
|
||||||
|
DecodeJSON(t, resp, &apiMilestone2)
|
||||||
|
assert.EqualValues(t, "closed", apiMilestone2.State)
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
4a357436d925b5c974181ff12a994538ddc5a269
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
|||||||
0cf15c3f66ec8384480ed9c3cf87c9e97fbb0ec3
|
423313fbd38093bb10d0c8387db9105409c6f196
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ func (issue *Issue) HashTag() string {
|
|||||||
|
|
||||||
// IsPoster returns true if given user by ID is the poster.
|
// IsPoster returns true if given user by ID is the poster.
|
||||||
func (issue *Issue) IsPoster(uid int64) bool {
|
func (issue *Issue) IsPoster(uid int64) bool {
|
||||||
return issue.PosterID == uid
|
return issue.OriginalAuthorID == 0 && issue.PosterID == uid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (issue *Issue) hasLabel(e Engine, labelID int64) bool {
|
func (issue *Issue) hasLabel(e Engine, labelID int64) bool {
|
||||||
|
|||||||
@@ -253,12 +253,33 @@ func updateMilestone(e Engine, m *Milestone) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateMilestone updates information of given milestone.
|
// UpdateMilestone updates information of given milestone.
|
||||||
func UpdateMilestone(m *Milestone) error {
|
func UpdateMilestone(m *Milestone, oldIsClosed bool) error {
|
||||||
if err := updateMilestone(x, m); err != nil {
|
sess := x.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
if err := sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateMilestoneCompleteness(x, m.ID)
|
if m.IsClosed && !oldIsClosed {
|
||||||
|
m.ClosedDateUnix = timeutil.TimeStampNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := updateMilestone(sess, m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := updateMilestoneCompleteness(sess, m.ID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if IsClosed changed, update milestone numbers of repository
|
||||||
|
if oldIsClosed != m.IsClosed {
|
||||||
|
if err := updateRepoMilestoneNum(sess, m.RepoID); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateMilestoneCompleteness(e Engine, milestoneID int64) error {
|
func updateMilestoneCompleteness(e Engine, milestoneID int64) error {
|
||||||
|
|||||||
@@ -160,8 +160,9 @@ func TestUpdateMilestone(t *testing.T) {
|
|||||||
milestone := AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone)
|
milestone := AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone)
|
||||||
milestone.Name = "newMilestoneName"
|
milestone.Name = "newMilestoneName"
|
||||||
milestone.Content = "newMilestoneContent"
|
milestone.Content = "newMilestoneContent"
|
||||||
assert.NoError(t, UpdateMilestone(milestone))
|
assert.NoError(t, UpdateMilestone(milestone, milestone.IsClosed))
|
||||||
AssertExistsAndLoadBean(t, milestone)
|
milestone = AssertExistsAndLoadBean(t, &Milestone{ID: 1}).(*Milestone)
|
||||||
|
assert.EqualValues(t, "newMilestoneName", milestone.Name)
|
||||||
CheckConsistencyFor(t, &Milestone{})
|
CheckConsistencyFor(t, &Milestone{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,23 +26,38 @@ func deleteOrphanedAttachments(x *xorm.Engine) error {
|
|||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
|
|
||||||
err := sess.BufferSize(setting.Database.IterateBufferSize).
|
var limit = setting.Database.IterateBufferSize
|
||||||
Where("`issue_id` = 0 and (`release_id` = 0 or `release_id` not in (select `id` from `release`))").Cols("uuid").
|
if limit <= 0 {
|
||||||
Iterate(new(Attachment),
|
limit = 50
|
||||||
func(idx int, bean interface{}) error {
|
|
||||||
attachment := bean.(*Attachment)
|
|
||||||
|
|
||||||
if err := os.RemoveAll(models.AttachmentLocalPath(attachment.UUID)); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := sess.ID(attachment.ID).NoAutoCondition().Delete(attachment)
|
|
||||||
return err
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sess.Commit()
|
for {
|
||||||
|
attachements := make([]Attachment, 0, limit)
|
||||||
|
if err := sess.Where("`issue_id` = 0 and (`release_id` = 0 or `release_id` not in (select `id` from `release`))").
|
||||||
|
Cols("id, uuid").Limit(limit).
|
||||||
|
Asc("id").
|
||||||
|
Find(&attachements); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(attachements) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var ids = make([]int64, 0, limit)
|
||||||
|
for _, attachment := range attachements {
|
||||||
|
ids = append(ids, attachment.ID)
|
||||||
|
}
|
||||||
|
if _, err := sess.In("id", ids).Delete(new(Attachment)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attachment := range attachements {
|
||||||
|
if err := os.RemoveAll(models.AttachmentLocalPath(attachment.UUID)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(attachements) < limit {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ func (pr *PullRequest) LoadHeadRepo() error {
|
|||||||
if has, err := x.ID(pr.HeadRepoID).Get(&repo); err != nil {
|
if has, err := x.ID(pr.HeadRepoID).Get(&repo); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
return ErrRepoNotExist{ID: pr.BaseRepoID}
|
return ErrRepoNotExist{ID: pr.HeadRepoID}
|
||||||
}
|
}
|
||||||
pr.HeadRepo = &repo
|
pr.HeadRepo = &repo
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,8 @@ type SearchRepoOptions struct {
|
|||||||
StarredByID int64
|
StarredByID int64
|
||||||
Page int
|
Page int
|
||||||
IsProfile bool
|
IsProfile bool
|
||||||
AllPublic bool // Include also all public repositories
|
AllPublic bool // Include also all public repositories of users and public organisations
|
||||||
|
AllLimited bool // Include also all public repositories of limited organisations
|
||||||
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
|
PageSize int // Can be smaller than or equal to setting.ExplorePagingNum
|
||||||
// None -> include collaborative AND non-collaborative
|
// None -> include collaborative AND non-collaborative
|
||||||
// True -> include just collaborative
|
// True -> include just collaborative
|
||||||
@@ -240,7 +241,11 @@ func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.AllPublic {
|
if opts.AllPublic {
|
||||||
accessCond = accessCond.Or(builder.Eq{"is_private": false})
|
accessCond = accessCond.Or(builder.Eq{"is_private": false}.And(builder.In("owner_id", builder.Select("`user`.id").From("`user`").Where(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}))))
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.AllLimited {
|
||||||
|
accessCond = accessCond.Or(builder.Eq{"is_private": false}.And(builder.In("owner_id", builder.Select("`user`.id").From("`user`").Where(builder.Eq{"`user`.visibility": structs.VisibleTypeLimited}))))
|
||||||
}
|
}
|
||||||
|
|
||||||
cond = cond.And(accessCond)
|
cond = cond.And(accessCond)
|
||||||
|
|||||||
@@ -177,8 +177,8 @@ func TestSearchRepository(t *testing.T) {
|
|||||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, AllPublic: true},
|
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, AllPublic: true},
|
||||||
count: 22},
|
count: 22},
|
||||||
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
|
||||||
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
|
opts: &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true},
|
||||||
count: 28},
|
count: 27},
|
||||||
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
|
{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
|
||||||
opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
|
opts: &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
|
||||||
count: 15},
|
count: 15},
|
||||||
|
|||||||
@@ -502,7 +502,7 @@ func (u *User) ValidatePassword(passwd string) bool {
|
|||||||
|
|
||||||
// IsPasswordSet checks if the password is set or left empty
|
// IsPasswordSet checks if the password is set or left empty
|
||||||
func (u *User) IsPasswordSet() bool {
|
func (u *User) IsPasswordSet() bool {
|
||||||
return len(u.Passwd) > 0
|
return !u.ValidatePassword("")
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadAvatar saves custom avatar for user.
|
// UploadAvatar saves custom avatar for user.
|
||||||
@@ -1715,6 +1715,15 @@ func SyncExternalUsers() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(sr) == 0 {
|
||||||
|
if !s.LDAP().AllowDeactivateAll {
|
||||||
|
log.Error("LDAP search found no entries but did not report an error. Refusing to deactivate all users")
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
log.Warn("LDAP search found no entries but did not report an error. All users will be deactivated as per settings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, su := range sr {
|
for _, su := range sr {
|
||||||
if len(su.Username) == 0 {
|
if len(su.Username) == 0 {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -283,8 +283,10 @@ func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, e
|
|||||||
Username: slack.Username,
|
Username: slack.Username,
|
||||||
IconURL: slack.IconURL,
|
IconURL: slack.IconURL,
|
||||||
Attachments: []SlackAttachment{{
|
Attachments: []SlackAttachment{{
|
||||||
Color: slack.Color,
|
Color: slack.Color,
|
||||||
Text: attachmentText,
|
Title: p.Repo.HTMLURL,
|
||||||
|
TitleLink: p.Repo.HTMLURL,
|
||||||
|
Text: attachmentText,
|
||||||
}},
|
}},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -380,12 +382,11 @@ func getSlackPullRequestApprovalPayload(p *api.PullRequestPayload, slack *SlackM
|
|||||||
|
|
||||||
func getSlackRepositoryPayload(p *api.RepositoryPayload, slack *SlackMeta) (*SlackPayload, error) {
|
func getSlackRepositoryPayload(p *api.RepositoryPayload, slack *SlackMeta) (*SlackPayload, error) {
|
||||||
senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
|
senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName)
|
||||||
var text, title, attachmentText string
|
var text string
|
||||||
|
|
||||||
switch p.Action {
|
switch p.Action {
|
||||||
case api.HookRepoCreated:
|
case api.HookRepoCreated:
|
||||||
text = fmt.Sprintf("[%s] Repository created by %s", p.Repository.FullName, senderLink)
|
text = fmt.Sprintf("[%s] Repository created by %s", p.Repository.FullName, senderLink)
|
||||||
title = p.Repository.HTMLURL
|
|
||||||
case api.HookRepoDeleted:
|
case api.HookRepoDeleted:
|
||||||
text = fmt.Sprintf("[%s] Repository deleted by %s", p.Repository.FullName, senderLink)
|
text = fmt.Sprintf("[%s] Repository deleted by %s", p.Repository.FullName, senderLink)
|
||||||
}
|
}
|
||||||
@@ -395,12 +396,6 @@ func getSlackRepositoryPayload(p *api.RepositoryPayload, slack *SlackMeta) (*Sla
|
|||||||
Text: text,
|
Text: text,
|
||||||
Username: slack.Username,
|
Username: slack.Username,
|
||||||
IconURL: slack.IconURL,
|
IconURL: slack.IconURL,
|
||||||
Attachments: []SlackAttachment{{
|
|
||||||
Color: slack.Color,
|
|
||||||
Title: title,
|
|
||||||
TitleLink: title,
|
|
||||||
Text: attachmentText,
|
|
||||||
}},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ type AuthenticationForm struct {
|
|||||||
SearchPageSize int
|
SearchPageSize int
|
||||||
Filter string
|
Filter string
|
||||||
AdminFilter string
|
AdminFilter string
|
||||||
|
AllowDeactivateAll bool
|
||||||
IsActive bool
|
IsActive bool
|
||||||
IsSyncEnabled bool
|
IsSyncEnabled bool
|
||||||
SMTPAuth string
|
SMTPAuth string
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ type Source struct {
|
|||||||
Filter string // Query filter to validate entry
|
Filter string // Query filter to validate entry
|
||||||
AdminFilter string // Query filter to check if user is admin
|
AdminFilter string // Query filter to check if user is admin
|
||||||
Enabled bool // if this source is disabled
|
Enabled bool // if this source is disabled
|
||||||
|
AllowDeactivateAll bool // Allow an empty search response to deactivate all users from this source
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchResult : user data
|
// SearchResult : user data
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Copyright 2020 The Gitea Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ func (ctx *Context) RedirectToFirst(location ...string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u, err := url.Parse(loc)
|
u, err := url.Parse(loc)
|
||||||
if err != nil || (u.Scheme != "" && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) {
|
if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,12 +91,12 @@ func (r *Repository) CanUseTimetracker(issue *models.Issue, user *models.User) b
|
|||||||
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
|
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
|
||||||
isAssigned, _ := models.IsUserAssignedToIssue(issue, user)
|
isAssigned, _ := models.IsUserAssignedToIssue(issue, user)
|
||||||
return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() ||
|
return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() ||
|
||||||
r.Permission.CanWrite(models.UnitTypeIssues) || issue.IsPoster(user.ID) || isAssigned)
|
r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanCreateIssueDependencies returns whether or not a user can create dependencies.
|
// CanCreateIssueDependencies returns whether or not a user can create dependencies.
|
||||||
func (r *Repository) CanCreateIssueDependencies(user *models.User) bool {
|
func (r *Repository) CanCreateIssueDependencies(user *models.User, isPull bool) bool {
|
||||||
return r.Permission.CanWrite(models.UnitTypeIssues) && r.Repository.IsDependenciesEnabled()
|
return r.Repository.IsDependenciesEnabled() && r.Permission.CanWriteIssuesOrPulls(isPull)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetCommitsCount returns cached commit count for current view
|
// GetCommitsCount returns cached commit count for current view
|
||||||
|
|||||||
@@ -1700,6 +1700,7 @@ auths.attribute_surname = Surname Attribute
|
|||||||
auths.attribute_mail = Email Attribute
|
auths.attribute_mail = Email Attribute
|
||||||
auths.attribute_ssh_public_key = Public SSH Key Attribute
|
auths.attribute_ssh_public_key = Public SSH Key Attribute
|
||||||
auths.attributes_in_bind = Fetch Attributes in Bind DN Context
|
auths.attributes_in_bind = Fetch Attributes in Bind DN Context
|
||||||
|
auths.allow_deactivate_all = Allow an empty search result to deactivate all users
|
||||||
auths.use_paged_search = Use Paged Search
|
auths.use_paged_search = Use Paged Search
|
||||||
auths.search_page_size = Page Size
|
auths.search_page_size = Page Size
|
||||||
auths.filter = User Filter
|
auths.filter = User Filter
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/* globals wipPrefixes, issuesTribute, emojiTribute */
|
/* globals wipPrefixes, issuesTribute, emojiTribute */
|
||||||
/* exported timeAddManual, toggleStopwatch, cancelStopwatch, initHeatmap */
|
/* exported timeAddManual, toggleStopwatch, cancelStopwatch, initHeatmap */
|
||||||
/* exported toggleDeadlineForm, setDeadline, deleteDependencyModal, cancelCodeComment, onOAuthLoginClick */
|
/* exported toggleDeadlineForm, setDeadline, deleteDependencyModal, submitReply, cancelCodeComment, onOAuthLoginClick */
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
function htmlEncode(text) {
|
function htmlEncode(text) {
|
||||||
@@ -3134,10 +3134,11 @@ function deleteDependencyModal(id, type) {
|
|||||||
|
|
||||||
function initIssueList() {
|
function initIssueList() {
|
||||||
const repolink = $('#repolink').val();
|
const repolink = $('#repolink').val();
|
||||||
|
const tp = $('#type').val();
|
||||||
$('#new-dependency-drop-list')
|
$('#new-dependency-drop-list')
|
||||||
.dropdown({
|
.dropdown({
|
||||||
apiSettings: {
|
apiSettings: {
|
||||||
url: suburl + '/api/v1/repos/' + repolink + '/issues?q={query}',
|
url: suburl + '/api/v1/repos/' + repolink + '/issues?q={query}&type='+tp,
|
||||||
onResponse: function(response) {
|
onResponse: function(response) {
|
||||||
const filteredResponse = {'success': true, 'results': []};
|
const filteredResponse = {'success': true, 'results': []};
|
||||||
const currIssueId = $('#new-dependency-drop-list').data('issue-id');
|
const currIssueId = $('#new-dependency-drop-list').data('issue-id');
|
||||||
@@ -3170,6 +3171,14 @@ function cancelCodeComment(btn) {
|
|||||||
form.closest('.comment-code-cloud').remove()
|
form.closest('.comment-code-cloud').remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function submitReply(btn) {
|
||||||
|
const form = $(btn).closest('form');
|
||||||
|
if (form.length > 0 && form.hasClass('comment-form')) {
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onOAuthLoginClick() {
|
function onOAuthLoginClick() {
|
||||||
const oauthLoader = $('#oauth2-login-loader');
|
const oauthLoader = $('#oauth2-login-loader');
|
||||||
const oauthNav = $('#oauth2-login-navigator');
|
const oauthNav = $('#oauth2-login-navigator');
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig {
|
|||||||
SearchPageSize: pageSize,
|
SearchPageSize: pageSize,
|
||||||
Filter: form.Filter,
|
Filter: form.Filter,
|
||||||
AdminFilter: form.AdminFilter,
|
AdminFilter: form.AdminFilter,
|
||||||
|
AllowDeactivateAll: form.AllowDeactivateAll,
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ func ListIssues(ctx *context.APIContext) {
|
|||||||
// in: query
|
// in: query
|
||||||
// description: search string
|
// description: search string
|
||||||
// type: string
|
// type: string
|
||||||
|
// - name: type
|
||||||
|
// in: query
|
||||||
|
// description: filter by type (issues / pulls) if set
|
||||||
|
// type: string
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/IssueList"
|
// "$ref": "#/responses/IssueList"
|
||||||
@@ -91,6 +95,16 @@ func ListIssues(ctx *context.APIContext) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isPull util.OptionalBool
|
||||||
|
switch ctx.Query("type") {
|
||||||
|
case "pulls":
|
||||||
|
isPull = util.OptionalBoolTrue
|
||||||
|
case "issues":
|
||||||
|
isPull = util.OptionalBoolFalse
|
||||||
|
default:
|
||||||
|
isPull = util.OptionalBoolNone
|
||||||
|
}
|
||||||
|
|
||||||
// Only fetch the issues if we either don't have a keyword or the search returned issues
|
// 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.
|
// This would otherwise return all issues if no issues were found by the search.
|
||||||
if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
|
if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 {
|
||||||
@@ -101,6 +115,7 @@ func ListIssues(ctx *context.APIContext) {
|
|||||||
IsClosed: isClosed,
|
IsClosed: isClosed,
|
||||||
IssueIDs: issueIDs,
|
IssueIDs: issueIDs,
|
||||||
LabelIDs: labelIDs,
|
LabelIDs: labelIDs,
|
||||||
|
IsPull: isPull,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,6 +307,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
issue.Repo = ctx.Repo.Repository
|
issue.Repo = ctx.Repo.Repository
|
||||||
|
canWrite := ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
|
||||||
|
|
||||||
err = issue.LoadAttributes()
|
err = issue.LoadAttributes()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -299,7 +315,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
if !issue.IsPoster(ctx.User.ID) && !canWrite {
|
||||||
ctx.Status(403)
|
ctx.Status(403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -312,7 +328,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the deadline
|
// Update the deadline
|
||||||
if form.Deadline != nil && ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
if form.Deadline != nil && canWrite {
|
||||||
deadlineUnix := timeutil.TimeStamp(form.Deadline.Unix())
|
deadlineUnix := timeutil.TimeStamp(form.Deadline.Unix())
|
||||||
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
|
if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.User); err != nil {
|
||||||
ctx.Error(500, "UpdateIssueDeadline", err)
|
ctx.Error(500, "UpdateIssueDeadline", err)
|
||||||
@@ -329,7 +345,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
|
|||||||
// Pass one or more user logins to replace the set of assignees on this Issue.
|
// Pass one or more user logins to replace the set of assignees on this Issue.
|
||||||
// Send an empty array ([]) to clear all assignees from the Issue.
|
// Send an empty array ([]) to clear all assignees from the Issue.
|
||||||
|
|
||||||
if ctx.Repo.CanWrite(models.UnitTypeIssues) && (form.Assignees != nil || form.Assignee != nil) {
|
if canWrite && (form.Assignees != nil || form.Assignee != nil) {
|
||||||
oneAssignee := ""
|
oneAssignee := ""
|
||||||
if form.Assignee != nil {
|
if form.Assignee != nil {
|
||||||
oneAssignee = *form.Assignee
|
oneAssignee = *form.Assignee
|
||||||
@@ -342,7 +358,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Repo.CanWrite(models.UnitTypeIssues) && form.Milestone != nil &&
|
if canWrite && form.Milestone != nil &&
|
||||||
issue.MilestoneID != *form.Milestone {
|
issue.MilestoneID != *form.Milestone {
|
||||||
oldMilestoneID := issue.MilestoneID
|
oldMilestoneID := issue.MilestoneID
|
||||||
issue.MilestoneID = *form.Milestone
|
issue.MilestoneID = *form.Milestone
|
||||||
@@ -430,7 +446,7 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
|
||||||
ctx.Status(403)
|
ctx.Status(403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -497,7 +513,7 @@ func StartIssueStopwatch(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
|
||||||
ctx.Status(403)
|
ctx.Status(403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -566,7 +582,7 @@ func StopIssueStopwatch(ctx *context.APIContext) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
|
||||||
ctx.Status(403)
|
ctx.Status(403)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ func CreateIssueComment(ctx *context.APIContext, form api.CreateIssueCommentOpti
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin {
|
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.User.IsAdmin {
|
||||||
ctx.Error(403, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
|
ctx.Error(403, "CreateIssueComment", errors.New(ctx.Tr("repo.issues.comment_on_locked")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,12 @@ func EditMilestone(ctx *context.APIContext, form api.EditMilestoneOption) {
|
|||||||
milestone.DeadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
|
milestone.DeadlineUnix = timeutil.TimeStamp(form.Deadline.Unix())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := models.UpdateMilestone(milestone); err != nil {
|
var oldIsClosed = milestone.IsClosed
|
||||||
|
if form.State != nil {
|
||||||
|
milestone.IsClosed = *form.State == string(api.StateClosed)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := models.UpdateMilestone(milestone, oldIsClosed); err != nil {
|
||||||
ctx.ServerError("UpdateMilestone", err)
|
ctx.ServerError("UpdateMilestone", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
|
|||||||
repo, err := models.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
|
repo, err := models.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
|
||||||
Name: opts.RepoName,
|
Name: opts.RepoName,
|
||||||
Description: opts.Description,
|
Description: opts.Description,
|
||||||
OriginalURL: opts.CloneAddr,
|
OriginalURL: form.CloneAddr,
|
||||||
IsPrivate: opts.Private,
|
IsPrivate: opts.Private,
|
||||||
IsMirror: opts.Mirror,
|
IsMirror: opts.Mirror,
|
||||||
Status: models.RepositoryBeingMigrated,
|
Status: models.RepositoryBeingMigrated,
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) {
|
|||||||
Keyword: keyword,
|
Keyword: keyword,
|
||||||
OwnerID: opts.OwnerID,
|
OwnerID: opts.OwnerID,
|
||||||
AllPublic: true,
|
AllPublic: true,
|
||||||
|
AllLimited: true,
|
||||||
TopicOnly: topicOnly,
|
TopicOnly: topicOnly,
|
||||||
IncludeDescription: setting.UI.SearchRepoDescription,
|
IncludeDescription: setting.UI.SearchRepoDescription,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/repofiles"
|
"code.gitea.io/gitea/modules/repofiles"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
|
"gopkg.in/src-d/go-git.v4/plumbing"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -32,6 +33,7 @@ type Branch struct {
|
|||||||
CommitsAhead int
|
CommitsAhead int
|
||||||
CommitsBehind int
|
CommitsBehind int
|
||||||
LatestPullRequest *models.PullRequest
|
LatestPullRequest *models.PullRequest
|
||||||
|
MergeMovedOn bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Branches render repository branch page
|
// Branches render repository branch page
|
||||||
@@ -168,6 +170,12 @@ func loadBranches(ctx *context.Context) []*Branch {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
repoIDToRepo := map[int64]*models.Repository{}
|
||||||
|
repoIDToRepo[ctx.Repo.Repository.ID] = ctx.Repo.Repository
|
||||||
|
|
||||||
|
repoIDToGitRepo := map[int64]*git.Repository{}
|
||||||
|
repoIDToGitRepo[ctx.Repo.Repository.ID] = ctx.Repo.GitRepo
|
||||||
|
|
||||||
branches := make([]*Branch, len(rawBranches))
|
branches := make([]*Branch, len(rawBranches))
|
||||||
for i := range rawBranches {
|
for i := range rawBranches {
|
||||||
commit, err := rawBranches[i].GetCommit()
|
commit, err := rawBranches[i].GetCommit()
|
||||||
@@ -196,11 +204,46 @@ func loadBranches(ctx *context.Context) []*Branch {
|
|||||||
ctx.ServerError("GetLatestPullRequestByHeadInfo", err)
|
ctx.ServerError("GetLatestPullRequestByHeadInfo", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
headCommit := commit.ID.String()
|
||||||
|
|
||||||
|
mergeMovedOn := false
|
||||||
if pr != nil {
|
if pr != nil {
|
||||||
|
pr.HeadRepo = ctx.Repo.Repository
|
||||||
if err := pr.LoadIssue(); err != nil {
|
if err := pr.LoadIssue(); err != nil {
|
||||||
ctx.ServerError("pr.LoadIssue", err)
|
ctx.ServerError("pr.LoadIssue", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if repo, ok := repoIDToRepo[pr.BaseRepoID]; ok {
|
||||||
|
pr.BaseRepo = repo
|
||||||
|
} else if err := pr.LoadBaseRepo(); err != nil {
|
||||||
|
ctx.ServerError("pr.LoadBaseRepo", err)
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
repoIDToRepo[pr.BaseRepoID] = pr.BaseRepo
|
||||||
|
}
|
||||||
|
pr.Issue.Repo = pr.BaseRepo
|
||||||
|
|
||||||
|
if pr.HasMerged {
|
||||||
|
baseGitRepo, ok := repoIDToGitRepo[pr.BaseRepoID]
|
||||||
|
if !ok {
|
||||||
|
baseGitRepo, err = git.OpenRepository(pr.BaseRepo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("OpenRepository", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer baseGitRepo.Close()
|
||||||
|
repoIDToGitRepo[pr.BaseRepoID] = baseGitRepo
|
||||||
|
}
|
||||||
|
pullCommit, err := baseGitRepo.GetRefCommitID(pr.GetGitRefName())
|
||||||
|
if err != nil && err != plumbing.ErrReferenceNotFound {
|
||||||
|
ctx.ServerError("GetBranchCommitID", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err == nil && headCommit != pullCommit {
|
||||||
|
// the head has moved on from the merge - we shouldn't delete
|
||||||
|
mergeMovedOn = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
branches[i] = &Branch{
|
branches[i] = &Branch{
|
||||||
@@ -210,6 +253,7 @@ func loadBranches(ctx *context.Context) []*Branch {
|
|||||||
CommitsAhead: divergence.Ahead,
|
CommitsAhead: divergence.Ahead,
|
||||||
CommitsBehind: divergence.Behind,
|
CommitsBehind: divergence.Behind,
|
||||||
LatestPullRequest: pr,
|
LatestPullRequest: pr,
|
||||||
|
MergeMovedOn: mergeMovedOn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,12 +152,12 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
|
|||||||
ctx.ServerError("OpenRepository", err)
|
ctx.ServerError("OpenRepository", err)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
|
defer headGitRepo.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// user should have permission to read baseRepo's codes and pulls, NOT headRepo's
|
// user should have permission to read baseRepo's codes and pulls, NOT headRepo's
|
||||||
permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User)
|
permBase, err := models.GetUserRepoPermission(baseRepo, ctx.User)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
headGitRepo.Close()
|
|
||||||
ctx.ServerError("GetUserRepoPermission", err)
|
ctx.ServerError("GetUserRepoPermission", err)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
@@ -168,42 +168,40 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
|
|||||||
baseRepo,
|
baseRepo,
|
||||||
permBase)
|
permBase)
|
||||||
}
|
}
|
||||||
headGitRepo.Close()
|
|
||||||
ctx.NotFound("ParseCompareInfo", nil)
|
ctx.NotFound("ParseCompareInfo", nil)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// user should have permission to read headrepo's codes
|
if !isSameRepo {
|
||||||
permHead, err := models.GetUserRepoPermission(headRepo, ctx.User)
|
// user should have permission to read headrepo's codes
|
||||||
if err != nil {
|
permHead, err := models.GetUserRepoPermission(headRepo, ctx.User)
|
||||||
headGitRepo.Close()
|
if err != nil {
|
||||||
ctx.ServerError("GetUserRepoPermission", err)
|
ctx.ServerError("GetUserRepoPermission", err)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
if !permHead.CanRead(models.UnitTypeCode) {
|
if !permHead.CanRead(models.UnitTypeCode) {
|
||||||
if log.IsTrace() {
|
if log.IsTrace() {
|
||||||
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
|
log.Trace("Permission Denied: User: %-v cannot read code in Repo: %-v\nUser in headRepo has Permissions: %-+v",
|
||||||
ctx.User,
|
ctx.User,
|
||||||
headRepo,
|
headRepo,
|
||||||
permHead)
|
permHead)
|
||||||
|
}
|
||||||
|
ctx.NotFound("ParseCompareInfo", nil)
|
||||||
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
headGitRepo.Close()
|
|
||||||
ctx.NotFound("ParseCompareInfo", nil)
|
|
||||||
return nil, nil, nil, nil, "", ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if head branch is valid.
|
// Check if head branch is valid.
|
||||||
headIsCommit := ctx.Repo.GitRepo.IsCommitExist(headBranch)
|
headIsCommit := headGitRepo.IsCommitExist(headBranch)
|
||||||
headIsBranch := headGitRepo.IsBranchExist(headBranch)
|
headIsBranch := headGitRepo.IsBranchExist(headBranch)
|
||||||
headIsTag := headGitRepo.IsTagExist(headBranch)
|
headIsTag := headGitRepo.IsTagExist(headBranch)
|
||||||
if !headIsCommit && !headIsBranch && !headIsTag {
|
if !headIsCommit && !headIsBranch && !headIsTag {
|
||||||
// Check if headBranch is short sha commit hash
|
// Check if headBranch is short sha commit hash
|
||||||
if headCommit, _ := ctx.Repo.GitRepo.GetCommit(headBranch); headCommit != nil {
|
if headCommit, _ := headGitRepo.GetCommit(headBranch); headCommit != nil {
|
||||||
headBranch = headCommit.ID.String()
|
headBranch = headCommit.ID.String()
|
||||||
ctx.Data["HeadBranch"] = headBranch
|
ctx.Data["HeadBranch"] = headBranch
|
||||||
headIsCommit = true
|
headIsCommit = true
|
||||||
} else {
|
} else {
|
||||||
headGitRepo.Close()
|
|
||||||
ctx.NotFound("IsRefExist", nil)
|
ctx.NotFound("IsRefExist", nil)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
@@ -224,14 +222,12 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
|
|||||||
baseRepo,
|
baseRepo,
|
||||||
permBase)
|
permBase)
|
||||||
}
|
}
|
||||||
headGitRepo.Close()
|
|
||||||
ctx.NotFound("ParseCompareInfo", nil)
|
ctx.NotFound("ParseCompareInfo", nil)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch)
|
compareInfo, err := headGitRepo.GetCompareInfo(baseRepo.RepoPath(), baseBranch, headBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
headGitRepo.Close()
|
|
||||||
ctx.ServerError("GetCompareInfo", err)
|
ctx.ServerError("GetCompareInfo", err)
|
||||||
return nil, nil, nil, nil, "", ""
|
return nil, nil, nil, nil, "", ""
|
||||||
}
|
}
|
||||||
@@ -377,7 +373,8 @@ func CompareDiff(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer headGitRepo.Close()
|
defer headGitRepo.Close()
|
||||||
if err := parseBaseRepoInfo(ctx, headRepo); err != nil {
|
var err error
|
||||||
|
if err = parseBaseRepoInfo(ctx, headRepo); err != nil {
|
||||||
ctx.ServerError("parseBaseRepoInfo", err)
|
ctx.ServerError("parseBaseRepoInfo", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -410,7 +407,7 @@ func CompareDiff(ctx *context.Context) {
|
|||||||
|
|
||||||
if !nothingToCompare {
|
if !nothingToCompare {
|
||||||
// Setup information for new form.
|
// Setup information for new form.
|
||||||
RetrieveRepoMetas(ctx, ctx.Repo.Repository)
|
RetrieveRepoMetas(ctx, ctx.Repo.Repository, true)
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -419,6 +416,11 @@ func CompareDiff(ctx *context.Context) {
|
|||||||
beforeCommitID := ctx.Data["BeforeCommitID"].(string)
|
beforeCommitID := ctx.Data["BeforeCommitID"].(string)
|
||||||
afterCommitID := ctx.Data["AfterCommitID"].(string)
|
afterCommitID := ctx.Data["AfterCommitID"].(string)
|
||||||
|
|
||||||
|
if ctx.Data["Assignees"], err = ctx.Repo.Repository.GetAssignees(); err != nil {
|
||||||
|
ctx.ServerError("GetAssignees", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + "..." + base.ShortSha(afterCommitID)
|
ctx.Data["Title"] = "Comparing " + base.ShortSha(beforeCommitID) + "..." + base.ShortSha(afterCommitID)
|
||||||
|
|
||||||
ctx.Data["IsRepoToolbarCommits"] = true
|
ctx.Data["IsRepoToolbarCommits"] = true
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
"code.gitea.io/gitea/modules/charset"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/lfs"
|
"code.gitea.io/gitea/modules/lfs"
|
||||||
@@ -33,7 +34,12 @@ func ServeData(ctx *context.Context, name string, reader io.Reader) error {
|
|||||||
name = strings.Replace(name, ",", " ", -1)
|
name = strings.Replace(name, ",", " ", -1)
|
||||||
|
|
||||||
if base.IsTextFile(buf) || ctx.QueryBool("render") {
|
if base.IsTextFile(buf) || ctx.QueryBool("render") {
|
||||||
ctx.Resp.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
cs, err := charset.DetectEncoding(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Detect raw file %s charset failed: %v, using by default utf-8", name, err)
|
||||||
|
cs = "utf-8"
|
||||||
|
}
|
||||||
|
ctx.Resp.Header().Set("Content-Type", "text/plain; charset="+strings.ToLower(cs))
|
||||||
} else if base.IsImageFile(buf) || base.IsPDFFile(buf) {
|
} else if base.IsImageFile(buf) || base.IsPDFFile(buf) {
|
||||||
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
|
ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ func MustAllowUserComment(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin {
|
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.User.IsAdmin {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked"))
|
ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked"))
|
||||||
ctx.Redirect(issue.HTMLURL())
|
ctx.Redirect(issue.HTMLURL())
|
||||||
return
|
return
|
||||||
@@ -346,8 +346,8 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repos
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RetrieveRepoMetas find all the meta information of a repository
|
// RetrieveRepoMetas find all the meta information of a repository
|
||||||
func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository) []*models.Label {
|
func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository, isPull bool) []*models.Label {
|
||||||
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
if !ctx.Repo.CanWriteIssuesOrPulls(isPull) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@ func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository) []*models.
|
|||||||
ctx.Data["Branches"] = brs
|
ctx.Data["Branches"] = brs
|
||||||
|
|
||||||
// Contains true if the user can create issue dependencies
|
// Contains true if the user can create issue dependencies
|
||||||
ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User)
|
ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User, isPull)
|
||||||
|
|
||||||
return labels
|
return labels
|
||||||
}
|
}
|
||||||
@@ -441,7 +441,7 @@ func NewIssue(ctx *context.Context) {
|
|||||||
setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates)
|
setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates)
|
||||||
renderAttachmentSettings(ctx)
|
renderAttachmentSettings(ctx)
|
||||||
|
|
||||||
RetrieveRepoMetas(ctx, ctx.Repo.Repository)
|
RetrieveRepoMetas(ctx, ctx.Repo.Repository, false)
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -456,7 +456,7 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull b
|
|||||||
err error
|
err error
|
||||||
)
|
)
|
||||||
|
|
||||||
labels := RetrieveRepoMetas(ctx, ctx.Repo.Repository)
|
labels := RetrieveRepoMetas(ctx, ctx.Repo.Repository, isPull)
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return nil, nil, 0
|
return nil, nil, 0
|
||||||
}
|
}
|
||||||
@@ -776,8 +776,16 @@ func ViewIssue(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if issue.IsPull && !ctx.Repo.CanRead(models.UnitTypeIssues) {
|
||||||
|
ctx.Data["IssueType"] = "pulls"
|
||||||
|
} else if !issue.IsPull && !ctx.Repo.CanRead(models.UnitTypePullRequests) {
|
||||||
|
ctx.Data["IssueType"] = "issues"
|
||||||
|
} else {
|
||||||
|
ctx.Data["IssueType"] = "all"
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the user can use the dependencies
|
// Check if the user can use the dependencies
|
||||||
ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User)
|
ctx.Data["CanCreateIssueDependencies"] = ctx.Repo.CanCreateIssueDependencies(ctx.User, issue.IsPull)
|
||||||
|
|
||||||
// Render comments and and fetch participants.
|
// Render comments and and fetch participants.
|
||||||
participants[0] = issue.Poster
|
participants[0] = issue.Poster
|
||||||
@@ -931,7 +939,10 @@ func ViewIssue(ctx *context.Context) {
|
|||||||
ctx.Data["IsBlockedByApprovals"] = pull.ProtectedBranch.RequiredApprovals > 0 && cnt < pull.ProtectedBranch.RequiredApprovals
|
ctx.Data["IsBlockedByApprovals"] = pull.ProtectedBranch.RequiredApprovals > 0 && cnt < pull.ProtectedBranch.RequiredApprovals
|
||||||
ctx.Data["GrantedApprovals"] = cnt
|
ctx.Data["GrantedApprovals"] = cnt
|
||||||
}
|
}
|
||||||
ctx.Data["IsPullBranchDeletable"] = canDelete && pull.HeadRepo != nil && git.IsBranchExist(pull.HeadRepo.RepoPath(), pull.HeadBranch)
|
ctx.Data["IsPullBranchDeletable"] = canDelete &&
|
||||||
|
pull.HeadRepo != nil &&
|
||||||
|
git.IsBranchExist(pull.HeadRepo.RepoPath(), pull.HeadBranch) &&
|
||||||
|
(!pull.HasMerged || ctx.Data["HeadBranchCommitID"] == ctx.Data["PullHeadCommitID"])
|
||||||
|
|
||||||
ctx.Data["PullReviewersWithType"], err = models.GetReviewersByPullID(issue.ID)
|
ctx.Data["PullReviewersWithType"], err = models.GetReviewersByPullID(issue.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -960,7 +971,6 @@ func ViewIssue(ctx *context.Context) {
|
|||||||
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
|
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
|
||||||
ctx.Data["IsIssueWriter"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
|
ctx.Data["IsIssueWriter"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
|
||||||
ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.IsAdmin() || ctx.User.IsAdmin)
|
ctx.Data["IsRepoAdmin"] = ctx.IsSigned && (ctx.Repo.IsAdmin() || ctx.User.IsAdmin)
|
||||||
ctx.Data["IsRepoIssuesWriter"] = ctx.IsSigned && (ctx.Repo.CanWrite(models.UnitTypeIssues) || ctx.User.IsAdmin)
|
|
||||||
ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons
|
ctx.Data["LockReasons"] = setting.Repository.Issue.LockReasons
|
||||||
ctx.HTML(200, tplIssueView)
|
ctx.HTML(200, tplIssueView)
|
||||||
}
|
}
|
||||||
@@ -1205,7 +1215,7 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
|
|||||||
ctx.Error(403)
|
ctx.Error(403)
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.IsLocked && !ctx.Repo.CanWrite(models.UnitTypeIssues) && !ctx.User.IsAdmin {
|
if issue.IsLocked && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) && !ctx.User.IsAdmin {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked"))
|
ctx.Flash.Error(ctx.Tr("repo.issues.comment_on_locked"))
|
||||||
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
|
ctx.Redirect(issue.HTMLURL(), http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -14,14 +14,6 @@ import (
|
|||||||
|
|
||||||
// AddDependency adds new dependencies
|
// AddDependency adds new dependencies
|
||||||
func AddDependency(ctx *context.Context) {
|
func AddDependency(ctx *context.Context) {
|
||||||
// Check if the Repo is allowed to have dependencies
|
|
||||||
if !ctx.Repo.CanCreateIssueDependencies(ctx.User) {
|
|
||||||
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
depID := ctx.QueryInt64("newDependency")
|
|
||||||
|
|
||||||
issueIndex := ctx.ParamsInt64("index")
|
issueIndex := ctx.ParamsInt64("index")
|
||||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex)
|
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -29,6 +21,14 @@ func AddDependency(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the Repo is allowed to have dependencies
|
||||||
|
if !ctx.Repo.CanCreateIssueDependencies(ctx.User, issue.IsPull) {
|
||||||
|
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
depID := ctx.QueryInt64("newDependency")
|
||||||
|
|
||||||
// Redirect
|
// Redirect
|
||||||
defer ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issueIndex), http.StatusSeeOther)
|
defer ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issueIndex), http.StatusSeeOther)
|
||||||
|
|
||||||
@@ -68,14 +68,6 @@ func AddDependency(ctx *context.Context) {
|
|||||||
|
|
||||||
// RemoveDependency removes the dependency
|
// RemoveDependency removes the dependency
|
||||||
func RemoveDependency(ctx *context.Context) {
|
func RemoveDependency(ctx *context.Context) {
|
||||||
// Check if the Repo is allowed to have dependencies
|
|
||||||
if !ctx.Repo.CanCreateIssueDependencies(ctx.User) {
|
|
||||||
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
depID := ctx.QueryInt64("removeDependencyID")
|
|
||||||
|
|
||||||
issueIndex := ctx.ParamsInt64("index")
|
issueIndex := ctx.ParamsInt64("index")
|
||||||
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex)
|
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, issueIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -83,8 +75,13 @@ func RemoveDependency(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redirect
|
// Check if the Repo is allowed to have dependencies
|
||||||
ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issueIndex), http.StatusSeeOther)
|
if !ctx.Repo.CanCreateIssueDependencies(ctx.User, issue.IsPull) {
|
||||||
|
ctx.Error(http.StatusForbidden, "CanCreateIssueDependencies")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
depID := ctx.QueryInt64("removeDependencyID")
|
||||||
|
|
||||||
// Dependency Type
|
// Dependency Type
|
||||||
depTypeStr := ctx.Req.PostForm.Get("dependencyType")
|
depTypeStr := ctx.Req.PostForm.Get("dependencyType")
|
||||||
@@ -116,4 +113,7 @@ func RemoveDependency(ctx *context.Context) {
|
|||||||
ctx.ServerError("RemoveIssueDependency", err)
|
ctx.ServerError("RemoveIssueDependency", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Redirect
|
||||||
|
ctx.Redirect(fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issueIndex), http.StatusSeeOther)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ func EditMilestonePost(ctx *context.Context, form auth.CreateMilestoneForm) {
|
|||||||
m.Name = form.Title
|
m.Name = form.Title
|
||||||
m.Content = form.Content
|
m.Content = form.Content
|
||||||
m.DeadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
m.DeadlineUnix = timeutil.TimeStamp(deadline.Unix())
|
||||||
if err = models.UpdateMilestone(m); err != nil {
|
if err = models.UpdateMilestone(m, m.IsClosed); err != nil {
|
||||||
ctx.ServerError("UpdateMilestone", err)
|
ctx.ServerError("UpdateMilestone", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -315,25 +315,37 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
|
|||||||
repo := ctx.Repo.Repository
|
repo := ctx.Repo.Repository
|
||||||
pull := issue.PullRequest
|
pull := issue.PullRequest
|
||||||
|
|
||||||
var err error
|
if err := pull.GetHeadRepo(); err != nil {
|
||||||
if err = pull.GetHeadRepo(); err != nil {
|
|
||||||
ctx.ServerError("GetHeadRepo", err)
|
ctx.ServerError("GetHeadRepo", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := pull.GetBaseRepo(); err != nil {
|
||||||
|
ctx.ServerError("GetBaseRepo", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
setMergeTarget(ctx, pull)
|
setMergeTarget(ctx, pull)
|
||||||
|
|
||||||
if err = pull.LoadProtectedBranch(); err != nil {
|
if err := pull.LoadProtectedBranch(); err != nil {
|
||||||
ctx.ServerError("GetLatestCommitStatus", err)
|
ctx.ServerError("GetLatestCommitStatus", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ctx.Data["EnableStatusCheck"] = pull.ProtectedBranch != nil && pull.ProtectedBranch.EnableStatusCheck
|
ctx.Data["EnableStatusCheck"] = pull.ProtectedBranch != nil && pull.ProtectedBranch.EnableStatusCheck
|
||||||
|
|
||||||
var headGitRepo *git.Repository
|
baseGitRepo, err := git.OpenRepository(pull.BaseRepo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("OpenRepository", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer baseGitRepo.Close()
|
||||||
var headBranchExist bool
|
var headBranchExist bool
|
||||||
|
var headBranchSha string
|
||||||
// HeadRepo may be missing
|
// HeadRepo may be missing
|
||||||
if pull.HeadRepo != nil {
|
if pull.HeadRepo != nil {
|
||||||
headGitRepo, err = git.OpenRepository(pull.HeadRepo.RepoPath())
|
var err error
|
||||||
|
|
||||||
|
headGitRepo, err := git.OpenRepository(pull.HeadRepo.RepoPath())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("OpenRepository", err)
|
ctx.ServerError("OpenRepository", err)
|
||||||
return nil
|
return nil
|
||||||
@@ -343,46 +355,53 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare
|
|||||||
headBranchExist = headGitRepo.IsBranchExist(pull.HeadBranch)
|
headBranchExist = headGitRepo.IsBranchExist(pull.HeadBranch)
|
||||||
|
|
||||||
if headBranchExist {
|
if headBranchExist {
|
||||||
sha, err := headGitRepo.GetBranchCommitID(pull.HeadBranch)
|
headBranchSha, err = headGitRepo.GetBranchCommitID(pull.HeadBranch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetBranchCommitID", err)
|
ctx.ServerError("GetBranchCommitID", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
commitStatuses, err := models.GetLatestCommitStatus(repo, sha, 0)
|
|
||||||
if err != nil {
|
|
||||||
ctx.ServerError("GetLatestCommitStatus", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if len(commitStatuses) > 0 {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pull.HeadRepo == nil || !headBranchExist {
|
sha, err := baseGitRepo.GetRefCommitID(pull.GetGitRefName())
|
||||||
ctx.Data["IsPullRequestBroken"] = true
|
if err != nil {
|
||||||
ctx.Data["HeadTarget"] = "deleted"
|
ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitRefName()), err)
|
||||||
ctx.Data["NumCommits"] = 0
|
|
||||||
ctx.Data["NumFiles"] = 0
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
compareInfo, err := headGitRepo.GetCompareInfo(models.RepoPath(repo.Owner.Name, repo.Name),
|
commitStatuses, err := models.GetLatestCommitStatus(repo, sha, 0)
|
||||||
pull.BaseBranch, pull.HeadBranch)
|
if err != nil {
|
||||||
|
ctx.ServerError("GetLatestCommitStatus", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(commitStatuses) > 0 {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Data["HeadBranchMovedOn"] = headBranchSha != sha
|
||||||
|
ctx.Data["HeadBranchCommitID"] = headBranchSha
|
||||||
|
ctx.Data["PullHeadCommitID"] = sha
|
||||||
|
|
||||||
|
if pull.HeadRepo == nil || !headBranchExist || headBranchSha != sha {
|
||||||
|
ctx.Data["IsPullRequestBroken"] = true
|
||||||
|
ctx.Data["HeadTarget"] = "deleted"
|
||||||
|
}
|
||||||
|
|
||||||
|
compareInfo, err := baseGitRepo.GetCompareInfo(pull.BaseRepo.RepoPath(),
|
||||||
|
pull.BaseBranch, pull.GetGitRefName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "fatal: Not a valid object name") {
|
if strings.Contains(err.Error(), "fatal: Not a valid object name") {
|
||||||
ctx.Data["IsPullRequestBroken"] = true
|
ctx.Data["IsPullRequestBroken"] = true
|
||||||
|
|||||||
@@ -117,9 +117,7 @@ func SubmitReview(ctx *context.Context, form auth.SubmitReviewForm) {
|
|||||||
|
|
||||||
// can not approve/reject your own PR
|
// can not approve/reject your own PR
|
||||||
case models.ReviewTypeApprove, models.ReviewTypeReject:
|
case models.ReviewTypeApprove, models.ReviewTypeReject:
|
||||||
|
if issue.IsPoster(ctx.User.ID) {
|
||||||
if issue.Poster.ID == ctx.User.ID {
|
|
||||||
|
|
||||||
var translated string
|
var translated string
|
||||||
|
|
||||||
if reviewType == models.ReviewTypeApprove {
|
if reviewType == models.ReviewTypeApprove {
|
||||||
|
|||||||
@@ -600,7 +600,7 @@ func AddTeamPost(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("team")))
|
name := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.Query("team")))
|
||||||
if len(name) == 0 || ctx.Repo.Owner.LowerName == name {
|
if len(name) == 0 {
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,27 +65,20 @@ type PageMeta struct {
|
|||||||
|
|
||||||
// findEntryForFile finds the tree entry for a target filepath.
|
// findEntryForFile finds the tree entry for a target filepath.
|
||||||
func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) {
|
func findEntryForFile(commit *git.Commit, target string) (*git.TreeEntry, error) {
|
||||||
entries, err := commit.ListEntries()
|
entry, err := commit.GetTreeEntryByPath(target)
|
||||||
if err != nil {
|
if err != nil && !git.IsErrNotExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// The longest name should be checked first
|
if entry != nil {
|
||||||
for _, entry := range entries {
|
return entry, nil
|
||||||
if entry.IsRegular() && entry.Name() == target {
|
|
||||||
return entry, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then the unescaped, shortest alternative
|
// Then the unescaped, shortest alternative
|
||||||
var unescapedTarget string
|
var unescapedTarget string
|
||||||
if unescapedTarget, err = url.QueryUnescape(target); err != nil {
|
if unescapedTarget, err = url.QueryUnescape(target); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, entry := range entries {
|
return commit.GetTreeEntryByPath(unescapedTarget)
|
||||||
if entry.IsRegular() && entry.Name() == unescapedTarget {
|
|
||||||
return entry, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) {
|
func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, error) {
|
||||||
@@ -122,10 +115,9 @@ func wikiContentsByEntry(ctx *context.Context, entry *git.TreeEntry) []byte {
|
|||||||
// wikiContentsByName returns the contents of a wiki page, along with a boolean
|
// wikiContentsByName returns the contents of a wiki page, along with a boolean
|
||||||
// indicating whether the page exists. Writes to ctx if an error occurs.
|
// indicating whether the page exists. Writes to ctx if an error occurs.
|
||||||
func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName string) ([]byte, *git.TreeEntry, string, bool) {
|
func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName string) ([]byte, *git.TreeEntry, string, bool) {
|
||||||
var entry *git.TreeEntry
|
|
||||||
var err error
|
|
||||||
pageFilename := models.WikiNameToFilename(wikiName)
|
pageFilename := models.WikiNameToFilename(wikiName)
|
||||||
if entry, err = findEntryForFile(commit, pageFilename); err != nil {
|
entry, err := findEntryForFile(commit, pageFilename)
|
||||||
|
if err != nil && !git.IsErrNotExist(err) {
|
||||||
ctx.ServerError("findEntryForFile", err)
|
ctx.ServerError("findEntryForFile", err)
|
||||||
return nil, nil, "", false
|
return nil, nil, "", false
|
||||||
} else if entry == nil {
|
} else if entry == nil {
|
||||||
@@ -517,7 +509,7 @@ func WikiRaw(ctx *context.Context) {
|
|||||||
if commit != nil {
|
if commit != nil {
|
||||||
// Try to find a file with that name
|
// Try to find a file with that name
|
||||||
entry, err = findEntryForFile(commit, providedPath)
|
entry, err = findEntryForFile(commit, providedPath)
|
||||||
if err != nil {
|
if err != nil && !git.IsErrNotExist(err) {
|
||||||
ctx.ServerError("findFile", err)
|
ctx.ServerError("findFile", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -530,7 +522,7 @@ func WikiRaw(ctx *context.Context) {
|
|||||||
|
|
||||||
wikiPath := models.WikiNameToFilename(providedPath)
|
wikiPath := models.WikiNameToFilename(providedPath)
|
||||||
entry, err = findEntryForFile(commit, wikiPath)
|
entry, err = findEntryForFile(commit, wikiPath)
|
||||||
if err != nil {
|
if err != nil && !git.IsErrNotExist(err) {
|
||||||
ctx.ServerError("findFile", err)
|
ctx.ServerError("findFile", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,6 +191,7 @@ func TestDeleteWikiPagePost(t *testing.T) {
|
|||||||
func TestWikiRaw(t *testing.T) {
|
func TestWikiRaw(t *testing.T) {
|
||||||
for filepath, filetype := range map[string]string{
|
for filepath, filetype := range map[string]string{
|
||||||
"jpeg.jpg": "image/jpeg",
|
"jpeg.jpg": "image/jpeg",
|
||||||
|
"images/jpeg.jpg": "image/jpeg",
|
||||||
"Page With Spaced Name": "text/plain; charset=utf-8",
|
"Page With Spaced Name": "text/plain; charset=utf-8",
|
||||||
"Page-With-Spaced-Name": "text/plain; charset=utf-8",
|
"Page-With-Spaced-Name": "text/plain; charset=utf-8",
|
||||||
"Page With Spaced Name.md": "text/plain; charset=utf-8",
|
"Page With Spaced Name.md": "text/plain; charset=utf-8",
|
||||||
|
|||||||
@@ -457,7 +457,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
||||||
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
|
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
|
||||||
m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
|
m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
|
||||||
m.Post("/msteams/:id", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
|
m.Post("/msteams/:id", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
|
||||||
})
|
})
|
||||||
|
|
||||||
m.Group("/auths", func() {
|
m.Group("/auths", func() {
|
||||||
@@ -532,18 +532,12 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
reqRepoReleaseReader := context.RequireRepoReader(models.UnitTypeReleases)
|
reqRepoReleaseReader := context.RequireRepoReader(models.UnitTypeReleases)
|
||||||
reqRepoWikiWriter := context.RequireRepoWriter(models.UnitTypeWiki)
|
reqRepoWikiWriter := context.RequireRepoWriter(models.UnitTypeWiki)
|
||||||
reqRepoIssueReader := context.RequireRepoReader(models.UnitTypeIssues)
|
reqRepoIssueReader := context.RequireRepoReader(models.UnitTypeIssues)
|
||||||
|
reqRepoIssueWriter := context.RequireRepoWriter(models.UnitTypeIssues)
|
||||||
reqRepoPullsWriter := context.RequireRepoWriter(models.UnitTypePullRequests)
|
reqRepoPullsWriter := context.RequireRepoWriter(models.UnitTypePullRequests)
|
||||||
reqRepoPullsReader := context.RequireRepoReader(models.UnitTypePullRequests)
|
reqRepoPullsReader := context.RequireRepoReader(models.UnitTypePullRequests)
|
||||||
reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(models.UnitTypeIssues, models.UnitTypePullRequests)
|
reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(models.UnitTypeIssues, models.UnitTypePullRequests)
|
||||||
reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(models.UnitTypeIssues, models.UnitTypePullRequests)
|
reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(models.UnitTypeIssues, models.UnitTypePullRequests)
|
||||||
|
|
||||||
reqRepoIssueWriter := func(ctx *context.Context) {
|
|
||||||
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
|
|
||||||
ctx.Error(403)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ***** START: Organization *****
|
// ***** START: Organization *****
|
||||||
m.Group("/org", func() {
|
m.Group("/org", func() {
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
@@ -590,6 +584,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
|
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
|
||||||
m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
|
m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
|
||||||
m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
|
m.Post("/telegram/new", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
|
||||||
|
m.Post("/msteams/new", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
|
||||||
m.Get("/:id", repo.WebHooksEdit)
|
m.Get("/:id", repo.WebHooksEdit)
|
||||||
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
|
||||||
m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost)
|
m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost)
|
||||||
@@ -597,6 +592,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
|||||||
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
|
||||||
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
|
m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
|
||||||
m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
|
m.Post("/telegram/:id", bindIgnErr(auth.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
|
||||||
|
m.Post("/msteams/:id", bindIgnErr(auth.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
|
||||||
})
|
})
|
||||||
|
|
||||||
m.Route("/delete", "GET,POST", org.SettingsDelete)
|
m.Route("/delete", "GET,POST", org.SettingsDelete)
|
||||||
|
|||||||
@@ -1282,7 +1282,7 @@ func ForgotPasswdPost(ctx *context.Context) {
|
|||||||
ctx.HTML(200, tplForgotPassword)
|
ctx.HTML(200, tplForgotPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
func commonResetPassword(ctx *context.Context) *models.User {
|
func commonResetPassword(ctx *context.Context) (*models.User, *models.TwoFactor) {
|
||||||
code := ctx.Query("code")
|
code := ctx.Query("code")
|
||||||
|
|
||||||
ctx.Data["Title"] = ctx.Tr("auth.reset_password")
|
ctx.Data["Title"] = ctx.Tr("auth.reset_password")
|
||||||
@@ -1294,14 +1294,25 @@ func commonResetPassword(ctx *context.Context) *models.User {
|
|||||||
|
|
||||||
if len(code) == 0 {
|
if len(code) == 0 {
|
||||||
ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
|
ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fail early, don't frustrate the user
|
// Fail early, don't frustrate the user
|
||||||
u := models.VerifyUserActiveCode(code)
|
u := models.VerifyUserActiveCode(code)
|
||||||
if u == nil {
|
if u == nil {
|
||||||
ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
|
ctx.Flash.Error(ctx.Tr("auth.invalid_code"))
|
||||||
return nil
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
twofa, err := models.GetTwoFactorByUID(u.ID)
|
||||||
|
if err != nil {
|
||||||
|
if !models.IsErrTwoFactorNotEnrolled(err) {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "CommonResetPassword", err.Error())
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.Data["has_two_factor"] = true
|
||||||
|
ctx.Data["scratch_code"] = ctx.QueryBool("scratch_code")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show the user that they are affecting the account that they intended to
|
// Show the user that they are affecting the account that they intended to
|
||||||
@@ -1309,10 +1320,10 @@ func commonResetPassword(ctx *context.Context) *models.User {
|
|||||||
|
|
||||||
if nil != ctx.User && u.ID != ctx.User.ID {
|
if nil != ctx.User && u.ID != ctx.User.ID {
|
||||||
ctx.Flash.Error(ctx.Tr("auth.reset_password_wrong_user", ctx.User.Email, u.Email))
|
ctx.Flash.Error(ctx.Tr("auth.reset_password_wrong_user", ctx.User.Email, u.Email))
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return u
|
return u, twofa
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetPasswd render the account recovery page
|
// ResetPasswd render the account recovery page
|
||||||
@@ -1320,13 +1331,19 @@ func ResetPasswd(ctx *context.Context) {
|
|||||||
ctx.Data["IsResetForm"] = true
|
ctx.Data["IsResetForm"] = true
|
||||||
|
|
||||||
commonResetPassword(ctx)
|
commonResetPassword(ctx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.HTML(200, tplResetPassword)
|
ctx.HTML(200, tplResetPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetPasswdPost response from account recovery request
|
// ResetPasswdPost response from account recovery request
|
||||||
func ResetPasswdPost(ctx *context.Context) {
|
func ResetPasswdPost(ctx *context.Context) {
|
||||||
u := commonResetPassword(ctx)
|
u, twofa := commonResetPassword(ctx)
|
||||||
|
if ctx.Written() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if u == nil {
|
if u == nil {
|
||||||
// Flash error has been set
|
// Flash error has been set
|
||||||
@@ -1348,6 +1365,39 @@ func ResetPasswdPost(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle two-factor
|
||||||
|
regenerateScratchToken := false
|
||||||
|
if twofa != nil {
|
||||||
|
if ctx.QueryBool("scratch_code") {
|
||||||
|
if !twofa.VerifyScratchToken(ctx.Query("token")) {
|
||||||
|
ctx.Data["IsResetForm"] = true
|
||||||
|
ctx.Data["Err_Token"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("auth.twofa_scratch_token_incorrect"), tplResetPassword, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
regenerateScratchToken = true
|
||||||
|
} else {
|
||||||
|
passcode := ctx.Query("passcode")
|
||||||
|
ok, err := twofa.ValidateTOTP(passcode)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error(http.StatusInternalServerError, "ValidateTOTP", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !ok || twofa.LastUsedPasscode == passcode {
|
||||||
|
ctx.Data["IsResetForm"] = true
|
||||||
|
ctx.Data["Err_Passcode"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("auth.twofa_passcode_incorrect"), tplResetPassword, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
twofa.LastUsedPasscode = passcode
|
||||||
|
if err = models.UpdateTwoFactor(twofa); err != nil {
|
||||||
|
ctx.ServerError("ResetPasswdPost: UpdateTwoFactor", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if u.Rands, err = models.GetUserSalt(); err != nil {
|
if u.Rands, err = models.GetUserSalt(); err != nil {
|
||||||
ctx.ServerError("UpdateUser", err)
|
ctx.ServerError("UpdateUser", err)
|
||||||
@@ -1357,7 +1407,6 @@ func ResetPasswdPost(ctx *context.Context) {
|
|||||||
ctx.ServerError("UpdateUser", err)
|
ctx.ServerError("UpdateUser", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
u.HashPassword(passwd)
|
u.HashPassword(passwd)
|
||||||
u.MustChangePassword = false
|
u.MustChangePassword = false
|
||||||
if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil {
|
if err := models.UpdateUserCols(u, "must_change_password", "passwd", "rands", "salt"); err != nil {
|
||||||
@@ -1366,9 +1415,27 @@ func ResetPasswdPost(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Trace("User password reset: %s", u.Name)
|
log.Trace("User password reset: %s", u.Name)
|
||||||
|
|
||||||
ctx.Data["IsResetFailed"] = true
|
ctx.Data["IsResetFailed"] = true
|
||||||
remember := len(ctx.Query("remember")) != 0
|
remember := len(ctx.Query("remember")) != 0
|
||||||
|
|
||||||
|
if regenerateScratchToken {
|
||||||
|
// Invalidate the scratch token.
|
||||||
|
_, err = twofa.GenerateScratchToken()
|
||||||
|
if err != nil {
|
||||||
|
ctx.ServerError("UserSignIn", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err = models.UpdateTwoFactor(twofa); err != nil {
|
||||||
|
ctx.ServerError("UserSignIn", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSignInFull(ctx, u, remember, false)
|
||||||
|
ctx.Flash.Info(ctx.Tr("auth.twofa_scratch_used"))
|
||||||
|
ctx.Redirect(setting.AppSubURL + "/user/settings/security")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
handleSignInFull(ctx, u, remember, true)
|
handleSignInFull(ctx, u, remember, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,9 @@ func retrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) {
|
|||||||
if act.ActUser != nil {
|
if act.ActUser != nil {
|
||||||
userCache[act.ActUserID] = act.ActUser
|
userCache[act.ActUserID] = act.ActUser
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, act := range actions {
|
||||||
repoOwner, ok := userCache[act.Repo.OwnerID]
|
repoOwner, ok := userCache[act.Repo.OwnerID]
|
||||||
if !ok {
|
if !ok {
|
||||||
repoOwner, err = models.GetUserByID(act.Repo.OwnerID)
|
repoOwner, err = models.GetUserByID(act.Repo.OwnerID)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/process"
|
"code.gitea.io/gitea/modules/process"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
)
|
)
|
||||||
@@ -37,6 +38,54 @@ func createTag(gitRepo *git.Repository, rel *models.Release) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rel.LowerTagName = strings.ToLower(rel.TagName)
|
rel.LowerTagName = strings.ToLower(rel.TagName)
|
||||||
|
// Prepare Notify
|
||||||
|
if err := rel.LoadAttributes(); err != nil {
|
||||||
|
log.Error("LoadAttributes: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
refName := git.TagPrefix + rel.TagName
|
||||||
|
apiPusher := rel.Publisher.APIFormat()
|
||||||
|
apiRepo := rel.Repo.APIFormat(models.AccessModeNone)
|
||||||
|
apiCommits, err := models.NewPushCommits().ToAPIPayloadCommits(rel.Repo.RepoPath(), rel.Repo.HTMLURL())
|
||||||
|
if err != nil {
|
||||||
|
log.Error("commits.ToAPIPayloadCommits failed: %v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := models.PrepareWebhooks(rel.Repo, models.HookEventPush, &api.PushPayload{
|
||||||
|
Ref: refName,
|
||||||
|
Before: git.EmptySHA,
|
||||||
|
After: commit.ID.String(),
|
||||||
|
CompareURL: setting.AppURL + models.NewPushCommits().CompareURL,
|
||||||
|
Commits: apiCommits,
|
||||||
|
Repo: apiRepo,
|
||||||
|
Pusher: apiPusher,
|
||||||
|
Sender: apiPusher,
|
||||||
|
}); err != nil {
|
||||||
|
log.Error("PrepareWebhooks: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
gitRepo, err := git.OpenRepository(rel.Repo.RepoPath())
|
||||||
|
if err != nil {
|
||||||
|
log.Error("OpenRepository[%s]: %v", rel.Repo.RepoPath(), err)
|
||||||
|
}
|
||||||
|
shaSum, err := gitRepo.GetTagCommitID(refName)
|
||||||
|
if err != nil {
|
||||||
|
gitRepo.Close()
|
||||||
|
log.Error("GetTagCommitID[%s]: %v", refName, err)
|
||||||
|
}
|
||||||
|
gitRepo.Close()
|
||||||
|
|
||||||
|
if err = models.PrepareWebhooks(rel.Repo, models.HookEventCreate, &api.CreatePayload{
|
||||||
|
Ref: git.RefEndName(refName),
|
||||||
|
Sha: shaSum,
|
||||||
|
RefType: "tag",
|
||||||
|
Repo: apiRepo,
|
||||||
|
Sender: apiPusher,
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("PrepareWebhooks: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
commit, err := gitRepo.GetTagCommit(rel.TagName)
|
commit, err := gitRepo.GetTagCommit(rel.TagName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -112,6 +112,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
<div class="inline field">
|
||||||
|
<div class="ui checkbox">
|
||||||
|
<label for="allow_deactivate_all"><strong>{{.i18n.Tr "admin.auths.allow_deactivate_all"}}</strong></label>
|
||||||
|
<input id="allow_deactivate_all" name="allow_deactivate_all" type="checkbox" {{if $cfg.AllowDeactivateAll}}checked{{end}}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
<!-- SMTP -->
|
<!-- SMTP -->
|
||||||
|
|||||||
@@ -73,21 +73,27 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td class="two wide right aligned">
|
<td class="three wide right aligned">
|
||||||
{{if not .LatestPullRequest}}
|
{{if not .LatestPullRequest}}
|
||||||
{{if and (not .IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}}
|
{{if and (not .IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}}
|
||||||
<a href="{{$.RepoLink}}/compare/{{$.DefaultBranch | EscapePound}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | EscapePound}}">
|
<a href="{{$.RepoLink}}/compare/{{$.DefaultBranch | EscapePound}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | EscapePound}}">
|
||||||
<button id="new-pull-request" class="ui compact basic button">{{$.i18n.Tr "repo.pulls.compare_changes"}}</button>
|
<button id="new-pull-request" class="ui compact basic button">{{$.i18n.Tr "repo.pulls.compare_changes"}}</button>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{else if and .LatestPullRequest.HasMerged .MergeMovedOn}}
|
||||||
|
{{if and (not .IsDeleted) $.AllowsPulls (gt .CommitsAhead 0)}}
|
||||||
|
<a href="{{$.RepoLink}}/compare/{{$.DefaultBranch | EscapePound}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | EscapePound}}">
|
||||||
|
<button id="new-pull-request" class="ui compact basic button">{{$.i18n.Tr "repo.pulls.compare_changes"}}</button>
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}">#{{.LatestPullRequest.Issue.Index}}</a>
|
<a href="{{.LatestPullRequest.Issue.HTMLURL}}">{{if ne .LatestPullRequest.BaseRepoID .LatestPullRequest.HeadRepoID}}{{.LatestPullRequest.BaseRepo.FullName}}{{end}}#{{.LatestPullRequest.Issue.Index}}</a>
|
||||||
{{if .LatestPullRequest.HasMerged}}
|
{{if .LatestPullRequest.HasMerged}}
|
||||||
<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}" class="ui purple small label"><i class="octicon octicon-git-pull-request"></i> {{$.i18n.Tr "repo.pulls.merged"}}</a>
|
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui purple mini label"><i class="octicon octicon-git-pull-request"></i> {{$.i18n.Tr "repo.pulls.merged"}}</a>
|
||||||
{{else if .LatestPullRequest.Issue.IsClosed}}
|
{{else if .LatestPullRequest.Issue.IsClosed}}
|
||||||
<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}" class="ui red small label"><i class="octicon octicon-issue-closed"></i> {{$.i18n.Tr "repo.issues.closed_title"}}</a>
|
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui red mini label"><i class="octicon octicon-issue-closed"></i> {{$.i18n.Tr "repo.issues.closed_title"}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a href="{{$.RepoLink}}/pulls/{{.LatestPullRequest.Issue.Index}}" class="ui green small label"><i class="octicon octicon-issue-opened"></i> {{$.i18n.Tr "repo.issues.open_title"}}</a>
|
<a href="{{.LatestPullRequest.Issue.HTMLURL}}" class="ui green mini label"><i class="octicon octicon-issue-opened"></i> {{$.i18n.Tr "repo.issues.open_title"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -26,7 +26,8 @@
|
|||||||
<span class="markdown-info"><i class="octicon octicon-markdown"></i> {{$.root.i18n.Tr "repo.diff.comment.markdown_info"}}</span>
|
<span class="markdown-info"><i class="octicon octicon-markdown"></i> {{$.root.i18n.Tr "repo.diff.comment.markdown_info"}}</span>
|
||||||
<div class="ui right floated">
|
<div class="ui right floated">
|
||||||
{{if $.reply}}
|
{{if $.reply}}
|
||||||
<button name="reply" value="{{$.reply}}" class="ui submit green tiny button btn-reply">{{$.root.i18n.Tr "repo.diff.comment.reply"}}</button>
|
<input type="hidden" name="reply" value="{{$.reply}}">
|
||||||
|
<button class="ui submit green tiny button btn-reply" onclick="submitReply(this);">{{$.root.i18n.Tr "repo.diff.comment.reply"}}</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{if $.root.CurrentReview}}
|
{{if $.root.CurrentReview}}
|
||||||
<button name="is_review" value="true" type="submit"
|
<button name="is_review" value="true" type="submit"
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
{{ template "repo/issue/view_content/pull". }}
|
{{ template "repo/issue/view_content/pull". }}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .IsSigned}}
|
{{if .IsSigned}}
|
||||||
{{ if and (or .IsRepoAdmin .IsRepoIssuesWriter (or (not .Issue.IsLocked))) (not .Repository.IsArchived) }}
|
{{ if and (or .IsRepoAdmin .IsIssuesWriter (or (not .Issue.IsLocked))) (not .Repository.IsArchived) }}
|
||||||
<div class="comment form">
|
<div class="comment form">
|
||||||
<a class="avatar" href="{{.SignedUser.HomeLink}}">
|
<a class="avatar" href="{{.SignedUser.HomeLink}}">
|
||||||
<img src="{{.SignedUser.RelAvatarLink}}">
|
<img src="{{.SignedUser.RelAvatarLink}}">
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
{{$.i18n.Tr "repo.pulls.reopen_to_merge"}}
|
{{$.i18n.Tr "repo.pulls.reopen_to_merge"}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{if .IsPullBranchDeletable}}
|
{{if and .IsPullBranchDeletable ( not .IsPullRequestBroken )}}
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div>
|
<div>
|
||||||
<a class="delete-button ui red button" href="" data-url="{{.DeleteBranchLink}}">{{$.i18n.Tr "repo.branch.delete" .HeadTarget}}</a>
|
<a class="delete-button ui red button" href="" data-url="{{.DeleteBranchLink}}">{{$.i18n.Tr "repo.branch.delete" .HeadTarget}}</a>
|
||||||
|
|||||||
@@ -426,6 +426,7 @@
|
|||||||
<input type="hidden" id="repolink" value="{{$.RepoRelPath}}">
|
<input type="hidden" id="repolink" value="{{$.RepoRelPath}}">
|
||||||
<!-- I know, there is probably a better way to do this -->
|
<!-- I know, there is probably a better way to do this -->
|
||||||
<input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/>
|
<input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/>
|
||||||
|
<input type="hidden" id="type" value="{{.IssueType}}">
|
||||||
|
|
||||||
<div class="ui basic modal remove-dependency">
|
<div class="ui basic modal remove-dependency">
|
||||||
<div class="ui icon header">
|
<div class="ui icon header">
|
||||||
|
|||||||
@@ -2777,6 +2777,12 @@
|
|||||||
"description": "search string",
|
"description": "search string",
|
||||||
"name": "q",
|
"name": "q",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "filter by type (issues / pulls) if set",
|
||||||
|
"name": "type",
|
||||||
|
"in": "query"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{if .IsResetForm}}
|
{{if .IsResetForm}}
|
||||||
<div class="required inline field {{if .Err_Password}}error{{end}}">
|
<div class="required inline field {{if .Err_Password}}error{{end}}">
|
||||||
<label for="password">{{.i18n.Tr "password"}}</label>
|
<label for="password">{{.i18n.Tr "settings.new_password"}}</label>
|
||||||
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" autofocus required>
|
<input id="password" name="password" type="password" value="{{.password}}" autocomplete="off" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
{{if not .user_signed_in}}
|
{{if not .user_signed_in}}
|
||||||
@@ -30,10 +30,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if .has_two_factor}}
|
||||||
|
<h4 class="ui dividing header">
|
||||||
|
{{.i18n.Tr "twofa"}}
|
||||||
|
</h4>
|
||||||
|
<div class="ui warning visible message">{{.i18n.Tr "settings.twofa_is_enrolled" | Str2html }}</div>
|
||||||
|
{{if .scratch_code}}
|
||||||
|
<div class="required inline field {{if .Err_Token}}error{{end}}">
|
||||||
|
<label for="token">{{.i18n.Tr "auth.scratch_code"}}</label>
|
||||||
|
<input id="token" name="token" type="text" autocomplete="off" autofocus required>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="scratch_code" value="true">
|
||||||
|
{{else}}
|
||||||
|
<div class="required inline field {{if .Err_Passcode}}error{{end}}">
|
||||||
|
<label for="passcode">{{.i18n.Tr "passcode"}}</label>
|
||||||
|
<input id="passcode" name="passcode" type="number" autocomplete="off" autofocus required>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label></label>
|
<label></label>
|
||||||
<button class="ui blue button">{{.i18n.Tr "auth.reset_password_helper"}}</button>
|
<button class="ui blue button">{{.i18n.Tr "auth.reset_password_helper"}}</button>
|
||||||
|
{{if and .has_two_factor (not .scratch_code)}}
|
||||||
|
<a href="{{.Link}}?code={{.Code}}&scratch_code=true">{{.i18n.Tr "auth.use_scratch_code" | Str2html}}</a>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
<p class="center">{{.i18n.Tr "auth.invalid_code"}}</p>
|
<p class="center">{{.i18n.Tr "auth.invalid_code"}}</p>
|
||||||
|
|||||||
Reference in New Issue
Block a user