wiki: finish new
This commit is contained in:
parent
c50a3503e6
commit
392f3ee210
15 changed files with 474 additions and 2236 deletions
|
@ -534,6 +534,7 @@ func runWeb(ctx *cli.Context) {
|
||||||
|
|
||||||
m.Group("/wiki", func() {
|
m.Group("/wiki", func() {
|
||||||
m.Get("/?:page", repo.Wiki)
|
m.Get("/?:page", repo.Wiki)
|
||||||
|
m.Get("/_list", repo.WikiList)
|
||||||
|
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
m.Combo("/_new").Get(repo.NewWiki).
|
m.Combo("/_new").Get(repo.NewWiki).
|
||||||
|
|
|
@ -542,6 +542,7 @@ wiki.create_first_page = Create the first page
|
||||||
wiki.new_page = Create New Page
|
wiki.new_page = Create New Page
|
||||||
wiki.default_commit_message = Write a note about this update (optional).
|
wiki.default_commit_message = Write a note about this update (optional).
|
||||||
wiki.save_page = Save Page
|
wiki.save_page = Save Page
|
||||||
|
wiki.last_commit_info = %s edited this page %s
|
||||||
|
|
||||||
settings = Settings
|
settings = Settings
|
||||||
settings.options = Options
|
settings.options = Options
|
||||||
|
|
1956
config.codekit
1956
config.codekit
File diff suppressed because it is too large
Load diff
|
@ -51,6 +51,10 @@ func IsReleaseExist(repoID int64, tagName string) (bool, error) {
|
||||||
return x.Get(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)})
|
return x.Get(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
git.GetVersion()
|
||||||
|
}
|
||||||
|
|
||||||
func createTag(gitRepo *git.Repository, rel *Release) error {
|
func createTag(gitRepo *git.Repository, rel *Release) error {
|
||||||
// Only actual create when publish.
|
// Only actual create when publish.
|
||||||
if !rel.IsDraft {
|
if !rel.IsDraft {
|
||||||
|
|
|
@ -31,7 +31,6 @@ import (
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
"github.com/gogits/gogs/modules/bindata"
|
"github.com/gogits/gogs/modules/bindata"
|
||||||
oldgit "github.com/gogits/gogs/modules/git"
|
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
"github.com/gogits/gogs/modules/process"
|
"github.com/gogits/gogs/modules/process"
|
||||||
"github.com/gogits/gogs/modules/setting"
|
"github.com/gogits/gogs/modules/setting"
|
||||||
|
@ -317,27 +316,24 @@ func (repo *Repository) LocalCopyPath() string {
|
||||||
return path.Join(setting.AppDataPath, "tmp/local", com.ToStr(repo.ID))
|
return path.Join(setting.AppDataPath, "tmp/local", com.ToStr(repo.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateLocalCopy makes sure the local copy of repository is up-to-date.
|
func updateLocalCopy(repoPath, localPath string) error {
|
||||||
func (repo *Repository) UpdateLocalCopy() error {
|
|
||||||
repoPath := repo.RepoPath()
|
|
||||||
localPath := repo.LocalCopyPath()
|
|
||||||
if !com.IsExist(localPath) {
|
if !com.IsExist(localPath) {
|
||||||
_, stderr, err := process.Exec(
|
if err := git.Clone(repoPath, localPath); err != nil {
|
||||||
fmt.Sprintf("UpdateLocalCopy(git clone): %s", repoPath), "git", "clone", repoPath, localPath)
|
return fmt.Errorf("Clone: %v", err)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("git clone: %v - %s", err, stderr)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, stderr, err := process.ExecDir(-1, localPath,
|
if err := git.Pull(localPath, true); err != nil {
|
||||||
fmt.Sprintf("UpdateLocalCopy(git pull --all): %s", repoPath), "git", "pull", "--all")
|
return fmt.Errorf("Pull: %v", err)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("git pull: %v - %s", err, stderr)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateLocalCopy makes sure the local copy of repository is up-to-date.
|
||||||
|
func (repo *Repository) UpdateLocalCopy() error {
|
||||||
|
return updateLocalCopy(repo.RepoPath(), repo.LocalCopyPath())
|
||||||
|
}
|
||||||
|
|
||||||
// PatchPath returns corresponding patch file path of repository by given issue ID.
|
// PatchPath returns corresponding patch file path of repository by given issue ID.
|
||||||
func (repo *Repository) PatchPath(index int64) (string, error) {
|
func (repo *Repository) PatchPath(index int64) (string, error) {
|
||||||
if err := repo.GetOwner(); err != nil {
|
if err := repo.GetOwner(); err != nil {
|
||||||
|
@ -471,6 +467,11 @@ func UpdateMirror(m *Mirror) error {
|
||||||
return updateMirror(x, m)
|
return updateMirror(x, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createUpdateHook(repoPath string) error {
|
||||||
|
return git.SetUpdateHook(repoPath,
|
||||||
|
fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf))
|
||||||
|
}
|
||||||
|
|
||||||
// MirrorRepository creates a mirror repository from source.
|
// MirrorRepository creates a mirror repository from source.
|
||||||
func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
|
func MirrorRepository(repoId int64, userName, repoName, repoPath, url string) error {
|
||||||
_, stderr, err := process.ExecTimeout(10*time.Minute,
|
_, stderr, err := process.ExecTimeout(10*time.Minute,
|
||||||
|
@ -568,20 +569,26 @@ func MigrateRepository(u *User, opts MigrateRepoOptions) (*Repository, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if repository has master branch, if so set it to default branch.
|
// Try to get HEAD branch and set it as default branch.
|
||||||
gitRepo, err := oldgit.OpenRepository(repoPath)
|
gitRepo, err := git.OpenRepository(repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return repo, fmt.Errorf("open git repository: %v", err)
|
log.Error(4, "OpenRepository: %v", err)
|
||||||
|
return repo, nil
|
||||||
}
|
}
|
||||||
if gitRepo.IsBranchExist("master") {
|
headBranch, err := gitRepo.GetHEADBranch()
|
||||||
repo.DefaultBranch = "master"
|
if err != nil {
|
||||||
|
log.Error(4, "GetHEADBranch: %v", err)
|
||||||
|
return repo, nil
|
||||||
|
}
|
||||||
|
if headBranch != nil {
|
||||||
|
repo.DefaultBranch = headBranch.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
return repo, UpdateRepository(repo, false)
|
return repo, UpdateRepository(repo, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initRepoCommit temporarily changes with work directory.
|
// initRepoCommit temporarily changes with work directory.
|
||||||
func initRepoCommit(tmpPath string, sig *oldgit.Signature) (err error) {
|
func initRepoCommit(tmpPath string, sig *git.Signature) (err error) {
|
||||||
var stderr string
|
var stderr string
|
||||||
if _, stderr, err = process.ExecDir(-1,
|
if _, stderr, err = process.ExecDir(-1,
|
||||||
tmpPath, fmt.Sprintf("initRepoCommit (git add): %s", tmpPath),
|
tmpPath, fmt.Sprintf("initRepoCommit (git add): %s", tmpPath),
|
||||||
|
@ -604,13 +611,6 @@ func initRepoCommit(tmpPath string, sig *oldgit.Signature) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createUpdateHook(repoPath string) error {
|
|
||||||
hookPath := path.Join(repoPath, "hooks/update")
|
|
||||||
os.MkdirAll(path.Dir(hookPath), os.ModePerm)
|
|
||||||
return ioutil.WriteFile(hookPath,
|
|
||||||
[]byte(fmt.Sprintf(_TPL_UPDATE_HOOK, setting.ScriptType, "\""+setting.AppPath+"\"", setting.CustomConf)), 0777)
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateRepoOptions struct {
|
type CreateRepoOptions struct {
|
||||||
Name string
|
Name string
|
||||||
Description string
|
Description string
|
||||||
|
@ -699,22 +699,17 @@ func prepareRepoCommit(repo *Repository, tmpDir, repoPath string, opts CreateRep
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitRepository initializes README and .gitignore if needed.
|
// InitRepository initializes README and .gitignore if needed.
|
||||||
func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts CreateRepoOptions) error {
|
func initRepository(e Engine, repoPath string, u *User, repo *Repository, opts CreateRepoOptions) (err error) {
|
||||||
// Somehow the directory could exist.
|
// Somehow the directory could exist.
|
||||||
if com.IsExist(repoPath) {
|
if com.IsExist(repoPath) {
|
||||||
return fmt.Errorf("initRepository: path already exists: %s", repoPath)
|
return fmt.Errorf("initRepository: path already exists: %s", repoPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init bare new repository.
|
// Init bare new repository.
|
||||||
os.MkdirAll(repoPath, os.ModePerm)
|
if err = git.InitRepository(repoPath, true); err != nil {
|
||||||
_, stderr, err := process.ExecDir(-1, repoPath,
|
return fmt.Errorf("InitRepository: %v", err)
|
||||||
fmt.Sprintf("initRepository (git init --bare): %s", repoPath), "git", "init", "--bare")
|
} else if err = createUpdateHook(repoPath); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("createUpdateHook: %v", err)
|
||||||
return fmt.Errorf("git init --bare: %v - %s", err, stderr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := createUpdateHook(repoPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpDir := filepath.Join(os.TempDir(), "gogs-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))
|
tmpDir := filepath.Join(os.TempDir(), "gogs-"+repo.Name+"-"+com.ToStr(time.Now().Nanosecond()))
|
||||||
|
|
|
@ -25,9 +25,11 @@ import (
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"github.com/nfnt/resize"
|
"github.com/nfnt/resize"
|
||||||
|
|
||||||
|
"github.com/gogits/git-shell"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/avatar"
|
"github.com/gogits/gogs/modules/avatar"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
"github.com/gogits/gogs/modules/git"
|
oldgit "github.com/gogits/gogs/modules/git"
|
||||||
"github.com/gogits/gogs/modules/log"
|
"github.com/gogits/gogs/modules/log"
|
||||||
"github.com/gogits/gogs/modules/setting"
|
"github.com/gogits/gogs/modules/setting"
|
||||||
)
|
)
|
||||||
|
@ -938,11 +940,11 @@ func MakeEmailPrimary(email *EmailAddress) error {
|
||||||
// UserCommit represents a commit with validation of user.
|
// UserCommit represents a commit with validation of user.
|
||||||
type UserCommit struct {
|
type UserCommit struct {
|
||||||
User *User
|
User *User
|
||||||
*git.Commit
|
*oldgit.Commit
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateCommitWithEmail chceck if author's e-mail of commit is corresponsind to a user.
|
// ValidateCommitWithEmail chceck if author's e-mail of commit is corresponsind to a user.
|
||||||
func ValidateCommitWithEmail(c *git.Commit) *User {
|
func ValidateCommitWithEmail(c *oldgit.Commit) *User {
|
||||||
u, err := GetUserByEmail(c.Author.Email)
|
u, err := GetUserByEmail(c.Author.Email)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -959,7 +961,7 @@ func ValidateCommitsWithEmails(oldCommits *list.List) *list.List {
|
||||||
e = oldCommits.Front()
|
e = oldCommits.Front()
|
||||||
)
|
)
|
||||||
for e != nil {
|
for e != nil {
|
||||||
c := e.Value.(*git.Commit)
|
c := e.Value.(*oldgit.Commit)
|
||||||
|
|
||||||
if v, ok := emails[c.Author.Email]; !ok {
|
if v, ok := emails[c.Author.Email]; !ok {
|
||||||
u, _ = GetUserByEmail(c.Author.Email)
|
u, _ = GetUserByEmail(c.Author.Email)
|
||||||
|
|
104
models/wiki.go
104
models/wiki.go
|
@ -6,19 +6,72 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
|
|
||||||
"github.com/gogits/git-shell"
|
"github.com/gogits/git-shell"
|
||||||
|
|
||||||
|
"github.com/gogits/gogs/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToWikiPageName formats a string to corresponding wiki URL name.
|
// workingPool represents a pool of working status which makes sure
|
||||||
func ToWikiPageName(name string) string {
|
// that only one instance of same task is performing at a time.
|
||||||
|
// However, different type of tasks can performing at the same time.
|
||||||
|
type workingPool struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
pool map[string]*sync.Mutex
|
||||||
|
count map[string]int
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckIn checks in a task and waits if others are running.
|
||||||
|
func (p *workingPool) CheckIn(name string) {
|
||||||
|
p.lock.Lock()
|
||||||
|
|
||||||
|
lock, has := p.pool[name]
|
||||||
|
if !has {
|
||||||
|
lock = &sync.Mutex{}
|
||||||
|
p.pool[name] = lock
|
||||||
|
}
|
||||||
|
p.count[name]++
|
||||||
|
|
||||||
|
p.lock.Unlock()
|
||||||
|
lock.Lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckOut checks out a task to let other tasks run.
|
||||||
|
func (p *workingPool) CheckOut(name string) {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
p.pool[name].Unlock()
|
||||||
|
if p.count[name] == 1 {
|
||||||
|
delete(p.pool, name)
|
||||||
|
delete(p.count, name)
|
||||||
|
} else {
|
||||||
|
p.count[name]--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var wikiWorkingPool = &workingPool{
|
||||||
|
pool: make(map[string]*sync.Mutex),
|
||||||
|
count: make(map[string]int),
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToWikiPageURL formats a string to corresponding wiki URL name.
|
||||||
|
func ToWikiPageURL(name string) string {
|
||||||
return strings.Replace(name, " ", "-", -1)
|
return strings.Replace(name, " ", "-", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToWikiPageName formats a URL back to corresponding wiki page name.
|
||||||
|
func ToWikiPageName(name string) string {
|
||||||
|
return strings.Replace(name, "-", " ", -1)
|
||||||
|
}
|
||||||
|
|
||||||
// WikiPath returns wiki data path by given user and repository name.
|
// WikiPath returns wiki data path by given user and repository name.
|
||||||
func WikiPath(userName, repoName string) string {
|
func WikiPath(userName, repoName string) string {
|
||||||
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
|
return filepath.Join(UserPath(userName), strings.ToLower(repoName)+".wiki.git")
|
||||||
|
@ -46,11 +99,56 @@ func (repo *Repository) InitWiki() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *Repository) LocalWikiPath() string {
|
||||||
|
return path.Join(setting.AppDataPath, "tmp/local-wiki", com.ToStr(repo.ID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateLocalWiki makes sure the local copy of repository wiki is up-to-date.
|
||||||
|
func (repo *Repository) UpdateLocalWiki() error {
|
||||||
|
return updateLocalCopy(repo.WikiPath(), repo.LocalWikiPath())
|
||||||
|
}
|
||||||
|
|
||||||
// AddWikiPage adds new page to repository wiki.
|
// AddWikiPage adds new page to repository wiki.
|
||||||
func (repo *Repository) AddWikiPage(title, content, message string) (err error) {
|
func (repo *Repository) AddWikiPage(doer *User, title, content, message string) (err error) {
|
||||||
|
wikiWorkingPool.CheckIn(com.ToStr(repo.ID))
|
||||||
|
defer wikiWorkingPool.CheckOut(com.ToStr(repo.ID))
|
||||||
|
|
||||||
if err = repo.InitWiki(); err != nil {
|
if err = repo.InitWiki(); err != nil {
|
||||||
return fmt.Errorf("InitWiki: %v", err)
|
return fmt.Errorf("InitWiki: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localPath := repo.LocalWikiPath()
|
||||||
|
|
||||||
|
// Discard local commits make sure even to remote when local copy exists.
|
||||||
|
if com.IsExist(localPath) {
|
||||||
|
// No need to check if nothing in the repository.
|
||||||
|
if git.IsBranchExist(localPath, "master") {
|
||||||
|
if err = git.Reset(localPath, true, "origin/master"); err != nil {
|
||||||
|
return fmt.Errorf("Reset: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = repo.UpdateLocalWiki(); err != nil {
|
||||||
|
return fmt.Errorf("UpdateLocalWiki: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
title = strings.Replace(title, "/", " ", -1)
|
||||||
|
filename := path.Join(localPath, title+".md")
|
||||||
|
if err = ioutil.WriteFile(filename, []byte(content), 0666); err != nil {
|
||||||
|
return fmt.Errorf("WriteFile: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(message) == 0 {
|
||||||
|
message = "Update page '" + title + "'"
|
||||||
|
}
|
||||||
|
if err = git.AddChanges(localPath, true); err != nil {
|
||||||
|
return fmt.Errorf("AddChanges: %v", err)
|
||||||
|
} else if err = git.CommitChanges(localPath, message, doer.NewGitSig()); err != nil {
|
||||||
|
return fmt.Errorf("CommitChanges: %v", err)
|
||||||
|
} else if err = git.Push(localPath, "origin", "master"); err != nil {
|
||||||
|
return fmt.Errorf("Push: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,7 +247,7 @@ func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
|
||||||
|
|
||||||
type NewWikiForm struct {
|
type NewWikiForm struct {
|
||||||
Title string `binding:"Required"`
|
Title string `binding:"Required"`
|
||||||
Content string
|
Content string `binding:"Required"`
|
||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"CodeKitInfo": "This is a CodeKit 2.x project configuration file. It is designed to sync project settings across multiple machines. MODIFYING THE CONTENTS OF THIS FILE IS A POOR LIFE DECISION. If you do so, you will likely cause CodeKit to crash. This file is not useful unless accompanied by the project that created it in CodeKit 2. This file is not backwards-compatible with CodeKit 1.x. For more information, see: http:\/\/incident57.com\/codekit",
|
"CodeKitInfo": "This is a CodeKit 2.x project configuration file. It is designed to sync project settings across multiple machines. MODIFYING THE CONTENTS OF THIS FILE IS A POOR LIFE DECISION. If you do so, you will likely cause CodeKit to crash. This file is not useful unless accompanied by the project that created it in CodeKit 2. This file is not backwards-compatible with CodeKit 1.x. For more information, see: http:\/\/incident57.com\/codekit",
|
||||||
"creatorBuild": "19102",
|
"creatorBuild": "19076",
|
||||||
"files": {
|
"files": {
|
||||||
"\/css\/dropzone-4.2.0.css": {
|
"\/css\/dropzone-4.2.0.css": {
|
||||||
"fileType": 16,
|
"fileType": 16,
|
||||||
|
@ -616,18 +616,10 @@
|
||||||
"active": 0,
|
"active": 0,
|
||||||
"flagValue": -1
|
"flagValue": -1
|
||||||
},
|
},
|
||||||
"no_nested_string_interpolation": {
|
|
||||||
"active": 1,
|
|
||||||
"flagValue": -1
|
|
||||||
},
|
|
||||||
"no_plusplus": {
|
"no_plusplus": {
|
||||||
"active": 0,
|
"active": 0,
|
||||||
"flagValue": -1
|
"flagValue": -1
|
||||||
},
|
},
|
||||||
"no_private_function_fat_arrows": {
|
|
||||||
"active": 1,
|
|
||||||
"flagValue": -1
|
|
||||||
},
|
|
||||||
"no_stand_alone_at": {
|
"no_stand_alone_at": {
|
||||||
"active": 1,
|
"active": 1,
|
||||||
"flagValue": -1
|
"flagValue": -1
|
||||||
|
@ -636,10 +628,6 @@
|
||||||
"active": 1,
|
"active": 1,
|
||||||
"flagValue": -1
|
"flagValue": -1
|
||||||
},
|
},
|
||||||
"no_this": {
|
|
||||||
"active": 0,
|
|
||||||
"flagValue": -1
|
|
||||||
},
|
|
||||||
"no_throwing_strings": {
|
"no_throwing_strings": {
|
||||||
"active": 1,
|
"active": 1,
|
||||||
"flagValue": -1
|
"flagValue": -1
|
||||||
|
|
|
@ -2531,6 +2531,20 @@ footer .container .links > *:first-child {
|
||||||
.repository.wiki.new .editor-preview {
|
.repository.wiki.new .editor-preview {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
.repository.wiki.view .ui.sub.header {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
.repository.wiki.view .markdown {
|
||||||
|
padding: 15px 30px;
|
||||||
|
}
|
||||||
|
.repository.wiki.view .markdown h1:first-of-type,
|
||||||
|
.repository.wiki.view .markdown h2:first-of-type,
|
||||||
|
.repository.wiki.view .markdown h3:first-of-type,
|
||||||
|
.repository.wiki.view .markdown h4:first-of-type,
|
||||||
|
.repository.wiki.view .markdown h5:first-of-type,
|
||||||
|
.repository.wiki.view .markdown h6:first-of-type {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
.repository.settings.collaboration .collaborator.list {
|
.repository.settings.collaboration .collaborator.list {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -970,6 +970,24 @@
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.view {
|
||||||
|
.header:not(.sub) {
|
||||||
|
// padding-left: 30px;
|
||||||
|
}
|
||||||
|
.ui.sub.header {
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
.markdown {
|
||||||
|
padding: 15px 30px;
|
||||||
|
|
||||||
|
h1, h2, h3, h4, h5, h6 {
|
||||||
|
&:first-of-type {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.settings {
|
&.settings {
|
||||||
|
|
|
@ -5,6 +5,10 @@
|
||||||
package repo
|
package repo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/gogits/git-shell"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/auth"
|
"github.com/gogits/gogs/modules/auth"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
@ -18,17 +22,68 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Wiki(ctx *middleware.Context) {
|
func Wiki(ctx *middleware.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.wiki")
|
|
||||||
ctx.Data["PageIsWiki"] = true
|
ctx.Data["PageIsWiki"] = true
|
||||||
|
|
||||||
if !ctx.Repo.Repository.HasWiki() {
|
if !ctx.Repo.Repository.HasWiki() {
|
||||||
|
ctx.Data["Title"] = ctx.Tr("repo.wiki")
|
||||||
ctx.HTML(200, WIKI_START)
|
ctx.HTML(200, WIKI_START)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wikiRepo, err := git.OpenRepository(ctx.Repo.Repository.WikiPath())
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "OpenRepository", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
commit, err := wikiRepo.GetCommitOfBranch("master")
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetCommitOfBranch", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
page := models.ToWikiPageName(ctx.Params(":page"))
|
||||||
|
if len(page) == 0 {
|
||||||
|
page = "Home"
|
||||||
|
}
|
||||||
|
ctx.Data["Title"] = page
|
||||||
|
ctx.Data["RequireHighlightJS"] = true
|
||||||
|
|
||||||
|
blob, err := commit.GetBlobByPath(page + ".md")
|
||||||
|
if err != nil {
|
||||||
|
if git.IsErrNotExist(err) {
|
||||||
|
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/_list")
|
||||||
|
} else {
|
||||||
|
ctx.Handle(500, "GetBlobByPath", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r, err := blob.Data()
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "Data", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data, err := ioutil.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "ReadAll", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Data["Content"] = string(base.RenderMarkdown(data, ctx.Repo.RepoLink))
|
||||||
|
|
||||||
|
// Get last change information.
|
||||||
|
lastCommit, err := wikiRepo.GetCommitByPath(page + ".md")
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetCommitByPath", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Data["Author"] = lastCommit.Author
|
||||||
|
|
||||||
ctx.HTML(200, WIKI_VIEW)
|
ctx.HTML(200, WIKI_VIEW)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WikiList(ctx *middleware.Context) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func NewWiki(ctx *middleware.Context) {
|
func NewWiki(ctx *middleware.Context) {
|
||||||
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
|
ctx.Data["Title"] = ctx.Tr("repo.wiki.new_page")
|
||||||
ctx.Data["PageIsWiki"] = true
|
ctx.Data["PageIsWiki"] = true
|
||||||
|
@ -51,12 +106,12 @@ func NewWikiPost(ctx *middleware.Context, form auth.NewWikiForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ctx.Repo.Repository.AddWikiPage(form.Title, form.Content, form.Message); err != nil {
|
if err := ctx.Repo.Repository.AddWikiPage(ctx.User, form.Title, form.Content, form.Message); err != nil {
|
||||||
ctx.Handle(500, "AddWikiPage", err)
|
ctx.Handle(500, "AddWikiPage", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageName(form.Title))
|
ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + models.ToWikiPageURL(form.Title))
|
||||||
}
|
}
|
||||||
|
|
||||||
func EditWiki(ctx *middleware.Context) {
|
func EditWiki(ctx *middleware.Context) {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<input name="title" value="{{.title}}" autofocus required>
|
<input name="title" value="{{.title}}" autofocus required>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<textarea id="edit-area" name="content" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.wiki.welcome"}}</textarea>
|
<textarea id="edit-area" name="content" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}">{{.i18n.Tr "repo.wiki.welcome"}}</textarea required>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<input name="message" placeholder="{{.i18n.Tr "repo.wiki.default_commit_message"}}">
|
<input name="message" placeholder="{{.i18n.Tr "repo.wiki.default_commit_message"}}">
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
{{template "base/head" .}}
|
||||||
|
<div class="repository wiki view">
|
||||||
|
{{template "repo/header" .}}
|
||||||
|
<div class="ui container">
|
||||||
|
{{template "repo/sidebar" .}}
|
||||||
|
<div class="ui dividing header">
|
||||||
|
{{.Title}}
|
||||||
|
<div class="ui sub header">
|
||||||
|
{{$timeSince := TimeSince .Author.When $.Lang}}
|
||||||
|
{{.i18n.Tr "repo.wiki.last_commit_info" .Author.Name $timeSince | Safe}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui segment markdown">
|
||||||
|
{{.Content | Str2html}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{template "base/footer" .}}
|
Reference in a new issue