Add units concept for modulable functions of a repository (#742)
* Add units concept for modulable functions of a repository * remove unused comment codes & fix lints and tests * remove unused comment codes * use struct config instead of map * fix lint * rm wrong files * fix tests
This commit is contained in:
parent
49fa03bf42
commit
8a421b1fd7
16 changed files with 668 additions and 89 deletions
|
@ -441,7 +441,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
|
|
||||||
}, func(ctx *context.Context) {
|
}, func(ctx *context.Context) {
|
||||||
ctx.Data["PageIsSettings"] = true
|
ctx.Data["PageIsSettings"] = true
|
||||||
})
|
}, context.UnitTypes())
|
||||||
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
|
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
|
||||||
|
|
||||||
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
|
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
|
||||||
|
@ -535,7 +535,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, reqSignIn, context.RepoAssignment(), repo.MustBeNotBare)
|
}, reqSignIn, context.RepoAssignment(), repo.MustBeNotBare, context.UnitTypes())
|
||||||
|
|
||||||
m.Group("/:username/:reponame", func() {
|
m.Group("/:username/:reponame", func() {
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
|
@ -581,7 +581,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.RawDiff)
|
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.RawDiff)
|
||||||
|
|
||||||
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.CompareDiff)
|
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.CompareDiff)
|
||||||
}, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare)
|
}, ignSignIn, context.RepoAssignment(), repo.MustBeNotBare, context.UnitTypes())
|
||||||
m.Group("/:username/:reponame", func() {
|
m.Group("/:username/:reponame", func() {
|
||||||
m.Get("/stars", repo.Stars)
|
m.Get("/stars", repo.Stars)
|
||||||
m.Get("/watchers", repo.Watchers)
|
m.Get("/watchers", repo.Watchers)
|
||||||
|
@ -591,7 +591,7 @@ func runWeb(ctx *cli.Context) error {
|
||||||
m.Group("/:reponame", func() {
|
m.Group("/:reponame", func() {
|
||||||
m.Get("", repo.SetEditorconfigIfExists, repo.Home)
|
m.Get("", repo.SetEditorconfigIfExists, repo.Home)
|
||||||
m.Get("\\.git$", repo.SetEditorconfigIfExists, repo.Home)
|
m.Get("\\.git$", repo.SetEditorconfigIfExists, repo.Home)
|
||||||
}, ignSignIn, context.RepoAssignment(true), context.RepoRef())
|
}, ignSignIn, context.RepoAssignment(true), context.RepoRef(), context.UnitTypes())
|
||||||
|
|
||||||
m.Group("/:reponame", func() {
|
m.Group("/:reponame", func() {
|
||||||
m.Group("/info/lfs", func() {
|
m.Group("/info/lfs", func() {
|
||||||
|
|
|
@ -76,10 +76,12 @@ var migrations = []Migration{
|
||||||
|
|
||||||
// v13 -> v14:v0.9.87
|
// v13 -> v14:v0.9.87
|
||||||
NewMigration("set comment updated with created", setCommentUpdatedWithCreated),
|
NewMigration("set comment updated with created", setCommentUpdatedWithCreated),
|
||||||
// v14
|
// v14 -> v15
|
||||||
NewMigration("create user column diff view style", createUserColumnDiffViewStyle),
|
NewMigration("create user column diff view style", createUserColumnDiffViewStyle),
|
||||||
// v15
|
// v15 -> v16
|
||||||
NewMigration("create user column allow create organization", createAllowCreateOrganizationColumn),
|
NewMigration("create user column allow create organization", createAllowCreateOrganizationColumn),
|
||||||
|
// V16 -> v17
|
||||||
|
NewMigration("create repo unit table and add units for all repos", addUnitsToTables),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate database to current version
|
// Migrate database to current version
|
||||||
|
|
117
models/migrations/v16.go
Normal file
117
models/migrations/v16.go
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/markdown"
|
||||||
|
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RepoUnit describes all units of a repository
|
||||||
|
type RepoUnit struct {
|
||||||
|
ID int64
|
||||||
|
RepoID int64 `xorm:"INDEX(s)"`
|
||||||
|
Type int `xorm:"INDEX(s)"`
|
||||||
|
Index int
|
||||||
|
Config map[string]string `xorm:"JSON"`
|
||||||
|
CreatedUnix int64 `xorm:"INDEX CREATED"`
|
||||||
|
Created time.Time `xorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enumerate all the unit types
|
||||||
|
const (
|
||||||
|
UnitTypeCode = iota + 1 // 1 code
|
||||||
|
UnitTypeIssues // 2 issues
|
||||||
|
UnitTypePRs // 3 PRs
|
||||||
|
UnitTypeCommits // 4 Commits
|
||||||
|
UnitTypeReleases // 5 Releases
|
||||||
|
UnitTypeWiki // 6 Wiki
|
||||||
|
UnitTypeSettings // 7 Settings
|
||||||
|
UnitTypeExternalWiki // 8 ExternalWiki
|
||||||
|
UnitTypeExternalTracker // 9 ExternalTracker
|
||||||
|
)
|
||||||
|
|
||||||
|
// Repo describes a repository
|
||||||
|
type Repo struct {
|
||||||
|
ID int64
|
||||||
|
EnableWiki, EnableExternalWiki, EnableIssues, EnableExternalTracker, EnablePulls bool
|
||||||
|
ExternalWikiURL, ExternalTrackerURL, ExternalTrackerFormat, ExternalTrackerStyle string
|
||||||
|
}
|
||||||
|
|
||||||
|
func addUnitsToTables(x *xorm.Engine) error {
|
||||||
|
var repos []Repo
|
||||||
|
err := x.Table("repository").Find(&repos)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Query repositories: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sess := x.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
|
||||||
|
if err := sess.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var repoUnit RepoUnit
|
||||||
|
if err := sess.CreateTable(&repoUnit); err != nil {
|
||||||
|
return fmt.Errorf("CreateTable RepoUnit: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sess.CreateUniques(&repoUnit); err != nil {
|
||||||
|
return fmt.Errorf("CreateUniques RepoUnit: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sess.CreateIndexes(&repoUnit); err != nil {
|
||||||
|
return fmt.Errorf("CreateIndexes RepoUnit: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, repo := range repos {
|
||||||
|
for i := 1; i <= 9; i++ {
|
||||||
|
if (i == UnitTypeWiki || i == UnitTypeExternalWiki) && !repo.EnableWiki {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if i == UnitTypeExternalWiki && !repo.EnableExternalWiki {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if i == UnitTypePRs && !repo.EnablePulls {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (i == UnitTypeIssues || i == UnitTypeExternalTracker) && !repo.EnableIssues {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if i == UnitTypeExternalTracker && !repo.EnableExternalTracker {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = make(map[string]string)
|
||||||
|
switch i {
|
||||||
|
case UnitTypeExternalTracker:
|
||||||
|
config["ExternalTrackerURL"] = repo.ExternalTrackerURL
|
||||||
|
config["ExternalTrackerFormat"] = repo.ExternalTrackerFormat
|
||||||
|
if len(repo.ExternalTrackerStyle) == 0 {
|
||||||
|
repo.ExternalTrackerStyle = markdown.IssueNameStyleNumeric
|
||||||
|
}
|
||||||
|
config["ExternalTrackerStyle"] = repo.ExternalTrackerStyle
|
||||||
|
case UnitTypeExternalWiki:
|
||||||
|
config["ExternalWikiURL"] = repo.ExternalWikiURL
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = sess.Insert(&RepoUnit{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: i,
|
||||||
|
Index: i,
|
||||||
|
Config: config,
|
||||||
|
}); err != nil {
|
||||||
|
return fmt.Errorf("Insert repo unit: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sess.Commit(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -106,6 +106,7 @@ func init() {
|
||||||
new(IssueUser),
|
new(IssueUser),
|
||||||
new(LFSMetaObject),
|
new(LFSMetaObject),
|
||||||
new(TwoFactor),
|
new(TwoFactor),
|
||||||
|
new(RepoUnit),
|
||||||
)
|
)
|
||||||
|
|
||||||
gonicNames := []string{"SSL", "UID"}
|
gonicNames := []string{"SSL", "UID"}
|
||||||
|
|
150
models/repo.go
150
models/repo.go
|
@ -200,17 +200,8 @@ type Repository struct {
|
||||||
IsMirror bool `xorm:"INDEX"`
|
IsMirror bool `xorm:"INDEX"`
|
||||||
*Mirror `xorm:"-"`
|
*Mirror `xorm:"-"`
|
||||||
|
|
||||||
// Advanced settings
|
ExternalMetas map[string]string `xorm:"-"`
|
||||||
EnableWiki bool `xorm:"NOT NULL DEFAULT true"`
|
Units []*RepoUnit `xorm:"-"`
|
||||||
EnableExternalWiki bool
|
|
||||||
ExternalWikiURL string
|
|
||||||
EnableIssues bool `xorm:"NOT NULL DEFAULT true"`
|
|
||||||
EnableExternalTracker bool
|
|
||||||
ExternalTrackerURL string
|
|
||||||
ExternalTrackerFormat string
|
|
||||||
ExternalTrackerStyle string
|
|
||||||
ExternalMetas map[string]string `xorm:"-"`
|
|
||||||
EnablePulls bool `xorm:"NOT NULL DEFAULT true"`
|
|
||||||
|
|
||||||
IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
IsFork bool `xorm:"INDEX NOT NULL DEFAULT false"`
|
||||||
ForkID int64 `xorm:"INDEX"`
|
ForkID int64 `xorm:"INDEX"`
|
||||||
|
@ -247,10 +238,6 @@ func (repo *Repository) AfterSet(colName string, _ xorm.Cell) {
|
||||||
repo.NumOpenPulls = repo.NumPulls - repo.NumClosedPulls
|
repo.NumOpenPulls = repo.NumPulls - repo.NumClosedPulls
|
||||||
case "num_closed_milestones":
|
case "num_closed_milestones":
|
||||||
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
|
repo.NumOpenMilestones = repo.NumMilestones - repo.NumClosedMilestones
|
||||||
case "external_tracker_style":
|
|
||||||
if len(repo.ExternalTrackerStyle) == 0 {
|
|
||||||
repo.ExternalTrackerStyle = markdown.IssueNameStyleNumeric
|
|
||||||
}
|
|
||||||
case "created_unix":
|
case "created_unix":
|
||||||
repo.Created = time.Unix(repo.CreatedUnix, 0).Local()
|
repo.Created = time.Unix(repo.CreatedUnix, 0).Local()
|
||||||
case "updated_unix":
|
case "updated_unix":
|
||||||
|
@ -307,6 +294,72 @@ func (repo *Repository) APIFormat(mode AccessMode) *api.Repository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *Repository) getUnits(e Engine) (err error) {
|
||||||
|
if repo.Units != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
repo.Units, err = getUnitsByRepoID(e, repo.ID)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUnitsByRepoID(e Engine, repoID int64) (units []*RepoUnit, err error) {
|
||||||
|
return units, e.Where("repo_id = ?", repoID).Find(&units)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableUnit if this repository enabled some unit
|
||||||
|
func (repo *Repository) EnableUnit(tp UnitType) bool {
|
||||||
|
repo.getUnits(x)
|
||||||
|
for _, unit := range repo.Units {
|
||||||
|
if unit.Type == tp {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrUnitNotExist organization does not exist
|
||||||
|
ErrUnitNotExist = errors.New("Unit does not exist")
|
||||||
|
)
|
||||||
|
|
||||||
|
// MustGetUnit always returns a RepoUnit object
|
||||||
|
func (repo *Repository) MustGetUnit(tp UnitType) *RepoUnit {
|
||||||
|
ru, err := repo.GetUnit(tp)
|
||||||
|
if err == nil {
|
||||||
|
return ru
|
||||||
|
}
|
||||||
|
|
||||||
|
if tp == UnitTypeExternalWiki {
|
||||||
|
return &RepoUnit{
|
||||||
|
Type: tp,
|
||||||
|
Config: new(ExternalWikiConfig),
|
||||||
|
}
|
||||||
|
} else if tp == UnitTypeExternalTracker {
|
||||||
|
return &RepoUnit{
|
||||||
|
Type: tp,
|
||||||
|
Config: new(ExternalTrackerConfig),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &RepoUnit{
|
||||||
|
Type: tp,
|
||||||
|
Config: new(UnitConfig),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUnit returns a RepoUnit object
|
||||||
|
func (repo *Repository) GetUnit(tp UnitType) (*RepoUnit, error) {
|
||||||
|
if err := repo.getUnits(x); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, unit := range repo.Units {
|
||||||
|
if unit.Type == tp {
|
||||||
|
return unit, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, ErrUnitNotExist
|
||||||
|
}
|
||||||
|
|
||||||
func (repo *Repository) getOwner(e Engine) (err error) {
|
func (repo *Repository) getOwner(e Engine) (err error) {
|
||||||
if repo.Owner != nil {
|
if repo.Owner != nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -334,15 +387,18 @@ func (repo *Repository) mustOwner(e Engine) *User {
|
||||||
|
|
||||||
// ComposeMetas composes a map of metas for rendering external issue tracker URL.
|
// ComposeMetas composes a map of metas for rendering external issue tracker URL.
|
||||||
func (repo *Repository) ComposeMetas() map[string]string {
|
func (repo *Repository) ComposeMetas() map[string]string {
|
||||||
if !repo.EnableExternalTracker {
|
unit, err := repo.GetUnit(UnitTypeExternalTracker)
|
||||||
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
} else if repo.ExternalMetas == nil {
|
}
|
||||||
|
|
||||||
|
if repo.ExternalMetas == nil {
|
||||||
repo.ExternalMetas = map[string]string{
|
repo.ExternalMetas = map[string]string{
|
||||||
"format": repo.ExternalTrackerFormat,
|
"format": unit.ExternalTrackerConfig().ExternalTrackerFormat,
|
||||||
"user": repo.MustOwner().Name,
|
"user": repo.MustOwner().Name,
|
||||||
"repo": repo.Name,
|
"repo": repo.Name,
|
||||||
}
|
}
|
||||||
switch repo.ExternalTrackerStyle {
|
switch unit.ExternalTrackerConfig().ExternalTrackerStyle {
|
||||||
case markdown.IssueNameStyleAlphanumeric:
|
case markdown.IssueNameStyleAlphanumeric:
|
||||||
repo.ExternalMetas["style"] = markdown.IssueNameStyleAlphanumeric
|
repo.ExternalMetas["style"] = markdown.IssueNameStyleAlphanumeric
|
||||||
default:
|
default:
|
||||||
|
@ -359,6 +415,8 @@ func (repo *Repository) DeleteWiki() {
|
||||||
for _, wikiPath := range wikiPaths {
|
for _, wikiPath := range wikiPaths {
|
||||||
RemoveAllWithNotice("Delete repository wiki", wikiPath)
|
RemoveAllWithNotice("Delete repository wiki", wikiPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x.Where("repo_id = ?", repo.ID).And("type = ?", UnitTypeWiki).Delete(new(RepoUnit))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) getAssignees(e Engine) (_ []*User, err error) {
|
func (repo *Repository) getAssignees(e Engine) (_ []*User, err error) {
|
||||||
|
@ -482,7 +540,7 @@ func (repo *Repository) CanEnablePulls() bool {
|
||||||
|
|
||||||
// AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled.
|
// AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled.
|
||||||
func (repo *Repository) AllowsPulls() bool {
|
func (repo *Repository) AllowsPulls() bool {
|
||||||
return repo.CanEnablePulls() && repo.EnablePulls
|
return repo.CanEnablePulls() && repo.EnableUnit(UnitTypePullRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanEnableEditor returns true if repository meets the requirements of web editor.
|
// CanEnableEditor returns true if repository meets the requirements of web editor.
|
||||||
|
@ -997,6 +1055,20 @@ func createRepository(e *xorm.Session, u *User, repo *Repository) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// insert units for repo
|
||||||
|
var units = make([]RepoUnit, 0, len(defaultRepoUnits))
|
||||||
|
for i, tp := range defaultRepoUnits {
|
||||||
|
units = append(units, RepoUnit{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: tp,
|
||||||
|
Index: i,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = e.Insert(&units); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
u.NumRepos++
|
u.NumRepos++
|
||||||
// Remember visibility preference.
|
// Remember visibility preference.
|
||||||
u.LastRepoVisibility = repo.IsPrivate
|
u.LastRepoVisibility = repo.IsPrivate
|
||||||
|
@ -1035,15 +1107,12 @@ func CreateRepository(u *User, opts CreateRepoOptions) (_ *Repository, err error
|
||||||
}
|
}
|
||||||
|
|
||||||
repo := &Repository{
|
repo := &Repository{
|
||||||
OwnerID: u.ID,
|
OwnerID: u.ID,
|
||||||
Owner: u,
|
Owner: u,
|
||||||
Name: opts.Name,
|
Name: opts.Name,
|
||||||
LowerName: strings.ToLower(opts.Name),
|
LowerName: strings.ToLower(opts.Name),
|
||||||
Description: opts.Description,
|
Description: opts.Description,
|
||||||
IsPrivate: opts.IsPrivate,
|
IsPrivate: opts.IsPrivate,
|
||||||
EnableWiki: true,
|
|
||||||
EnableIssues: true,
|
|
||||||
EnablePulls: true,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
|
@ -1380,6 +1449,25 @@ func UpdateRepository(repo *Repository, visibilityChanged bool) (err error) {
|
||||||
return sess.Commit()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateRepositoryUnits updates a repository's units
|
||||||
|
func UpdateRepositoryUnits(repo *Repository, units []RepoUnit) (err error) {
|
||||||
|
sess := x.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
if err = sess.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = sess.Where("repo_id = ?", repo.ID).Delete(new(RepoUnit)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = sess.Insert(units); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteRepository deletes a repository for a user or organization.
|
// DeleteRepository deletes a repository for a user or organization.
|
||||||
func DeleteRepository(uid, repoID int64) error {
|
func DeleteRepository(uid, repoID int64) error {
|
||||||
repo := &Repository{ID: repoID, OwnerID: uid}
|
repo := &Repository{ID: repoID, OwnerID: uid}
|
||||||
|
@ -1467,6 +1555,10 @@ func DeleteRepository(uid, repoID int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, err = sess.Where("repo_id = ?", repoID).Delete(new(RepoUnit)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if repo.IsFork {
|
if repo.IsFork {
|
||||||
if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repo.ForkID); err != nil {
|
if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repo.ForkID); err != nil {
|
||||||
return fmt.Errorf("decrease fork count: %v", err)
|
return fmt.Errorf("decrease fork count: %v", err)
|
||||||
|
|
|
@ -14,34 +14,42 @@ func TestRepo(t *testing.T) {
|
||||||
repo.Name = "testrepo"
|
repo.Name = "testrepo"
|
||||||
repo.Owner = new(User)
|
repo.Owner = new(User)
|
||||||
repo.Owner.Name = "testuser"
|
repo.Owner.Name = "testuser"
|
||||||
repo.ExternalTrackerFormat = "https://someurl.com/{user}/{repo}/{issue}"
|
externalTracker := RepoUnit{
|
||||||
|
Type: UnitTypeExternalTracker,
|
||||||
|
Config: &ExternalTrackerConfig{
|
||||||
|
ExternalTrackerFormat: "https://someurl.com/{user}/{repo}/{issue}",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
repo.Units = []*RepoUnit{
|
||||||
|
&externalTracker,
|
||||||
|
}
|
||||||
|
|
||||||
Convey("When no external tracker is configured", func() {
|
Convey("When no external tracker is configured", func() {
|
||||||
Convey("It should be nil", func() {
|
Convey("It should be nil", func() {
|
||||||
repo.EnableExternalTracker = false
|
repo.Units = nil
|
||||||
So(repo.ComposeMetas(), ShouldEqual, map[string]string(nil))
|
So(repo.ComposeMetas(), ShouldEqual, map[string]string(nil))
|
||||||
})
|
})
|
||||||
Convey("It should be nil even if other settings are present", func() {
|
Convey("It should be nil even if other settings are present", func() {
|
||||||
repo.EnableExternalTracker = false
|
repo.Units = nil
|
||||||
repo.ExternalTrackerFormat = "http://someurl.com/{user}/{repo}/{issue}"
|
|
||||||
repo.ExternalTrackerStyle = markdown.IssueNameStyleNumeric
|
|
||||||
So(repo.ComposeMetas(), ShouldEqual, map[string]string(nil))
|
So(repo.ComposeMetas(), ShouldEqual, map[string]string(nil))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("When an external issue tracker is configured", func() {
|
Convey("When an external issue tracker is configured", func() {
|
||||||
repo.EnableExternalTracker = true
|
repo.Units = []*RepoUnit{
|
||||||
|
&externalTracker,
|
||||||
|
}
|
||||||
Convey("It should default to numeric issue style", func() {
|
Convey("It should default to numeric issue style", func() {
|
||||||
metas := repo.ComposeMetas()
|
metas := repo.ComposeMetas()
|
||||||
So(metas["style"], ShouldEqual, markdown.IssueNameStyleNumeric)
|
So(metas["style"], ShouldEqual, markdown.IssueNameStyleNumeric)
|
||||||
})
|
})
|
||||||
Convey("It should pass through numeric issue style setting", func() {
|
Convey("It should pass through numeric issue style setting", func() {
|
||||||
repo.ExternalTrackerStyle = markdown.IssueNameStyleNumeric
|
externalTracker.ExternalTrackerConfig().ExternalTrackerStyle = markdown.IssueNameStyleNumeric
|
||||||
metas := repo.ComposeMetas()
|
metas := repo.ComposeMetas()
|
||||||
So(metas["style"], ShouldEqual, markdown.IssueNameStyleNumeric)
|
So(metas["style"], ShouldEqual, markdown.IssueNameStyleNumeric)
|
||||||
})
|
})
|
||||||
Convey("It should pass through alphanumeric issue style setting", func() {
|
Convey("It should pass through alphanumeric issue style setting", func() {
|
||||||
repo.ExternalTrackerStyle = markdown.IssueNameStyleAlphanumeric
|
externalTracker.ExternalTrackerConfig().ExternalTrackerStyle = markdown.IssueNameStyleAlphanumeric
|
||||||
metas := repo.ComposeMetas()
|
metas := repo.ComposeMetas()
|
||||||
So(metas["style"], ShouldEqual, markdown.IssueNameStyleAlphanumeric)
|
So(metas["style"], ShouldEqual, markdown.IssueNameStyleAlphanumeric)
|
||||||
})
|
})
|
||||||
|
|
137
models/repo_unit.go
Normal file
137
models/repo_unit.go
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/Unknwon/com"
|
||||||
|
"github.com/go-xorm/core"
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RepoUnit describes all units of a repository
|
||||||
|
type RepoUnit struct {
|
||||||
|
ID int64
|
||||||
|
RepoID int64 `xorm:"INDEX(s)"`
|
||||||
|
Type UnitType `xorm:"INDEX(s)"`
|
||||||
|
Index int
|
||||||
|
Config core.Conversion `xorm:"TEXT"`
|
||||||
|
CreatedUnix int64 `xorm:"INDEX CREATED"`
|
||||||
|
Created time.Time `xorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnitConfig describes common unit config
|
||||||
|
type UnitConfig struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromDB fills up a UnitConfig from serialized format.
|
||||||
|
func (cfg *UnitConfig) FromDB(bs []byte) error {
|
||||||
|
return json.Unmarshal(bs, &cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDB exports a UnitConfig to a serialized format.
|
||||||
|
func (cfg *UnitConfig) ToDB() ([]byte, error) {
|
||||||
|
return json.Marshal(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalWikiConfig describes external wiki config
|
||||||
|
type ExternalWikiConfig struct {
|
||||||
|
ExternalWikiURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromDB fills up a ExternalWikiConfig from serialized format.
|
||||||
|
func (cfg *ExternalWikiConfig) FromDB(bs []byte) error {
|
||||||
|
return json.Unmarshal(bs, &cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDB exports a ExternalWikiConfig to a serialized format.
|
||||||
|
func (cfg *ExternalWikiConfig) ToDB() ([]byte, error) {
|
||||||
|
return json.Marshal(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalTrackerConfig describes external tracker config
|
||||||
|
type ExternalTrackerConfig struct {
|
||||||
|
ExternalTrackerURL string
|
||||||
|
ExternalTrackerFormat string
|
||||||
|
ExternalTrackerStyle string
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromDB fills up a ExternalTrackerConfig from serialized format.
|
||||||
|
func (cfg *ExternalTrackerConfig) FromDB(bs []byte) error {
|
||||||
|
return json.Unmarshal(bs, &cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDB exports a ExternalTrackerConfig to a serialized format.
|
||||||
|
func (cfg *ExternalTrackerConfig) ToDB() ([]byte, error) {
|
||||||
|
return json.Marshal(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BeforeSet is invoked from XORM before setting the value of a field of this object.
|
||||||
|
func (r *RepoUnit) BeforeSet(colName string, val xorm.Cell) {
|
||||||
|
switch colName {
|
||||||
|
case "type":
|
||||||
|
switch UnitType(Cell2Int64(val)) {
|
||||||
|
case UnitTypeCode, UnitTypeIssues, UnitTypePullRequests, UnitTypeCommits, UnitTypeReleases,
|
||||||
|
UnitTypeWiki, UnitTypeSettings:
|
||||||
|
r.Config = new(UnitConfig)
|
||||||
|
case UnitTypeExternalWiki:
|
||||||
|
r.Config = new(ExternalWikiConfig)
|
||||||
|
case UnitTypeExternalTracker:
|
||||||
|
r.Config = new(ExternalTrackerConfig)
|
||||||
|
default:
|
||||||
|
panic("unrecognized repo unit type: " + com.ToStr(*val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AfterSet is invoked from XORM after setting the value of a field of this object.
|
||||||
|
func (r *RepoUnit) AfterSet(colName string, _ xorm.Cell) {
|
||||||
|
switch colName {
|
||||||
|
case "created_unix":
|
||||||
|
r.Created = time.Unix(r.CreatedUnix, 0).Local()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unit returns Unit
|
||||||
|
func (r *RepoUnit) Unit() Unit {
|
||||||
|
return Units[r.Type]
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeConfig returns config for UnitTypeCode
|
||||||
|
func (r *RepoUnit) CodeConfig() *UnitConfig {
|
||||||
|
return r.Config.(*UnitConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IssuesConfig returns config for UnitTypeIssues
|
||||||
|
func (r *RepoUnit) IssuesConfig() *UnitConfig {
|
||||||
|
return r.Config.(*UnitConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PullRequestsConfig returns config for UnitTypePullRequests
|
||||||
|
func (r *RepoUnit) PullRequestsConfig() *UnitConfig {
|
||||||
|
return r.Config.(*UnitConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitsConfig returns config for UnitTypeCommits
|
||||||
|
func (r *RepoUnit) CommitsConfig() *UnitConfig {
|
||||||
|
return r.Config.(*UnitConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReleasesConfig returns config for UnitTypeReleases
|
||||||
|
func (r *RepoUnit) ReleasesConfig() *UnitConfig {
|
||||||
|
return r.Config.(*UnitConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalWikiConfig returns config for UnitTypeExternalWiki
|
||||||
|
func (r *RepoUnit) ExternalWikiConfig() *ExternalWikiConfig {
|
||||||
|
return r.Config.(*ExternalWikiConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalTrackerConfig returns config for UnitTypeExternalTracker
|
||||||
|
func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig {
|
||||||
|
return r.Config.(*ExternalTrackerConfig)
|
||||||
|
}
|
137
models/unit.go
Normal file
137
models/unit.go
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package models
|
||||||
|
|
||||||
|
// UnitType is Unit's Type
|
||||||
|
type UnitType int
|
||||||
|
|
||||||
|
// Enumerate all the unit types
|
||||||
|
const (
|
||||||
|
UnitTypeCode UnitType = iota + 1 // 1 code
|
||||||
|
UnitTypeIssues // 2 issues
|
||||||
|
UnitTypePullRequests // 3 PRs
|
||||||
|
UnitTypeCommits // 4 Commits
|
||||||
|
UnitTypeReleases // 5 Releases
|
||||||
|
UnitTypeWiki // 6 Wiki
|
||||||
|
UnitTypeSettings // 7 Settings
|
||||||
|
UnitTypeExternalWiki // 8 ExternalWiki
|
||||||
|
UnitTypeExternalTracker // 9 ExternalTracker
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unit is a tab page of one repository
|
||||||
|
type Unit struct {
|
||||||
|
Type UnitType
|
||||||
|
NameKey string
|
||||||
|
URI string
|
||||||
|
DescKey string
|
||||||
|
Idx int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enumerate all the units
|
||||||
|
var (
|
||||||
|
UnitCode = Unit{
|
||||||
|
UnitTypeCode,
|
||||||
|
"repo.code",
|
||||||
|
"/",
|
||||||
|
"repo.code_desc",
|
||||||
|
0,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitIssues = Unit{
|
||||||
|
UnitTypeIssues,
|
||||||
|
"repo.issues",
|
||||||
|
"/issues",
|
||||||
|
"repo.issues_desc",
|
||||||
|
1,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitExternalTracker = Unit{
|
||||||
|
UnitTypeExternalTracker,
|
||||||
|
"repo.issues",
|
||||||
|
"/issues",
|
||||||
|
"repo.issues_desc",
|
||||||
|
1,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitPullRequests = Unit{
|
||||||
|
UnitTypePullRequests,
|
||||||
|
"repo.pulls",
|
||||||
|
"/pulls",
|
||||||
|
"repo.pulls_desc",
|
||||||
|
2,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitCommits = Unit{
|
||||||
|
UnitTypeCommits,
|
||||||
|
"repo.commits",
|
||||||
|
"/commits/master",
|
||||||
|
"repo.commits_desc",
|
||||||
|
3,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitReleases = Unit{
|
||||||
|
UnitTypeReleases,
|
||||||
|
"repo.releases",
|
||||||
|
"/releases",
|
||||||
|
"repo.releases_desc",
|
||||||
|
4,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitWiki = Unit{
|
||||||
|
UnitTypeWiki,
|
||||||
|
"repo.wiki",
|
||||||
|
"/wiki",
|
||||||
|
"repo.wiki_desc",
|
||||||
|
5,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitExternalWiki = Unit{
|
||||||
|
UnitTypeExternalWiki,
|
||||||
|
"repo.wiki",
|
||||||
|
"/wiki",
|
||||||
|
"repo.wiki_desc",
|
||||||
|
5,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitSettings = Unit{
|
||||||
|
UnitTypeSettings,
|
||||||
|
"repo.settings",
|
||||||
|
"/settings",
|
||||||
|
"repo.settings_desc",
|
||||||
|
6,
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultRepoUnits contains all the default unit types
|
||||||
|
defaultRepoUnits = []UnitType{
|
||||||
|
UnitTypeCode,
|
||||||
|
UnitTypeIssues,
|
||||||
|
UnitTypePullRequests,
|
||||||
|
UnitTypeCommits,
|
||||||
|
UnitTypeReleases,
|
||||||
|
UnitTypeWiki,
|
||||||
|
UnitTypeSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustRepoUnits contains the units could be disabled currently
|
||||||
|
MustRepoUnits = []UnitType{
|
||||||
|
UnitTypeCode,
|
||||||
|
UnitTypeCommits,
|
||||||
|
UnitTypeReleases,
|
||||||
|
UnitTypeSettings,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Units contains all the units
|
||||||
|
Units = map[UnitType]Unit{
|
||||||
|
UnitTypeCode: UnitCode,
|
||||||
|
UnitTypeIssues: UnitIssues,
|
||||||
|
UnitTypeExternalTracker: UnitExternalTracker,
|
||||||
|
UnitTypePullRequests: UnitPullRequests,
|
||||||
|
UnitTypeCommits: UnitCommits,
|
||||||
|
UnitTypeReleases: UnitReleases,
|
||||||
|
UnitTypeWiki: UnitWiki,
|
||||||
|
UnitTypeExternalWiki: UnitExternalWiki,
|
||||||
|
UnitTypeSettings: UnitSettings,
|
||||||
|
}
|
||||||
|
)
|
|
@ -477,3 +477,18 @@ func GitHookService() macaron.Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnitTypes returns a macaron middleware to set unit types to context variables.
|
||||||
|
func UnitTypes() macaron.Handler {
|
||||||
|
return func(ctx *Context) {
|
||||||
|
ctx.Data["UnitTypeCode"] = models.UnitTypeCode
|
||||||
|
ctx.Data["UnitTypeIssues"] = models.UnitTypeIssues
|
||||||
|
ctx.Data["UnitTypePullRequests"] = models.UnitTypePullRequests
|
||||||
|
ctx.Data["UnitTypeCommits"] = models.UnitTypeCommits
|
||||||
|
ctx.Data["UnitTypeReleases"] = models.UnitTypeReleases
|
||||||
|
ctx.Data["UnitTypeWiki"] = models.UnitTypeWiki
|
||||||
|
ctx.Data["UnitTypeSettings"] = models.UnitTypeSettings
|
||||||
|
ctx.Data["UnitTypeExternalWiki"] = models.UnitTypeExternalWiki
|
||||||
|
ctx.Data["UnitTypeExternalTracker"] = models.UnitTypeExternalTracker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -205,7 +205,7 @@ func orgAssignment(args ...bool) macaron.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustEnableIssues(ctx *context.APIContext) {
|
func mustEnableIssues(ctx *context.APIContext) {
|
||||||
if !ctx.Repo.Repository.EnableIssues || ctx.Repo.Repository.EnableExternalTracker {
|
if !ctx.Repo.Repository.EnableUnit(models.UnitTypeIssues) {
|
||||||
ctx.Status(404)
|
ctx.Status(404)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,13 +59,15 @@ var (
|
||||||
|
|
||||||
// MustEnableIssues check if repository enable internal issues
|
// MustEnableIssues check if repository enable internal issues
|
||||||
func MustEnableIssues(ctx *context.Context) {
|
func MustEnableIssues(ctx *context.Context) {
|
||||||
if !ctx.Repo.Repository.EnableIssues {
|
if !ctx.Repo.Repository.EnableUnit(models.UnitTypeIssues) &&
|
||||||
|
!ctx.Repo.Repository.EnableUnit(models.UnitTypeExternalTracker) {
|
||||||
ctx.Handle(404, "MustEnableIssues", nil)
|
ctx.Handle(404, "MustEnableIssues", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Repo.Repository.EnableExternalTracker {
|
unit, err := ctx.Repo.Repository.GetUnit(models.UnitTypeExternalTracker)
|
||||||
ctx.Redirect(ctx.Repo.Repository.ExternalTrackerURL)
|
if err == nil {
|
||||||
|
ctx.Redirect(unit.ExternalTrackerConfig().ExternalTrackerURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,18 +143,70 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||||
ctx.Redirect(repo.Link() + "/settings")
|
ctx.Redirect(repo.Link() + "/settings")
|
||||||
|
|
||||||
case "advanced":
|
case "advanced":
|
||||||
repo.EnableWiki = form.EnableWiki
|
var units []models.RepoUnit
|
||||||
repo.EnableExternalWiki = form.EnableExternalWiki
|
|
||||||
repo.ExternalWikiURL = form.ExternalWikiURL
|
|
||||||
repo.EnableIssues = form.EnableIssues
|
|
||||||
repo.EnableExternalTracker = form.EnableExternalTracker
|
|
||||||
repo.ExternalTrackerURL = form.ExternalTrackerURL
|
|
||||||
repo.ExternalTrackerFormat = form.TrackerURLFormat
|
|
||||||
repo.ExternalTrackerStyle = form.TrackerIssueStyle
|
|
||||||
repo.EnablePulls = form.EnablePulls
|
|
||||||
|
|
||||||
if err := models.UpdateRepository(repo, false); err != nil {
|
for _, tp := range models.MustRepoUnits {
|
||||||
ctx.Handle(500, "UpdateRepository", err)
|
units = append(units, models.RepoUnit{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: tp,
|
||||||
|
Index: int(tp),
|
||||||
|
Config: new(models.UnitConfig),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.EnableWiki {
|
||||||
|
if form.EnableExternalWiki {
|
||||||
|
units = append(units, models.RepoUnit{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: models.UnitTypeExternalWiki,
|
||||||
|
Index: int(models.UnitTypeExternalWiki),
|
||||||
|
Config: &models.ExternalWikiConfig{
|
||||||
|
ExternalWikiURL: form.ExternalWikiURL,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
units = append(units, models.RepoUnit{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: models.UnitTypeWiki,
|
||||||
|
Index: int(models.UnitTypeWiki),
|
||||||
|
Config: new(models.UnitConfig),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.EnableIssues {
|
||||||
|
if form.EnableExternalTracker {
|
||||||
|
units = append(units, models.RepoUnit{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: models.UnitTypeExternalWiki,
|
||||||
|
Index: int(models.UnitTypeExternalWiki),
|
||||||
|
Config: &models.ExternalTrackerConfig{
|
||||||
|
ExternalTrackerURL: form.ExternalTrackerURL,
|
||||||
|
ExternalTrackerFormat: form.TrackerURLFormat,
|
||||||
|
ExternalTrackerStyle: form.TrackerIssueStyle,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
units = append(units, models.RepoUnit{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: models.UnitTypeIssues,
|
||||||
|
Index: int(models.UnitTypeIssues),
|
||||||
|
Config: new(models.UnitConfig),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if form.EnablePulls {
|
||||||
|
units = append(units, models.RepoUnit{
|
||||||
|
RepoID: repo.ID,
|
||||||
|
Type: models.UnitTypePullRequests,
|
||||||
|
Index: int(models.UnitTypePullRequests),
|
||||||
|
Config: new(models.UnitConfig),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := models.UpdateRepositoryUnits(repo, units); err != nil {
|
||||||
|
ctx.Handle(500, "UpdateRepositoryUnits", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
log.Trace("Repository advanced settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||||
|
@ -281,12 +333,6 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||||
repo.DeleteWiki()
|
repo.DeleteWiki()
|
||||||
log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name)
|
||||||
|
|
||||||
repo.EnableWiki = false
|
|
||||||
if err := models.UpdateRepository(repo, false); err != nil {
|
|
||||||
ctx.Handle(500, "UpdateRepository", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success"))
|
ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success"))
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,15 @@ const (
|
||||||
|
|
||||||
// MustEnableWiki check if wiki is enabled, if external then redirect
|
// MustEnableWiki check if wiki is enabled, if external then redirect
|
||||||
func MustEnableWiki(ctx *context.Context) {
|
func MustEnableWiki(ctx *context.Context) {
|
||||||
if !ctx.Repo.Repository.EnableWiki {
|
if !ctx.Repo.Repository.EnableUnit(models.UnitTypeWiki) &&
|
||||||
|
!ctx.Repo.Repository.EnableUnit(models.UnitTypeExternalWiki) {
|
||||||
ctx.Handle(404, "MustEnableWiki", nil)
|
ctx.Handle(404, "MustEnableWiki", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Repo.Repository.EnableExternalWiki {
|
unit, err := ctx.Repo.Repository.GetUnit(models.UnitTypeExternalWiki)
|
||||||
ctx.Redirect(ctx.Repo.Repository.ExternalWikiURL)
|
if err == nil {
|
||||||
|
ctx.Redirect(unit.ExternalWikiConfig().ExternalWikiURL)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,7 +236,7 @@ func Issues(ctx *context.Context) {
|
||||||
for _, repo := range repos {
|
for _, repo := range repos {
|
||||||
if (isPullList && repo.NumPulls == 0) ||
|
if (isPullList && repo.NumPulls == 0) ||
|
||||||
(!isPullList &&
|
(!isPullList &&
|
||||||
(!repo.EnableIssues || repo.EnableExternalTracker || repo.NumIssues == 0)) {
|
(!repo.EnableUnit(models.UnitTypeIssues) || repo.NumIssues == 0)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,30 +49,48 @@
|
||||||
{{if not (or .IsBareRepo .IsDiffCompare)}}
|
{{if not (or .IsBareRepo .IsDiffCompare)}}
|
||||||
<div class="ui tabs container">
|
<div class="ui tabs container">
|
||||||
<div class="ui tabular menu navbar">
|
<div class="ui tabular menu navbar">
|
||||||
|
{{if .Repository.EnableUnit $.UnitTypeCode}}
|
||||||
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}">
|
<a class="{{if .PageIsViewCode}}active{{end}} item" href="{{.RepoLink}}">
|
||||||
<i class="octicon octicon-code"></i> {{.i18n.Tr "repo.code"}}
|
<i class="octicon octicon-code"></i> {{.i18n.Tr "repo.code"}}
|
||||||
</a>
|
</a>
|
||||||
{{if .Repository.EnableIssues}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if .Repository.EnableUnit $.UnitTypeIssues}}
|
||||||
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">
|
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">
|
||||||
<i class="octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues"}} {{if not .Repository.EnableExternalTracker}}<span class="ui {{if not .Repository.NumOpenIssues}}gray{{else}}blue{{end}} small label">{{.Repository.NumOpenIssues}}{{end}}</span>
|
<i class="octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues"}} <span class="ui {{if not .Repository.NumOpenIssues}}gray{{else}}blue{{end}} small label">{{.Repository.NumOpenIssues}}</span>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if .Repository.EnableUnit $.UnitTypeExternalTracker}}
|
||||||
|
<a class="{{if .PageIsIssueList}}active{{end}} item" href="{{.RepoLink}}/issues">
|
||||||
|
<i class="octicon octicon-issue-opened"></i> {{.i18n.Tr "repo.issues"}} </span>
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{if .Repository.AllowsPulls}}
|
{{if .Repository.AllowsPulls}}
|
||||||
<a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls">
|
<a class="{{if .PageIsPullList}}active{{end}} item" href="{{.RepoLink}}/pulls">
|
||||||
<i class="octicon octicon-git-pull-request"></i> {{.i18n.Tr "repo.pulls"}} <span class="ui {{if not .Repository.NumOpenPulls}}gray{{else}}blue{{end}} small label">{{.Repository.NumOpenPulls}}</span>
|
<i class="octicon octicon-git-pull-request"></i> {{.i18n.Tr "repo.pulls"}} <span class="ui {{if not .Repository.NumOpenPulls}}gray{{else}}blue{{end}} small label">{{.Repository.NumOpenPulls}}</span>
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if .Repository.EnableUnit $.UnitTypeCommits}}
|
||||||
<a class="{{if (or (.PageIsCommits) (.PageIsDiff))}}active{{end}} item" href="{{.RepoLink}}/commits/{{EscapePound .BranchName}}">
|
<a class="{{if (or (.PageIsCommits) (.PageIsDiff))}}active{{end}} item" href="{{.RepoLink}}/commits/{{EscapePound .BranchName}}">
|
||||||
<i class="octicon octicon-history"></i> {{.i18n.Tr "repo.commits"}} <span class="ui {{if not .CommitsCount}}gray{{else}}blue{{end}} small label">{{.CommitsCount}}</span>
|
<i class="octicon octicon-history"></i> {{.i18n.Tr "repo.commits"}} <span class="ui {{if not .CommitsCount}}gray{{else}}blue{{end}} small label">{{.CommitsCount}}</span>
|
||||||
</a>
|
</a>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{if .Repository.EnableUnit $.UnitTypeReleases}}
|
||||||
<a class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases">
|
<a class="{{if .PageIsReleaseList}}active{{end}} item" href="{{.RepoLink}}/releases">
|
||||||
<i class="octicon octicon-tag"></i> {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .Repository.NumTags}}gray{{else}}blue{{end}} small label">{{.Repository.NumTags}}</span>
|
<i class="octicon octicon-tag"></i> {{.i18n.Tr "repo.releases"}} <span class="ui {{if not .Repository.NumTags}}gray{{else}}blue{{end}} small label">{{.Repository.NumTags}}</span>
|
||||||
</a>
|
</a>
|
||||||
{{if .Repository.EnableWiki}}
|
{{end}}
|
||||||
|
|
||||||
|
{{if or (.Repository.EnableUnit $.UnitTypeWiki) (.Repository.EnableUnit $.UnitTypeExternalWiki)}}
|
||||||
<a class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki">
|
<a class="{{if .PageIsWiki}}active{{end}} item" href="{{.RepoLink}}/wiki">
|
||||||
<i class="octicon octicon-book"></i> {{.i18n.Tr "repo.wiki"}}
|
<i class="octicon octicon-book"></i> {{.i18n.Tr "repo.wiki"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if .IsRepositoryAdmin}}
|
{{if .IsRepositoryAdmin}}
|
||||||
<div class="right menu">
|
<div class="right menu">
|
||||||
<a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings">
|
<a class="{{if .PageIsSettings}}active{{end}} item" href="{{.RepoLink}}/settings">
|
||||||
|
|
|
@ -114,26 +114,26 @@
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label>{{.i18n.Tr "repo.wiki"}}</label>
|
<label>{{.i18n.Tr "repo.wiki"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input class="enable-system" name="enable_wiki" type="checkbox" data-target="#wiki_box" {{if .Repository.EnableWiki}}checked{{end}}>
|
<input class="enable-system" name="enable_wiki" type="checkbox" data-target="#wiki_box" {{if or (.Repository.EnableUnit $.UnitTypeWiki) (.Repository.EnableUnit $.UnitTypeExternalWiki)}}checked{{end}}>
|
||||||
<label>{{.i18n.Tr "repo.settings.wiki_desc"}}</label>
|
<label>{{.i18n.Tr "repo.settings.wiki_desc"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field {{if not .Repository.EnableWiki}}disabled{{end}}" id="wiki_box">
|
<div class="field {{if not (.Repository.EnableUnit $.UnitTypeWiki)}}disabled{{end}}" id="wiki_box">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="false" data-target="#external_wiki_box" {{if not .Repository.EnableExternalWiki}}checked{{end}}/>
|
<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="false" data-target="#external_wiki_box" {{if not (.Repository.EnableUnit $.UnitTypeExternalWiki)}}checked{{end}}/>
|
||||||
<label>{{.i18n.Tr "repo.settings.use_internal_wiki"}}</label>
|
<label>{{.i18n.Tr "repo.settings.use_internal_wiki"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.EnableExternalWiki}}checked{{end}}/>
|
<input class="hidden enable-system-radio" tabindex="0" name="enable_external_wiki" type="radio" value="true" data-target="#external_wiki_box" {{if .Repository.EnableUnit $.UnitTypeExternalWiki}}checked{{end}}/>
|
||||||
<label>{{.i18n.Tr "repo.settings.use_external_wiki"}}</label>
|
<label>{{.i18n.Tr "repo.settings.use_external_wiki"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field {{if not .Repository.EnableExternalWiki}}disabled{{end}}" id="external_wiki_box">
|
<div class="field {{if not (.Repository.EnableUnit $.UnitTypeExternalWiki)}}disabled{{end}}" id="external_wiki_box">
|
||||||
<label for="external_wiki_url">{{.i18n.Tr "repo.settings.external_wiki_url"}}</label>
|
<label for="external_wiki_url">{{.i18n.Tr "repo.settings.external_wiki_url"}}</label>
|
||||||
<input id="external_wiki_url" name="external_wiki_url" type="url" value="{{.Repository.ExternalWikiURL}}">
|
<input id="external_wiki_url" name="external_wiki_url" type="url" value="{{(.Repository.MustGetUnit $.UnitTypeExternalWiki).ExternalWikiConfig.ExternalWikiURL}}">
|
||||||
<p class="help">{{.i18n.Tr "repo.settings.external_wiki_url_desc"}}</p>
|
<p class="help">{{.i18n.Tr "repo.settings.external_wiki_url_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -143,45 +143,47 @@
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label>{{.i18n.Tr "repo.issues"}}</label>
|
<label>{{.i18n.Tr "repo.issues"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input class="enable-system" name="enable_issues" type="checkbox" data-target="#issue_box" {{if .Repository.EnableIssues}}checked{{end}}>
|
<input class="enable-system" name="enable_issues" type="checkbox" data-target="#issue_box" {{if or (.Repository.EnableUnit $.UnitTypeIssues) (.Repository.EnableUnit $.UnitTypeExternalTracker)}}checked{{end}}>
|
||||||
<label>{{.i18n.Tr "repo.settings.issues_desc"}}</label>
|
<label>{{.i18n.Tr "repo.settings.issues_desc"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field {{if not .Repository.EnableIssues}}disabled{{end}}" id="issue_box">
|
<div class="field {{if not (.Repository.EnableUnit $.UnitTypeIssues)}}disabled{{end}}" id="issue_box">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="false" data-target="#external_issue_box" {{if not .Repository.EnableExternalTracker}}checked{{end}}/>
|
<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="false" data-target="#external_issue_box" {{if not (.Repository.EnableUnit $.UnitTypeExternalTracker)}}checked{{end}}/>
|
||||||
<label>{{.i18n.Tr "repo.settings.use_internal_issue_tracker"}}</label>
|
<label>{{.i18n.Tr "repo.settings.use_internal_issue_tracker"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="true" data-target="#external_issue_box" {{if .Repository.EnableExternalTracker}}checked{{end}}/>
|
<input class="hidden enable-system-radio" tabindex="0" name="enable_external_tracker" type="radio" value="true" data-target="#external_issue_box" {{if .Repository.EnableUnit $.UnitTypeExternalTracker}}checked{{end}}/>
|
||||||
<label>{{.i18n.Tr "repo.settings.use_external_issue_tracker"}}</label>
|
<label>{{.i18n.Tr "repo.settings.use_external_issue_tracker"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field {{if not .Repository.EnableExternalTracker}}disabled{{end}}" id="external_issue_box">
|
<div class="field {{if not (.Repository.EnableUnit $.UnitTypeExternalTracker)}}disabled{{end}}" id="external_issue_box">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="external_tracker_url">{{.i18n.Tr "repo.settings.external_tracker_url"}}</label>
|
<label for="external_tracker_url">{{.i18n.Tr "repo.settings.external_tracker_url"}}</label>
|
||||||
<input id="external_tracker_url" name="external_tracker_url" type="url" value="{{.Repository.ExternalTrackerURL}}">
|
<input id="external_tracker_url" name="external_tracker_url" type="url" value="{{(.Repository.MustGetUnit $.UnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerURL}}">
|
||||||
<p class="help">{{.i18n.Tr "repo.settings.external_tracker_url_desc"}}</p>
|
<p class="help">{{.i18n.Tr "repo.settings.external_tracker_url_desc"}}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label for="tracker_url_format">{{.i18n.Tr "repo.settings.tracker_url_format"}}</label>
|
<label for="tracker_url_format">{{.i18n.Tr "repo.settings.tracker_url_format"}}</label>
|
||||||
<input id="tracker_url_format" name="tracker_url_format" type="url" value="{{.Repository.ExternalTrackerFormat}}" placeholder="e.g. https://github.com/{user}/{repo}/issues/{index}">
|
<input id="tracker_url_format" name="tracker_url_format" type="url" value="{{(.Repository.MustGetUnit $.UnitTypeExternalTracker).ExternalTrackerConfig.ExternalTrackerFormat}}" placeholder="e.g. https://github.com/{user}/{repo}/issues/{index}">
|
||||||
<p class="help">{{.i18n.Tr "repo.settings.tracker_url_format_desc" | Str2html}}</p>
|
<p class="help">{{.i18n.Tr "repo.settings.tracker_url_format_desc" | Str2html}}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="inline fields">
|
<div class="inline fields">
|
||||||
<label for="issue_style">{{.i18n.Tr "repo.settings.tracker_issue_style"}}</label>
|
<label for="issue_style">{{.i18n.Tr "repo.settings.tracker_issue_style"}}</label>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
<input class="hidden" tabindex="0" name="tracker_issue_style" type="radio" value="numeric" {{if eq .Repository.ExternalTrackerStyle "numeric"}}checked=""{{end}}/>
|
{{$externalTracker := (.Repository.MustGetUnit $.UnitTypeExternalTracker)}}
|
||||||
|
{{$externalTrackerStyle := $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle}}
|
||||||
|
<input class="hidden" tabindex="0" name="tracker_issue_style" type="radio" value="numeric" {{if $externalTrackerStyle}}{{if eq $externalTrackerStyle "numeric"}}checked=""{{end}}{{end}}/>
|
||||||
<label>{{.i18n.Tr "repo.settings.tracker_issue_style.numeric"}} <span class="ui light grey text">(#1234)</span></label>
|
<label>{{.i18n.Tr "repo.settings.tracker_issue_style.numeric"}} <span class="ui light grey text">(#1234)</span></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="ui radio checkbox">
|
<div class="ui radio checkbox">
|
||||||
<input class="hidden" tabindex="0" name="tracker_issue_style" type="radio" value="alphanumeric" {{if eq .Repository.ExternalTrackerStyle "alphanumeric"}}checked=""{{end}}/>
|
<input class="hidden" tabindex="0" name="tracker_issue_style" type="radio" value="alphanumeric" {{if $externalTrackerStyle}}{{if eq $externalTracker.ExternalTrackerConfig.ExternalTrackerStyle "alphanumeric"}}checked=""{{end}}{{end}} />
|
||||||
<label>{{.i18n.Tr "repo.settings.tracker_issue_style.alphanumeric"}} <span class="ui light grey text">(ABC-123, DEFG-234)</span></label>
|
<label>{{.i18n.Tr "repo.settings.tracker_issue_style.alphanumeric"}} <span class="ui light grey text">(ABC-123, DEFG-234)</span></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -195,7 +197,7 @@
|
||||||
<div class="inline field">
|
<div class="inline field">
|
||||||
<label>{{.i18n.Tr "repo.pulls"}}</label>
|
<label>{{.i18n.Tr "repo.pulls"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
<input name="enable_pulls" type="checkbox" {{if .Repository.EnablePulls}}checked{{end}}>
|
<input name="enable_pulls" type="checkbox" {{if .Repository.EnableUnit $.UnitTypePullRequests}}checked{{end}}>
|
||||||
<label>{{.i18n.Tr "repo.settings.pulls_desc"}}</label>
|
<label>{{.i18n.Tr "repo.settings.pulls_desc"}}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -236,7 +238,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if .Repository.EnableWiki}}
|
{{if .Repository.EnableUnit $.UnitTypeWiki}}
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
<div class="item">
|
<div class="item">
|
||||||
|
@ -370,7 +372,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{if .Repository.EnableWiki}}
|
{{if .Repository.EnableUnit $.UnitTypeWiki}}
|
||||||
<div class="ui small modal" id="delete-wiki-modal">
|
<div class="ui small modal" id="delete-wiki-modal">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{.i18n.Tr "repo.settings.wiki-delete"}}
|
{{.i18n.Tr "repo.settings.wiki-delete"}}
|
||||||
|
|
Reference in a new issue