mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-26 12:27:06 +00:00 
			
		
		
		
	Improve delete SSH key
This commit is contained in:
		| @@ -30,4 +30,4 @@ Any significant improvement should be documented as [a GitHub issue](https://git | |||||||
|  |  | ||||||
| ### ...but check for existing issues first! | ### ...but check for existing issues first! | ||||||
|  |  | ||||||
| Please take a moment to check that an issue doesn't already exist documenting your bug report or improvement proposal. If it does, it never hurts to add a quick "+1" or "I have this problem too". This will help prioritize the most common problems and requests. | Please take a moment to check that an issue or card on [Trello](https://trello.com/b/uxAoeLUl/gogs-go-git-service) doesn't already exist documenting your bug report or improvement proposal. If it does, it never hurts to add a quick "+1" or "I have this problem too". This will help prioritize the most common problems and requests. | ||||||
							
								
								
									
										3
									
								
								bee.json
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								bee.json
									
									
									
									
									
								
							| @@ -13,8 +13,7 @@ | |||||||
| 		"others": [ | 		"others": [ | ||||||
| 			"modules", | 			"modules", | ||||||
| 			"$GOPATH/src/github.com/gogits/logs", | 			"$GOPATH/src/github.com/gogits/logs", | ||||||
| 			"$GOPATH/src/github.com/gogits/git", | 			"$GOPATH/src/github.com/gogits/git" | ||||||
| 			"$GOPATH/src/github.com/gogits/gfm" |  | ||||||
| 		] | 		] | ||||||
| 	}, | 	}, | ||||||
| 	"cmd_args": [ | 	"cmd_args": [ | ||||||
|   | |||||||
| @@ -180,7 +180,7 @@ func runWeb(*cli.Context) { | |||||||
| 	}, reqSignIn, middleware.RepoAssignment(true), reqOwner) | 	}, reqSignIn, middleware.RepoAssignment(true), reqOwner) | ||||||
|  |  | ||||||
| 	m.Group("/:username/:reponame", func(r martini.Router) { | 	m.Group("/:username/:reponame", func(r martini.Router) { | ||||||
| 		r.Get("/action/:action", repo.Action) // TODO | 		r.Get("/action/:action", repo.Action) | ||||||
| 		r.Get("/issues/new", repo.CreateIssue) | 		r.Get("/issues/new", repo.CreateIssue) | ||||||
| 		r.Post("/issues/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost) | 		r.Post("/issues/new", bindIgnErr(auth.CreateIssueForm{}), repo.CreateIssuePost) | ||||||
| 		r.Post("/issues/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue) | 		r.Post("/issues/:index", bindIgnErr(auth.CreateIssueForm{}), repo.UpdateIssue) | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								gogs.go
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								gogs.go
									
									
									
									
									
								
							| @@ -17,9 +17,6 @@ import ( | |||||||
| 	"github.com/gogits/gogs/modules/base" | 	"github.com/gogits/gogs/modules/base" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Test that go1.2 tag above is included in builds. main.go refers to this definition. |  | ||||||
| const go12tag = true |  | ||||||
|  |  | ||||||
| const APP_VER = "0.3.3.0506 Alpha" | const APP_VER = "0.3.3.0506 Alpha" | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
|   | |||||||
| @@ -30,19 +30,17 @@ type Issue struct { | |||||||
| 	IsPull          bool // Indicates whether is a pull request or not. | 	IsPull          bool // Indicates whether is a pull request or not. | ||||||
| 	IsClosed        bool | 	IsClosed        bool | ||||||
| 	Labels          string `xorm:"TEXT"` | 	Labels          string `xorm:"TEXT"` | ||||||
| 	Mentions        string `xorm:"TEXT"` |  | ||||||
| 	Content         string `xorm:"TEXT"` | 	Content         string `xorm:"TEXT"` | ||||||
| 	RenderedContent string `xorm:"-"` | 	RenderedContent string `xorm:"-"` | ||||||
|  | 	Priority        int | ||||||
| 	NumComments     int | 	NumComments     int | ||||||
|  | 	Deadline        time.Time | ||||||
| 	Created         time.Time `xorm:"created"` | 	Created         time.Time `xorm:"created"` | ||||||
| 	Updated         time.Time `xorm:"updated"` | 	Updated         time.Time `xorm:"updated"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // CreateIssue creates new issue for repository. | // CreateIssue creates new issue for repository. | ||||||
| func CreateIssue(userId, repoId, milestoneId, assigneeId int64, issueCount int, name, labels, content string, isPull bool) (issue *Issue, err error) { | func CreateIssue(userId, repoId, milestoneId, assigneeId int64, issueCount int, name, labels, content string, isPull bool) (issue *Issue, err error) { | ||||||
| 	// TODO: find out mentions |  | ||||||
| 	mentions := "" |  | ||||||
|  |  | ||||||
| 	sess := orm.NewSession() | 	sess := orm.NewSession() | ||||||
| 	defer sess.Close() | 	defer sess.Close() | ||||||
| 	sess.Begin() | 	sess.Begin() | ||||||
| @@ -56,7 +54,6 @@ func CreateIssue(userId, repoId, milestoneId, assigneeId int64, issueCount int, | |||||||
| 		AssigneeId:  assigneeId, | 		AssigneeId:  assigneeId, | ||||||
| 		IsPull:      isPull, | 		IsPull:      isPull, | ||||||
| 		Labels:      labels, | 		Labels:      labels, | ||||||
| 		Mentions:    mentions, |  | ||||||
| 		Content:     content, | 		Content:     content, | ||||||
| 	} | 	} | ||||||
| 	if _, err = sess.Insert(issue); err != nil { | 	if _, err = sess.Insert(issue); err != nil { | ||||||
|   | |||||||
| @@ -139,10 +139,9 @@ func NewEngine() (err error) { | |||||||
|  |  | ||||||
| type Statistic struct { | type Statistic struct { | ||||||
| 	Counter struct { | 	Counter struct { | ||||||
| 		User, PublicKey, Repo, | 		User, PublicKey, Repo, Watch, Action, Access, | ||||||
| 		Watch, Action, Access, | 		Issue, Comment, Mirror, Oauth, Release, | ||||||
| 		Issue, Comment, | 		LoginSource, Webhook int64 | ||||||
| 		Mirror, Oauth, Release int64 |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -158,6 +157,8 @@ func GetStatistic() (stats Statistic) { | |||||||
| 	stats.Counter.Mirror, _ = orm.Count(new(Mirror)) | 	stats.Counter.Mirror, _ = orm.Count(new(Mirror)) | ||||||
| 	stats.Counter.Oauth, _ = orm.Count(new(Oauth2)) | 	stats.Counter.Oauth, _ = orm.Count(new(Oauth2)) | ||||||
| 	stats.Counter.Release, _ = orm.Count(new(Release)) | 	stats.Counter.Release, _ = orm.Count(new(Release)) | ||||||
|  | 	stats.Counter.LoginSource, _ = orm.Count(new(LoginSource)) | ||||||
|  | 	stats.Counter.Webhook, _ = orm.Count(new(Webhook)) | ||||||
| 	return | 	return | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,12 +6,11 @@ package models | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bufio" | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" |  | ||||||
| 	"io/ioutil" | 	"io/ioutil" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/exec" |  | ||||||
| 	"path" | 	"path" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
| @@ -19,7 +18,9 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/Unknwon/com" | 	"github.com/Unknwon/com" | ||||||
|  | 	qlog "github.com/qiniu/log" | ||||||
|  |  | ||||||
|  | 	"github.com/gogits/gogs/modules/base" | ||||||
| 	"github.com/gogits/gogs/modules/log" | 	"github.com/gogits/gogs/modules/log" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -30,29 +31,21 @@ const ( | |||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	ErrKeyAlreadyExist = errors.New("Public key already exist") | 	ErrKeyAlreadyExist = errors.New("Public key already exist") | ||||||
|  | 	ErrKeyNotExist     = errors.New("Public key does not exist") | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var sshOpLocker = sync.Mutex{} | var sshOpLocker = sync.Mutex{} | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	sshPath string | 	sshPath string // SSH directory. | ||||||
| 	appPath string | 	appPath string // Execution(binary) path. | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // exePath returns the executable path. |  | ||||||
| func exePath() (string, error) { |  | ||||||
| 	file, err := exec.LookPath(os.Args[0]) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return "", err |  | ||||||
| 	} |  | ||||||
| 	return filepath.Abs(file) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // homeDir returns the home directory of current user. | // homeDir returns the home directory of current user. | ||||||
| func homeDir() string { | func homeDir() string { | ||||||
| 	home, err := com.HomeDir() | 	home, err := com.HomeDir() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "/" | 		qlog.Fatalln(err) | ||||||
| 	} | 	} | ||||||
| 	return home | 	return home | ||||||
| } | } | ||||||
| @@ -60,17 +53,14 @@ func homeDir() string { | |||||||
| func init() { | func init() { | ||||||
| 	var err error | 	var err error | ||||||
|  |  | ||||||
| 	appPath, err = exePath() | 	if appPath, err = base.ExecDir(); err != nil { | ||||||
| 	if err != nil { | 		qlog.Fatalf("publickey.init(fail to get app path): %v\n", err) | ||||||
| 		fmt.Printf("publickey.init(fail to get app path): %v\n", err) |  | ||||||
| 		os.Exit(2) |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Determine and create .ssh path. | 	// Determine and create .ssh path. | ||||||
| 	sshPath = filepath.Join(homeDir(), ".ssh") | 	sshPath = filepath.Join(homeDir(), ".ssh") | ||||||
| 	if err = os.MkdirAll(sshPath, os.ModePerm); err != nil { | 	if err = os.MkdirAll(sshPath, os.ModePerm); err != nil { | ||||||
| 		fmt.Printf("publickey.init(fail to create sshPath(%s)): %v\n", sshPath, err) | 		qlog.Fatalf("publickey.init(fail to create sshPath(%s)): %v\n", sshPath, err) | ||||||
| 		os.Exit(2) |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -129,8 +119,8 @@ func AddPublicKey(key *PublicKey) (err error) { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // rewriteAuthorizedKeys finds and deletes corresponding line in authorized_keys file. | ||||||
| func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error { | func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error { | ||||||
| 	// Delete SSH key in SSH key file. |  | ||||||
| 	sshOpLocker.Lock() | 	sshOpLocker.Lock() | ||||||
| 	defer sshOpLocker.Unlock() | 	defer sshOpLocker.Unlock() | ||||||
|  |  | ||||||
| @@ -146,55 +136,48 @@ func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error { | |||||||
| 	} | 	} | ||||||
| 	defer fw.Close() | 	defer fw.Close() | ||||||
|  |  | ||||||
| 	buf := bufio.NewReader(fr) | 	isFound := false | ||||||
| 	for { | 	keyword := []byte(fmt.Sprintf("key-%d", key.Id)) | ||||||
| 		line, errRead := buf.ReadString('\n') | 	content := []byte(key.Content) | ||||||
| 		line = strings.TrimSpace(line) |  | ||||||
|  |  | ||||||
| 		if errRead != nil { | 	snr := bufio.NewScanner(fr) | ||||||
| 			if errRead != io.EOF { | 	for snr.Scan() { | ||||||
| 				return errRead | 		line := append(bytes.TrimSpace(snr.Bytes()), '\n') | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			// Reached end of file, if nothing to read then break, |  | ||||||
| 			// otherwise handle the last line. |  | ||||||
| 		if len(line) == 0 { | 		if len(line) == 0 { | ||||||
| 				break | 			continue | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Found the line and copy rest of file. | 		// Found the line and copy rest of file. | ||||||
| 		if strings.Contains(line, fmt.Sprintf("key-%d", key.Id)) && strings.Contains(line, key.Content) { | 		if !isFound && bytes.Contains(line, keyword) && bytes.Contains(line, content) { | ||||||
|  | 			isFound = true | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// Still finding the line, copy the line that currently read. | 		// Still finding the line, copy the line that currently read. | ||||||
| 		if _, err = fw.WriteString(line + "\n"); err != nil { | 		if _, err = fw.Write(line); err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 		if errRead == io.EOF { |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // DeletePublicKey deletes SSH key information both in database and authorized_keys file. | // DeletePublicKey deletes SSH key information both in database and authorized_keys file. | ||||||
| func DeletePublicKey(key *PublicKey) (err error) { | func DeletePublicKey(key *PublicKey) error { | ||||||
| 	// Delete SSH key in database. | 	has, err := orm.Get(key) | ||||||
| 	has, err := orm.Id(key.Id).Get(key) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} else if !has { | 	} else if !has { | ||||||
| 		return errors.New("Public key does not exist") | 		return ErrKeyNotExist | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if _, err = orm.Delete(key); err != nil { | 	if _, err = orm.Delete(key); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	p := filepath.Join(sshPath, "authorized_keys") | 	p := filepath.Join(sshPath, "authorized_keys") | ||||||
| 	tmpP := filepath.Join(sshPath, "authorized_keys.tmp") | 	tmpP := filepath.Join(sshPath, "authorized_keys.tmp") | ||||||
| 	log.Trace("ssh.DeletePublicKey(authorized_keys): %s", p) | 	log.Trace("publickey.DeletePublicKey(authorized_keys): %s", p) | ||||||
|  |  | ||||||
| 	if err = rewriteAuthorizedKeys(key, p, tmpP); err != nil { | 	if err = rewriteAuthorizedKeys(key, p, tmpP); err != nil { | ||||||
| 		return err | 		return err | ||||||
|   | |||||||
| @@ -32,7 +32,6 @@ var ( | |||||||
| 	ErrUserNotExist     = errors.New("User does not exist") | 	ErrUserNotExist     = errors.New("User does not exist") | ||||||
| 	ErrEmailAlreadyUsed = errors.New("E-mail already used") | 	ErrEmailAlreadyUsed = errors.New("E-mail already used") | ||||||
| 	ErrUserNameIllegal  = errors.New("User name contains illegal characters") | 	ErrUserNameIllegal  = errors.New("User name contains illegal characters") | ||||||
| 	ErrKeyNotExist      = errors.New("Public key does not exist") |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // User represents the object of individual and member of organization. | // User represents the object of individual and member of organization. | ||||||
| @@ -315,12 +314,12 @@ func DeleteUser(user *User) error { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Delete all SSH keys. | 	// Delete all SSH keys. | ||||||
| 	keys := make([]PublicKey, 0, 10) | 	keys := make([]*PublicKey, 0, 10) | ||||||
| 	if err = orm.Find(&keys, &PublicKey{OwnerId: user.Id}); err != nil { | 	if err = orm.Find(&keys, &PublicKey{OwnerId: user.Id}); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	for _, key := range keys { | 	for _, key := range keys { | ||||||
| 		if err = DeletePublicKey(&key); err != nil { | 		if err = DeletePublicKey(key); err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ import ( | |||||||
| 	"github.com/go-martini/martini" | 	"github.com/go-martini/martini" | ||||||
|  |  | ||||||
| 	"github.com/gogits/gogs/modules/base" | 	"github.com/gogits/gogs/modules/base" | ||||||
| 	"github.com/gogits/gogs/modules/log" |  | ||||||
| 	"github.com/gogits/gogs/modules/middleware/binding" | 	"github.com/gogits/gogs/modules/middleware/binding" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -31,20 +30,6 @@ func (f *CreateIssueForm) Name(field string) string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (f *CreateIssueForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { | func (f *CreateIssueForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { | ||||||
| 	if req.Method == "GET" || errors.Count() == 0 { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | 	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | ||||||
| 	data["HasError"] = true |  | ||||||
| 	AssignForm(f, data) |  | ||||||
|  |  | ||||||
| 	if len(errors.Overall) > 0 { |  | ||||||
| 		for _, err := range errors.Overall { |  | ||||||
| 			log.Error("CreateIssueForm.Validate: %v", err) |  | ||||||
| 		} |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	validate(errors, data, f) | 	validate(errors, data, f) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -11,7 +11,6 @@ import ( | |||||||
| 	"github.com/go-martini/martini" | 	"github.com/go-martini/martini" | ||||||
|  |  | ||||||
| 	"github.com/gogits/gogs/modules/base" | 	"github.com/gogits/gogs/modules/base" | ||||||
| 	"github.com/gogits/gogs/modules/log" |  | ||||||
| 	"github.com/gogits/gogs/modules/middleware/binding" | 	"github.com/gogits/gogs/modules/middleware/binding" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -32,20 +31,6 @@ func (f *NewReleaseForm) Name(field string) string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (f *NewReleaseForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { | func (f *NewReleaseForm) Validate(errors *binding.BindingErrors, req *http.Request, context martini.Context) { | ||||||
| 	if req.Method == "GET" || errors.Count() == 0 { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | 	data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) | ||||||
| 	data["HasError"] = true |  | ||||||
| 	AssignForm(f, data) |  | ||||||
|  |  | ||||||
| 	if len(errors.Overall) > 0 { |  | ||||||
| 		for _, err := range errors.Overall { |  | ||||||
| 			log.Error("NewReleaseForm.Validate: %v", err) |  | ||||||
| 		} |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	validate(errors, data, f) | 	validate(errors, data, f) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -98,6 +98,7 @@ var Service struct { | |||||||
| 	LdapAuth             bool | 	LdapAuth             bool | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // ExecDir returns absolute path execution(binary) path. | ||||||
| func ExecDir() (string, error) { | func ExecDir() (string, error) { | ||||||
| 	file, err := exec.LookPath(os.Args[0]) | 	file, err := exec.LookPath(os.Args[0]) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ package middleware | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"net/url" | 	"net/url" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/go-martini/martini" | 	"github.com/go-martini/martini" | ||||||
|  |  | ||||||
| @@ -40,6 +41,10 @@ func Toggle(options *ToggleOptions) martini.Handler { | |||||||
|  |  | ||||||
| 		if options.SignInRequire { | 		if options.SignInRequire { | ||||||
| 			if !ctx.IsSigned { | 			if !ctx.IsSigned { | ||||||
|  | 				// Ignore watch repository operation. | ||||||
|  | 				if strings.HasSuffix(ctx.Req.RequestURI, "watch") { | ||||||
|  | 					return | ||||||
|  | 				} | ||||||
| 				ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI)) | 				ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI)) | ||||||
| 				ctx.Redirect("/user/login") | 				ctx.Redirect("/user/login") | ||||||
| 				return | 				return | ||||||
|   | |||||||
| @@ -154,12 +154,8 @@ func SettingSSHKeys(ctx *middleware.Context, form auth.AddSSHKeyForm) { | |||||||
| 			}) | 			}) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 		k := &models.PublicKey{ |  | ||||||
| 			Id:      id, |  | ||||||
| 			OwnerId: ctx.User.Id, |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if err = models.DeletePublicKey(k); err != nil { | 		if err = models.DeletePublicKey(&models.PublicKey{Id: id}); err != nil { | ||||||
| 			log.Error("ssh.DelPublicKey: %v", err) | 			log.Error("ssh.DelPublicKey: %v", err) | ||||||
| 			ctx.JSON(200, map[string]interface{}{ | 			ctx.JSON(200, map[string]interface{}{ | ||||||
| 				"ok":  false, | 				"ok":  false, | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
|             </div> |             </div> | ||||||
|  |  | ||||||
|             <div class="panel-body"> |             <div class="panel-body"> | ||||||
|                 Gogs database has <b>{{.Stats.Counter.User}}</b> users, <b>{{.Stats.Counter.PublicKey}}</b> SSH keys, <b>{{.Stats.Counter.Repo}}</b> repositories, <b>{{.Stats.Counter.Watch}}</b> watches, <b>{{.Stats.Counter.Action}}</b> actions, <b>{{.Stats.Counter.Access}}</b> accesses, <b>{{.Stats.Counter.Issue}}</b> issues, <b>{{.Stats.Counter.Comment}}</b> comments, <b>{{.Stats.Counter.Mirror}}</b> mirrors, <b>{{.Stats.Counter.Oauth}}</b> oauthes, <b>{{.Stats.Counter.Release}}</b> releases. |                 Gogs database has <b>{{.Stats.Counter.User}}</b> users, <b>{{.Stats.Counter.PublicKey}}</b> SSH keys, <b>{{.Stats.Counter.Repo}}</b> repositories, <b>{{.Stats.Counter.Watch}}</b> watches, <b>{{.Stats.Counter.Action}}</b> actions, <b>{{.Stats.Counter.Access}}</b> accesses, <b>{{.Stats.Counter.Issue}}</b> issues, <b>{{.Stats.Counter.Comment}}</b> comments, <b>{{.Stats.Counter.Mirror}}</b> mirrors, <b>{{.Stats.Counter.Oauth}}</b> oauthes, <b>{{.Stats.Counter.Release}}</b> releases, <b>{{.Stats.Counter.LoginSource}}</b> login sources, <b>{{.Stats.Counter.Webhook}}</b> webhooks. | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Unknown
					Unknown