mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-10 15:32:55 +09:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0b8e3c8e1 | ||
|
|
7ff8e863a5 | ||
|
|
c65e49d72f | ||
|
|
50084daa4c | ||
|
|
c7db7438b7 | ||
|
|
e11f042a95 | ||
|
|
87782636e6 | ||
|
|
b935472cdf | ||
|
|
8ac48584ec | ||
|
|
e898590c81 | ||
|
|
d407857d97 |
13
CHANGELOG.md
13
CHANGELOG.md
@@ -4,6 +4,19 @@ 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.14.4](https://github.com/go-gitea/gitea/releases/tag/v1.14.4) - 2021-07-06
|
||||||
|
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix relative links in postprocessed images (#16334) (#16340)
|
||||||
|
* Fix list_options GetStartEnd (#16303) (#16305)
|
||||||
|
* Fix API to use author for commits instead of committer (#16276) (#16277)
|
||||||
|
* Handle misencoding of login_source cfg in mssql (#16268) (#16275)
|
||||||
|
* Fixed issues not updated by commits (#16254) (#16261)
|
||||||
|
* Improve efficiency in FindRenderizableReferenceNumeric and getReference (#16251) (#16255)
|
||||||
|
* Use html.Parse rather than html.ParseFragment (#16223) (#16225)
|
||||||
|
* Fix milestone counters on new issue (#16183) (#16224)
|
||||||
|
* reqOrgMembership calls need to be preceded by reqToken (#16198) (#16219)
|
||||||
|
|
||||||
## [1.14.3](https://github.com/go-gitea/gitea/releases/tag/v1.14.3) - 2021-06-10
|
## [1.14.3](https://github.com/go-gitea/gitea/releases/tag/v1.14.3) - 2021-06-10
|
||||||
|
|
||||||
* SECURITY
|
* SECURITY
|
||||||
|
|||||||
@@ -144,7 +144,9 @@ func TestAPITeamSearch(t *testing.T) {
|
|||||||
var results TeamSearchResults
|
var results TeamSearchResults
|
||||||
|
|
||||||
session := loginUser(t, user.Name)
|
session := loginUser(t, user.Name)
|
||||||
|
csrf := GetCSRF(t, session, "/"+org.Name)
|
||||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "_team")
|
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "_team")
|
||||||
|
req.Header.Add("X-Csrf-Token", csrf)
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
DecodeJSON(t, resp, &results)
|
DecodeJSON(t, resp, &results)
|
||||||
assert.NotEmpty(t, results.Data)
|
assert.NotEmpty(t, results.Data)
|
||||||
@@ -154,7 +156,9 @@ func TestAPITeamSearch(t *testing.T) {
|
|||||||
// no access if not organization member
|
// no access if not organization member
|
||||||
user5 := models.AssertExistsAndLoadBean(t, &models.User{ID: 5}).(*models.User)
|
user5 := models.AssertExistsAndLoadBean(t, &models.User{ID: 5}).(*models.User)
|
||||||
session = loginUser(t, user5.Name)
|
session = loginUser(t, user5.Name)
|
||||||
|
csrf = GetCSRF(t, session, "/"+org.Name)
|
||||||
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "team")
|
req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s", org.Name, "team")
|
||||||
|
req.Header.Add("X-Csrf-Token", csrf)
|
||||||
resp = session.MakeRequest(t, req, http.StatusForbidden)
|
resp = session.MakeRequest(t, req, http.StatusForbidden)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,6 +141,12 @@ func (milestone *Milestone) checkForConsistency(t *testing.T) {
|
|||||||
actual := getCount(t, x.Where("is_closed=?", true), &Issue{MilestoneID: milestone.ID})
|
actual := getCount(t, x.Where("is_closed=?", true), &Issue{MilestoneID: milestone.ID})
|
||||||
assert.EqualValues(t, milestone.NumClosedIssues, actual,
|
assert.EqualValues(t, milestone.NumClosedIssues, actual,
|
||||||
"Unexpected number of closed issues for milestone %+v", milestone)
|
"Unexpected number of closed issues for milestone %+v", milestone)
|
||||||
|
|
||||||
|
completeness := 0
|
||||||
|
if milestone.NumIssues > 0 {
|
||||||
|
completeness = milestone.NumClosedIssues * 100 / milestone.NumIssues
|
||||||
|
}
|
||||||
|
assert.Equal(t, completeness, milestone.Completeness)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (label *Label) checkForConsistency(t *testing.T) {
|
func (label *Label) checkForConsistency(t *testing.T) {
|
||||||
|
|||||||
@@ -648,8 +648,10 @@ func (issue *Issue) doChangeStatus(e *xorm.Session, doer *User, isMergePull bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update issue count of milestone
|
// Update issue count of milestone
|
||||||
if err := updateMilestoneClosedNum(e, issue.MilestoneID); err != nil {
|
if issue.MilestoneID > 0 {
|
||||||
return nil, err
|
if err := updateMilestoneCounters(e, issue.MilestoneID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := issue.updateClosedNum(e); err != nil {
|
if err := issue.updateClosedNum(e); err != nil {
|
||||||
@@ -912,7 +914,7 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
|
|||||||
opts.Issue.Index = inserted.Index
|
opts.Issue.Index = inserted.Index
|
||||||
|
|
||||||
if opts.Issue.MilestoneID > 0 {
|
if opts.Issue.MilestoneID > 0 {
|
||||||
if _, err = e.Exec("UPDATE `milestone` SET num_issues=num_issues+1 WHERE id=?", opts.Issue.MilestoneID); err != nil {
|
if err := updateMilestoneCounters(e, opts.Issue.MilestoneID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,8 +129,12 @@ func GetMilestoneByRepoIDANDName(repoID int64, name string) (*Milestone, error)
|
|||||||
|
|
||||||
// GetMilestoneByID returns the milestone via id .
|
// GetMilestoneByID returns the milestone via id .
|
||||||
func GetMilestoneByID(id int64) (*Milestone, error) {
|
func GetMilestoneByID(id int64) (*Milestone, error) {
|
||||||
|
return getMilestoneByID(x, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMilestoneByID(e Engine, id int64) (*Milestone, error) {
|
||||||
var m Milestone
|
var m Milestone
|
||||||
has, err := x.ID(id).Get(&m)
|
has, err := e.ID(id).Get(&m)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if !has {
|
} else if !has {
|
||||||
@@ -155,10 +159,6 @@ func UpdateMilestone(m *Milestone, oldIsClosed bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := updateMilestoneCompleteness(sess, m.ID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if IsClosed changed, update milestone numbers of repository
|
// if IsClosed changed, update milestone numbers of repository
|
||||||
if oldIsClosed != m.IsClosed {
|
if oldIsClosed != m.IsClosed {
|
||||||
if err := updateRepoMilestoneNum(sess, m.RepoID); err != nil {
|
if err := updateRepoMilestoneNum(sess, m.RepoID); err != nil {
|
||||||
@@ -171,23 +171,31 @@ func UpdateMilestone(m *Milestone, oldIsClosed bool) error {
|
|||||||
|
|
||||||
func updateMilestone(e Engine, m *Milestone) error {
|
func updateMilestone(e Engine, m *Milestone) error {
|
||||||
m.Name = strings.TrimSpace(m.Name)
|
m.Name = strings.TrimSpace(m.Name)
|
||||||
_, err := e.ID(m.ID).AllCols().
|
_, err := e.ID(m.ID).AllCols().Update(m)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return updateMilestoneCounters(e, m.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// updateMilestoneCounters calculates NumIssues, NumClosesIssues and Completeness
|
||||||
|
func updateMilestoneCounters(e Engine, id int64) error {
|
||||||
|
_, err := e.ID(id).
|
||||||
SetExpr("num_issues", builder.Select("count(*)").From("issue").Where(
|
SetExpr("num_issues", builder.Select("count(*)").From("issue").Where(
|
||||||
builder.Eq{"milestone_id": m.ID},
|
builder.Eq{"milestone_id": id},
|
||||||
)).
|
)).
|
||||||
SetExpr("num_closed_issues", builder.Select("count(*)").From("issue").Where(
|
SetExpr("num_closed_issues", builder.Select("count(*)").From("issue").Where(
|
||||||
builder.Eq{
|
builder.Eq{
|
||||||
"milestone_id": m.ID,
|
"milestone_id": id,
|
||||||
"is_closed": true,
|
"is_closed": true,
|
||||||
},
|
},
|
||||||
)).
|
)).
|
||||||
Update(m)
|
Update(&Milestone{})
|
||||||
return err
|
if err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
func updateMilestoneCompleteness(e Engine, milestoneID int64) error {
|
_, err = e.Exec("UPDATE `milestone` SET completeness=100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) WHERE id=?",
|
||||||
_, err := e.Exec("UPDATE `milestone` SET completeness=100*num_closed_issues/(CASE WHEN num_issues > 0 THEN num_issues ELSE 1 END) WHERE id=?",
|
id,
|
||||||
milestoneID,
|
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -256,25 +264,15 @@ func changeMilestoneAssign(e *xorm.Session, doer *User, issue *Issue, oldMilesto
|
|||||||
}
|
}
|
||||||
|
|
||||||
if oldMilestoneID > 0 {
|
if oldMilestoneID > 0 {
|
||||||
if err := updateMilestoneTotalNum(e, oldMilestoneID); err != nil {
|
if err := updateMilestoneCounters(e, oldMilestoneID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if issue.IsClosed {
|
|
||||||
if err := updateMilestoneClosedNum(e, oldMilestoneID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if issue.MilestoneID > 0 {
|
if issue.MilestoneID > 0 {
|
||||||
if err := updateMilestoneTotalNum(e, issue.MilestoneID); err != nil {
|
if err := updateMilestoneCounters(e, issue.MilestoneID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if issue.IsClosed {
|
|
||||||
if err := updateMilestoneClosedNum(e, issue.MilestoneID); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if oldMilestoneID > 0 || issue.MilestoneID > 0 {
|
if oldMilestoneID > 0 || issue.MilestoneID > 0 {
|
||||||
@@ -558,29 +556,6 @@ func updateRepoMilestoneNum(e Engine, repoID int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateMilestoneTotalNum(e Engine, milestoneID int64) (err error) {
|
|
||||||
if _, err = e.Exec("UPDATE `milestone` SET num_issues=(SELECT count(*) FROM issue WHERE milestone_id=?) WHERE id=?",
|
|
||||||
milestoneID,
|
|
||||||
milestoneID,
|
|
||||||
); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateMilestoneCompleteness(e, milestoneID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateMilestoneClosedNum(e Engine, milestoneID int64) (err error) {
|
|
||||||
if _, err = e.Exec("UPDATE `milestone` SET num_closed_issues=(SELECT count(*) FROM issue WHERE milestone_id=? AND is_closed=?) WHERE id=?",
|
|
||||||
milestoneID,
|
|
||||||
true,
|
|
||||||
milestoneID,
|
|
||||||
); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return updateMilestoneCompleteness(e, milestoneID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// _____ _ _ _____ _
|
// _____ _ _ _____ _
|
||||||
// |_ _| __ __ _ ___| | _____ __| |_ _(_)_ __ ___ ___ ___
|
// |_ _| __ __ _ ___| | _____ __| |_ _(_)_ __ ___ ___ ___
|
||||||
// | || '__/ _` |/ __| |/ / _ \/ _` | | | | | '_ ` _ \ / _ \/ __|
|
// | || '__/ _` |/ __| |/ / _ \/ _` | | | | | '_ ` _ \ / _ \/ __|
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ func TestChangeMilestoneStatus(t *testing.T) {
|
|||||||
CheckConsistencyFor(t, &Repository{ID: milestone.RepoID}, &Milestone{})
|
CheckConsistencyFor(t, &Repository{ID: milestone.RepoID}, &Milestone{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateMilestoneClosedNum(t *testing.T) {
|
func TestUpdateMilestoneCounters(t *testing.T) {
|
||||||
assert.NoError(t, PrepareTestDatabase())
|
assert.NoError(t, PrepareTestDatabase())
|
||||||
issue := AssertExistsAndLoadBean(t, &Issue{MilestoneID: 1},
|
issue := AssertExistsAndLoadBean(t, &Issue{MilestoneID: 1},
|
||||||
"is_closed=0").(*Issue)
|
"is_closed=0").(*Issue)
|
||||||
@@ -224,14 +224,14 @@ func TestUpdateMilestoneClosedNum(t *testing.T) {
|
|||||||
issue.ClosedUnix = timeutil.TimeStampNow()
|
issue.ClosedUnix = timeutil.TimeStampNow()
|
||||||
_, err := x.ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
|
_, err := x.ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, updateMilestoneClosedNum(x, issue.MilestoneID))
|
assert.NoError(t, updateMilestoneCounters(x, issue.MilestoneID))
|
||||||
CheckConsistencyFor(t, &Milestone{})
|
CheckConsistencyFor(t, &Milestone{})
|
||||||
|
|
||||||
issue.IsClosed = false
|
issue.IsClosed = false
|
||||||
issue.ClosedUnix = 0
|
issue.ClosedUnix = 0
|
||||||
_, err = x.ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
|
_, err = x.ID(issue.ID).Cols("is_closed", "closed_unix").Update(issue)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, updateMilestoneClosedNum(x, issue.MilestoneID))
|
assert.NoError(t, updateMilestoneCounters(x, issue.MilestoneID))
|
||||||
CheckConsistencyFor(t, &Milestone{})
|
CheckConsistencyFor(t, &Milestone{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func (opts *ListOptions) setEnginePagination(e Engine) Engine {
|
|||||||
func (opts *ListOptions) GetStartEnd() (start, end int) {
|
func (opts *ListOptions) GetStartEnd() (start, end int) {
|
||||||
opts.setDefaultValues()
|
opts.setDefaultValues()
|
||||||
start = (opts.Page - 1) * opts.PageSize
|
start = (opts.Page - 1) * opts.PageSize
|
||||||
end = start + opts.Page
|
end = start + opts.PageSize
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,17 @@ var (
|
|||||||
_ convert.Conversion = &SSPIConfig{}
|
_ convert.Conversion = &SSPIConfig{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// jsonUnmarshalIgnoreErroneousBOM - due to a bug in xorm (see https://gitea.com/xorm/xorm/pulls/1957) - it's
|
||||||
|
// possible that a Blob may gain an unwanted prefix of 0xff 0xfe.
|
||||||
|
func jsonUnmarshalIgnoreErroneousBOM(bs []byte, v interface{}) error {
|
||||||
|
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
||||||
|
err := json.Unmarshal(bs, &v)
|
||||||
|
if err != nil && len(bs) > 2 && bs[0] == 0xff && bs[1] == 0xfe {
|
||||||
|
err = json.Unmarshal(bs[2:], &v)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// LDAPConfig holds configuration for LDAP login source.
|
// LDAPConfig holds configuration for LDAP login source.
|
||||||
type LDAPConfig struct {
|
type LDAPConfig struct {
|
||||||
*ldap.Source
|
*ldap.Source
|
||||||
@@ -76,8 +87,7 @@ type LDAPConfig struct {
|
|||||||
|
|
||||||
// FromDB fills up a LDAPConfig from serialized format.
|
// FromDB fills up a LDAPConfig from serialized format.
|
||||||
func (cfg *LDAPConfig) FromDB(bs []byte) error {
|
func (cfg *LDAPConfig) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg)
|
||||||
return json.Unmarshal(bs, &cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports a LDAPConfig to a serialized format.
|
// ToDB exports a LDAPConfig to a serialized format.
|
||||||
@@ -104,8 +114,7 @@ type SMTPConfig struct {
|
|||||||
|
|
||||||
// FromDB fills up an SMTPConfig from serialized format.
|
// FromDB fills up an SMTPConfig from serialized format.
|
||||||
func (cfg *SMTPConfig) FromDB(bs []byte) error {
|
func (cfg *SMTPConfig) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, cfg)
|
||||||
return json.Unmarshal(bs, cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports an SMTPConfig to a serialized format.
|
// ToDB exports an SMTPConfig to a serialized format.
|
||||||
@@ -122,8 +131,7 @@ type PAMConfig struct {
|
|||||||
|
|
||||||
// FromDB fills up a PAMConfig from serialized format.
|
// FromDB fills up a PAMConfig from serialized format.
|
||||||
func (cfg *PAMConfig) FromDB(bs []byte) error {
|
func (cfg *PAMConfig) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, cfg)
|
||||||
return json.Unmarshal(bs, &cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports a PAMConfig to a serialized format.
|
// ToDB exports a PAMConfig to a serialized format.
|
||||||
@@ -144,8 +152,7 @@ type OAuth2Config struct {
|
|||||||
|
|
||||||
// FromDB fills up an OAuth2Config from serialized format.
|
// FromDB fills up an OAuth2Config from serialized format.
|
||||||
func (cfg *OAuth2Config) FromDB(bs []byte) error {
|
func (cfg *OAuth2Config) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, cfg)
|
||||||
return json.Unmarshal(bs, cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports an SMTPConfig to a serialized format.
|
// ToDB exports an SMTPConfig to a serialized format.
|
||||||
@@ -165,8 +172,7 @@ type SSPIConfig struct {
|
|||||||
|
|
||||||
// FromDB fills up an SSPIConfig from serialized format.
|
// FromDB fills up an SSPIConfig from serialized format.
|
||||||
func (cfg *SSPIConfig) FromDB(bs []byte) error {
|
func (cfg *SSPIConfig) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, cfg)
|
||||||
return json.Unmarshal(bs, cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports an SSPIConfig to a serialized format.
|
// ToDB exports an SSPIConfig to a serialized format.
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ type UnitConfig struct{}
|
|||||||
|
|
||||||
// FromDB fills up a UnitConfig from serialized format.
|
// FromDB fills up a UnitConfig from serialized format.
|
||||||
func (cfg *UnitConfig) FromDB(bs []byte) error {
|
func (cfg *UnitConfig) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg)
|
||||||
return json.Unmarshal(bs, &cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports a UnitConfig to a serialized format.
|
// ToDB exports a UnitConfig to a serialized format.
|
||||||
@@ -45,8 +44,7 @@ type ExternalWikiConfig struct {
|
|||||||
|
|
||||||
// FromDB fills up a ExternalWikiConfig from serialized format.
|
// FromDB fills up a ExternalWikiConfig from serialized format.
|
||||||
func (cfg *ExternalWikiConfig) FromDB(bs []byte) error {
|
func (cfg *ExternalWikiConfig) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg)
|
||||||
return json.Unmarshal(bs, &cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports a ExternalWikiConfig to a serialized format.
|
// ToDB exports a ExternalWikiConfig to a serialized format.
|
||||||
@@ -64,8 +62,7 @@ type ExternalTrackerConfig struct {
|
|||||||
|
|
||||||
// FromDB fills up a ExternalTrackerConfig from serialized format.
|
// FromDB fills up a ExternalTrackerConfig from serialized format.
|
||||||
func (cfg *ExternalTrackerConfig) FromDB(bs []byte) error {
|
func (cfg *ExternalTrackerConfig) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg)
|
||||||
return json.Unmarshal(bs, &cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports a ExternalTrackerConfig to a serialized format.
|
// ToDB exports a ExternalTrackerConfig to a serialized format.
|
||||||
@@ -83,8 +80,7 @@ type IssuesConfig struct {
|
|||||||
|
|
||||||
// FromDB fills up a IssuesConfig from serialized format.
|
// FromDB fills up a IssuesConfig from serialized format.
|
||||||
func (cfg *IssuesConfig) FromDB(bs []byte) error {
|
func (cfg *IssuesConfig) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg)
|
||||||
return json.Unmarshal(bs, &cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports a IssuesConfig to a serialized format.
|
// ToDB exports a IssuesConfig to a serialized format.
|
||||||
@@ -106,8 +102,7 @@ type PullRequestsConfig struct {
|
|||||||
|
|
||||||
// FromDB fills up a PullRequestsConfig from serialized format.
|
// FromDB fills up a PullRequestsConfig from serialized format.
|
||||||
func (cfg *PullRequestsConfig) FromDB(bs []byte) error {
|
func (cfg *PullRequestsConfig) FromDB(bs []byte) error {
|
||||||
json := jsoniter.ConfigCompatibleWithStandardLibrary
|
return jsonUnmarshalIgnoreErroneousBOM(bs, &cfg)
|
||||||
return json.Unmarshal(bs, &cfg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToDB exports a PullRequestsConfig to a serialized format.
|
// ToDB exports a PullRequestsConfig to a serialized format.
|
||||||
|
|||||||
@@ -155,8 +155,8 @@ func ToCommit(repo *models.Repository, commit *git.Commit, userCache map[string]
|
|||||||
URL: repo.APIURL() + "/git/commits/" + commit.ID.String(),
|
URL: repo.APIURL() + "/git/commits/" + commit.ID.String(),
|
||||||
Author: &api.CommitUser{
|
Author: &api.CommitUser{
|
||||||
Identity: api.Identity{
|
Identity: api.Identity{
|
||||||
Name: commit.Committer.Name,
|
Name: commit.Author.Name,
|
||||||
Email: commit.Committer.Email,
|
Email: commit.Author.Email,
|
||||||
},
|
},
|
||||||
Date: commit.Author.When.Format(time.RFC3339),
|
Date: commit.Author.When.Format(time.RFC3339),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -334,40 +334,37 @@ func (ctx *postProcessCtx) postProcess(rawHTML []byte) ([]byte, error) {
|
|||||||
_, _ = res.WriteString("</body></html>")
|
_, _ = res.WriteString("</body></html>")
|
||||||
|
|
||||||
// parse the HTML
|
// parse the HTML
|
||||||
nodes, err := html.ParseFragment(res, nil)
|
node, err := html.Parse(res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &postProcessError{"invalid HTML", err}
|
return nil, &postProcessError{"invalid HTML", err}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, node := range nodes {
|
if node.Type == html.DocumentNode {
|
||||||
ctx.visitNode(node, true)
|
node = node.FirstChild
|
||||||
}
|
}
|
||||||
|
|
||||||
newNodes := make([]*html.Node, 0, len(nodes))
|
ctx.visitNode(node, true)
|
||||||
|
|
||||||
for _, node := range nodes {
|
nodes := make([]*html.Node, 0, 5)
|
||||||
if node.Data == "html" {
|
|
||||||
node = node.FirstChild
|
if node.Data == "html" {
|
||||||
for node != nil && node.Data != "body" {
|
node = node.FirstChild
|
||||||
node = node.NextSibling
|
for node != nil && node.Data != "body" {
|
||||||
}
|
node = node.NextSibling
|
||||||
}
|
|
||||||
if node == nil {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if node != nil {
|
||||||
if node.Data == "body" {
|
if node.Data == "body" {
|
||||||
child := node.FirstChild
|
child := node.FirstChild
|
||||||
for child != nil {
|
for child != nil {
|
||||||
newNodes = append(newNodes, child)
|
nodes = append(nodes, child)
|
||||||
child = child.NextSibling
|
child = child.NextSibling
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newNodes = append(newNodes, node)
|
nodes = append(nodes, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes = newNodes
|
|
||||||
|
|
||||||
// Create buffer in which the data will be placed again. We know that the
|
// Create buffer in which the data will be placed again. We know that the
|
||||||
// length will be at least that of res; to spare a few alloc+copy, we
|
// length will be at least that of res; to spare a few alloc+copy, we
|
||||||
// reuse res, resetting its length to 0.
|
// reuse res, resetting its length to 0.
|
||||||
@@ -404,7 +401,7 @@ func (ctx *postProcessCtx) visitNode(node *html.Node, visitText bool) {
|
|||||||
}
|
}
|
||||||
case html.ElementNode:
|
case html.ElementNode:
|
||||||
if node.Data == "img" {
|
if node.Data == "img" {
|
||||||
for _, attr := range node.Attr {
|
for i, attr := range node.Attr {
|
||||||
if attr.Key != "src" {
|
if attr.Key != "src" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -417,6 +414,7 @@ func (ctx *postProcessCtx) visitNode(node *html.Node, visitText bool) {
|
|||||||
|
|
||||||
attr.Val = util.URLJoin(prefix, attr.Val)
|
attr.Val = util.URLJoin(prefix, attr.Val)
|
||||||
}
|
}
|
||||||
|
node.Attr[i] = attr
|
||||||
}
|
}
|
||||||
} else if node.Data == "a" {
|
} else if node.Data == "a" {
|
||||||
visitText = false
|
visitText = false
|
||||||
|
|||||||
@@ -384,6 +384,32 @@ func TestRender_ShortLinks(t *testing.T) {
|
|||||||
`<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`)
|
`<p><a href="https://example.org" rel="nofollow">[[foobar]]</a></p>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRender_RelativeImages(t *testing.T) {
|
||||||
|
setting.AppURL = AppURL
|
||||||
|
setting.AppSubURL = AppSubURL
|
||||||
|
tree := util.URLJoin(AppSubURL, "src", "master")
|
||||||
|
|
||||||
|
test := func(input, expected, expectedWiki string) {
|
||||||
|
buffer := markdown.RenderString(input, tree, localMetas)
|
||||||
|
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
|
||||||
|
buffer = markdown.RenderWiki([]byte(input), setting.AppSubURL, localMetas)
|
||||||
|
assert.Equal(t, strings.TrimSpace(expectedWiki), strings.TrimSpace(buffer))
|
||||||
|
}
|
||||||
|
|
||||||
|
rawwiki := util.URLJoin(AppSubURL, "wiki", "raw")
|
||||||
|
mediatree := util.URLJoin(AppSubURL, "media", "master")
|
||||||
|
|
||||||
|
test(
|
||||||
|
`<img src="Link">`,
|
||||||
|
`<img src="`+util.URLJoin(mediatree, "Link")+`"/>`,
|
||||||
|
`<img src="`+util.URLJoin(rawwiki, "Link")+`"/>`)
|
||||||
|
|
||||||
|
test(
|
||||||
|
`<img src="./icon.png">`,
|
||||||
|
`<img src="`+util.URLJoin(mediatree, "icon.png")+`"/>`,
|
||||||
|
`<img src="`+util.URLJoin(rawwiki, "icon.png")+`"/>`)
|
||||||
|
}
|
||||||
|
|
||||||
func Test_ParseClusterFuzz(t *testing.T) {
|
func Test_ParseClusterFuzz(t *testing.T) {
|
||||||
setting.AppURL = AppURL
|
setting.AppURL = AppURL
|
||||||
setting.AppSubURL = AppSubURL
|
setting.AppSubURL = AppSubURL
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package references
|
package references
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -14,6 +15,8 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/markup/mdstripper"
|
"code.gitea.io/gitea/modules/markup/mdstripper"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
|
"github.com/yuin/goldmark/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -321,7 +324,7 @@ func FindRenderizableReferenceNumeric(content string, prOnly bool) (bool, *Rende
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r := getCrossReference([]byte(content), match[2], match[3], false, prOnly)
|
r := getCrossReference(util.StringToReadOnlyBytes(content), match[2], match[3], false, prOnly)
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
@@ -465,17 +468,16 @@ func findAllIssueReferencesBytes(content []byte, links []string) []*rawReference
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getCrossReference(content []byte, start, end int, fromLink bool, prOnly bool) *rawReference {
|
func getCrossReference(content []byte, start, end int, fromLink bool, prOnly bool) *rawReference {
|
||||||
refid := string(content[start:end])
|
sep := bytes.IndexAny(content[start:end], "#!")
|
||||||
sep := strings.IndexAny(refid, "#!")
|
|
||||||
if sep < 0 {
|
if sep < 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
isPull := refid[sep] == '!'
|
isPull := content[start+sep] == '!'
|
||||||
if prOnly && !isPull {
|
if prOnly && !isPull {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
repo := refid[:sep]
|
repo := string(content[start : start+sep])
|
||||||
issue := refid[sep+1:]
|
issue := string(content[start+sep+1 : end])
|
||||||
index, err := strconv.ParseInt(issue, 10, 64)
|
index, err := strconv.ParseInt(issue, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -986,10 +986,10 @@ func Routes() *web.Route {
|
|||||||
Delete(reqToken(), reqOrgMembership(), org.ConcealMember)
|
Delete(reqToken(), reqOrgMembership(), org.ConcealMember)
|
||||||
})
|
})
|
||||||
m.Group("/teams", func() {
|
m.Group("/teams", func() {
|
||||||
m.Combo("", reqToken()).Get(org.ListTeams).
|
m.Get("", org.ListTeams)
|
||||||
Post(reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
|
m.Post("", reqOrgOwnership(), bind(api.CreateTeamOption{}), org.CreateTeam)
|
||||||
m.Get("/search", org.SearchTeam)
|
m.Get("/search", org.SearchTeam)
|
||||||
}, reqOrgMembership())
|
}, reqToken(), reqOrgMembership())
|
||||||
m.Group("/labels", func() {
|
m.Group("/labels", func() {
|
||||||
m.Get("", org.ListLabels)
|
m.Get("", org.ListLabels)
|
||||||
m.Post("", reqToken(), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel)
|
m.Post("", reqToken(), reqOrgOwnership(), bind(api.CreateLabelOption{}), org.CreateLabel)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ func GetUserByParamsName(ctx *context.APIContext, name string) *models.User {
|
|||||||
user, err := models.GetUserByName(username)
|
user, err := models.GetUserByName(username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if models.IsErrUserNotExist(err) {
|
if models.IsErrUserNotExist(err) {
|
||||||
if redirectUserID, err := models.LookupUserRedirect(username); err == nil {
|
if redirectUserID, err2 := models.LookupUserRedirect(username); err2 == nil {
|
||||||
context.RedirectToUser(ctx.Context, username, redirectUserID)
|
context.RedirectToUser(ctx.Context, username, redirectUserID)
|
||||||
} else {
|
} else {
|
||||||
ctx.NotFound("GetUserByName", err)
|
ctx.NotFound("GetUserByName", err)
|
||||||
|
|||||||
@@ -193,16 +193,17 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
commits = repo_module.ListToPushCommits(l)
|
commits = repo_module.ListToPushCommits(l)
|
||||||
|
|
||||||
|
if err := repofiles.UpdateIssuesCommit(pusher, repo, commits.Commits, refName); err != nil {
|
||||||
|
log.Error("updateIssuesCommit: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
if len(commits.Commits) > setting.UI.FeedMaxCommitNum {
|
if len(commits.Commits) > setting.UI.FeedMaxCommitNum {
|
||||||
commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum]
|
commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum]
|
||||||
}
|
}
|
||||||
commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
||||||
notification.NotifyPushCommits(pusher, repo, opts, commits)
|
notification.NotifyPushCommits(pusher, repo, opts, commits)
|
||||||
|
|
||||||
if err := repofiles.UpdateIssuesCommit(pusher, repo, commits.Commits, refName); err != nil {
|
|
||||||
log.Error("updateIssuesCommit: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = models.RemoveDeletedBranch(repo.ID, branch); err != nil {
|
if err = models.RemoveDeletedBranch(repo.ID, branch); err != nil {
|
||||||
log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, branch, err)
|
log.Error("models.RemoveDeletedBranch %s/%s failed: %v", repo.ID, branch, err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user