aboutsummaryrefslogtreecommitdiff
path: root/routes/admin
diff options
context:
space:
mode:
authorUnknwon <u@gogs.io>2017-06-11 00:34:14 -0400
committerUnknwon <u@gogs.io>2017-06-11 00:34:14 -0400
commit4400d2fdd933204044aeb18ce7d8613c53aa87c0 (patch)
tree841e91d5294c49b7335170fbc4b9ff79e882f91a /routes/admin
parent6197a7639a88f7fb0fee8927e1d501504ae770ff (diff)
Refactoring: rename package routers -> routes
Diffstat (limited to 'routes/admin')
-rw-r--r--routes/admin/admin.go258
-rw-r--r--routes/admin/auths.go265
-rw-r--r--routes/admin/notice.go72
-rw-r--r--routes/admin/orgs.go31
-rw-r--r--routes/admin/repos.go87
-rw-r--r--routes/admin/users.go262
6 files changed, 975 insertions, 0 deletions
diff --git a/routes/admin/admin.go b/routes/admin/admin.go
new file mode 100644
index 00000000..0d5eb7a6
--- /dev/null
+++ b/routes/admin/admin.go
@@ -0,0 +1,258 @@
+// Copyright 2014 The Gogs 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 admin
+
+import (
+ "encoding/json"
+ "fmt"
+ "runtime"
+ "strings"
+ "time"
+
+ "github.com/Unknwon/com"
+ "gopkg.in/macaron.v1"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/pkg/context"
+ "github.com/gogits/gogs/pkg/cron"
+ "github.com/gogits/gogs/pkg/mailer"
+ "github.com/gogits/gogs/pkg/process"
+ "github.com/gogits/gogs/pkg/setting"
+ "github.com/gogits/gogs/pkg/tool"
+)
+
+const (
+ DASHBOARD = "admin/dashboard"
+ CONFIG = "admin/config"
+ MONITOR = "admin/monitor"
+)
+
+var (
+ startTime = time.Now()
+)
+
+var sysStatus struct {
+ Uptime string
+ NumGoroutine int
+
+ // General statistics.
+ MemAllocated string // bytes allocated and still in use
+ MemTotal string // bytes allocated (even if freed)
+ MemSys string // bytes obtained from system (sum of XxxSys below)
+ Lookups uint64 // number of pointer lookups
+ MemMallocs uint64 // number of mallocs
+ MemFrees uint64 // number of frees
+
+ // Main allocation heap statistics.
+ HeapAlloc string // bytes allocated and still in use
+ HeapSys string // bytes obtained from system
+ HeapIdle string // bytes in idle spans
+ HeapInuse string // bytes in non-idle span
+ HeapReleased string // bytes released to the OS
+ HeapObjects uint64 // total number of allocated objects
+
+ // Low-level fixed-size structure allocator statistics.
+ // Inuse is bytes used now.
+ // Sys is bytes obtained from system.
+ StackInuse string // bootstrap stacks
+ StackSys string
+ MSpanInuse string // mspan structures
+ MSpanSys string
+ MCacheInuse string // mcache structures
+ MCacheSys string
+ BuckHashSys string // profiling bucket hash table
+ GCSys string // GC metadata
+ OtherSys string // other system allocations
+
+ // Garbage collector statistics.
+ NextGC string // next run in HeapAlloc time (bytes)
+ LastGC string // last run in absolute time (ns)
+ PauseTotalNs string
+ PauseNs string // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256]
+ NumGC uint32
+}
+
+func updateSystemStatus() {
+ sysStatus.Uptime = tool.TimeSincePro(startTime)
+
+ m := new(runtime.MemStats)
+ runtime.ReadMemStats(m)
+ sysStatus.NumGoroutine = runtime.NumGoroutine()
+
+ sysStatus.MemAllocated = tool.FileSize(int64(m.Alloc))
+ sysStatus.MemTotal = tool.FileSize(int64(m.TotalAlloc))
+ sysStatus.MemSys = tool.FileSize(int64(m.Sys))
+ sysStatus.Lookups = m.Lookups
+ sysStatus.MemMallocs = m.Mallocs
+ sysStatus.MemFrees = m.Frees
+
+ sysStatus.HeapAlloc = tool.FileSize(int64(m.HeapAlloc))
+ sysStatus.HeapSys = tool.FileSize(int64(m.HeapSys))
+ sysStatus.HeapIdle = tool.FileSize(int64(m.HeapIdle))
+ sysStatus.HeapInuse = tool.FileSize(int64(m.HeapInuse))
+ sysStatus.HeapReleased = tool.FileSize(int64(m.HeapReleased))
+ sysStatus.HeapObjects = m.HeapObjects
+
+ sysStatus.StackInuse = tool.FileSize(int64(m.StackInuse))
+ sysStatus.StackSys = tool.FileSize(int64(m.StackSys))
+ sysStatus.MSpanInuse = tool.FileSize(int64(m.MSpanInuse))
+ sysStatus.MSpanSys = tool.FileSize(int64(m.MSpanSys))
+ sysStatus.MCacheInuse = tool.FileSize(int64(m.MCacheInuse))
+ sysStatus.MCacheSys = tool.FileSize(int64(m.MCacheSys))
+ sysStatus.BuckHashSys = tool.FileSize(int64(m.BuckHashSys))
+ sysStatus.GCSys = tool.FileSize(int64(m.GCSys))
+ sysStatus.OtherSys = tool.FileSize(int64(m.OtherSys))
+
+ sysStatus.NextGC = tool.FileSize(int64(m.NextGC))
+ sysStatus.LastGC = fmt.Sprintf("%.1fs", float64(time.Now().UnixNano()-int64(m.LastGC))/1000/1000/1000)
+ sysStatus.PauseTotalNs = fmt.Sprintf("%.1fs", float64(m.PauseTotalNs)/1000/1000/1000)
+ sysStatus.PauseNs = fmt.Sprintf("%.3fs", float64(m.PauseNs[(m.NumGC+255)%256])/1000/1000/1000)
+ sysStatus.NumGC = m.NumGC
+}
+
+// Operation types.
+type AdminOperation int
+
+const (
+ CLEAN_INACTIVATE_USER AdminOperation = iota + 1
+ CLEAN_REPO_ARCHIVES
+ CLEAN_MISSING_REPOS
+ GIT_GC_REPOS
+ SYNC_SSH_AUTHORIZED_KEY
+ SYNC_REPOSITORY_HOOKS
+ REINIT_MISSING_REPOSITORY
+)
+
+func Dashboard(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.dashboard")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminDashboard"] = true
+
+ // Run operation.
+ op, _ := com.StrTo(c.Query("op")).Int()
+ if op > 0 {
+ var err error
+ var success string
+
+ switch AdminOperation(op) {
+ case CLEAN_INACTIVATE_USER:
+ success = c.Tr("admin.dashboard.delete_inactivate_accounts_success")
+ err = models.DeleteInactivateUsers()
+ case CLEAN_REPO_ARCHIVES:
+ success = c.Tr("admin.dashboard.delete_repo_archives_success")
+ err = models.DeleteRepositoryArchives()
+ case CLEAN_MISSING_REPOS:
+ success = c.Tr("admin.dashboard.delete_missing_repos_success")
+ err = models.DeleteMissingRepositories()
+ case GIT_GC_REPOS:
+ success = c.Tr("admin.dashboard.git_gc_repos_success")
+ err = models.GitGcRepos()
+ case SYNC_SSH_AUTHORIZED_KEY:
+ success = c.Tr("admin.dashboard.resync_all_sshkeys_success")
+ err = models.RewriteAllPublicKeys()
+ case SYNC_REPOSITORY_HOOKS:
+ success = c.Tr("admin.dashboard.resync_all_hooks_success")
+ err = models.SyncRepositoryHooks()
+ case REINIT_MISSING_REPOSITORY:
+ success = c.Tr("admin.dashboard.reinit_missing_repos_success")
+ err = models.ReinitMissingRepositories()
+ }
+
+ if err != nil {
+ c.Flash.Error(err.Error())
+ } else {
+ c.Flash.Success(success)
+ }
+ c.Redirect(setting.AppSubURL + "/admin")
+ return
+ }
+
+ c.Data["Stats"] = models.GetStatistic()
+ // FIXME: update periodically
+ updateSystemStatus()
+ c.Data["SysStatus"] = sysStatus
+ c.HTML(200, DASHBOARD)
+}
+
+func SendTestMail(c *context.Context) {
+ email := c.Query("email")
+ // Send a test email to the user's email address and redirect back to Config
+ if err := mailer.SendTestMail(email); err != nil {
+ c.Flash.Error(c.Tr("admin.config.test_mail_failed", email, err))
+ } else {
+ c.Flash.Info(c.Tr("admin.config.test_mail_sent", email))
+ }
+
+ c.Redirect(setting.AppSubURL + "/admin/config")
+}
+
+func Config(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.config")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminConfig"] = true
+
+ c.Data["AppURL"] = setting.AppURL
+ c.Data["Domain"] = setting.Domain
+ c.Data["OfflineMode"] = setting.OfflineMode
+ c.Data["DisableRouterLog"] = setting.DisableRouterLog
+ c.Data["RunUser"] = setting.RunUser
+ c.Data["RunMode"] = strings.Title(macaron.Env)
+ c.Data["StaticRootPath"] = setting.StaticRootPath
+ c.Data["LogRootPath"] = setting.LogRootPath
+ c.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser
+
+ c.Data["SSH"] = setting.SSH
+
+ c.Data["RepoRootPath"] = setting.RepoRootPath
+ c.Data["ScriptType"] = setting.ScriptType
+ c.Data["Repository"] = setting.Repository
+
+ c.Data["Service"] = setting.Service
+ c.Data["DbCfg"] = models.DbCfg
+ c.Data["Webhook"] = setting.Webhook
+
+ c.Data["MailerEnabled"] = false
+ if setting.MailService != nil {
+ c.Data["MailerEnabled"] = true
+ c.Data["Mailer"] = setting.MailService
+ }
+
+ c.Data["CacheAdapter"] = setting.CacheAdapter
+ c.Data["CacheInterval"] = setting.CacheInterval
+ c.Data["CacheConn"] = setting.CacheConn
+
+ c.Data["SessionConfig"] = setting.SessionConfig
+
+ c.Data["DisableGravatar"] = setting.DisableGravatar
+ c.Data["EnableFederatedAvatar"] = setting.EnableFederatedAvatar
+
+ c.Data["GitVersion"] = setting.Git.Version
+ c.Data["Git"] = setting.Git
+
+ type logger struct {
+ Mode, Config string
+ }
+ loggers := make([]*logger, len(setting.LogModes))
+ for i := range setting.LogModes {
+ loggers[i] = &logger{
+ Mode: strings.Title(setting.LogModes[i]),
+ }
+
+ result, _ := json.MarshalIndent(setting.LogConfigs[i], "", " ")
+ loggers[i].Config = string(result)
+ }
+ c.Data["Loggers"] = loggers
+
+ c.HTML(200, CONFIG)
+}
+
+func Monitor(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.monitor")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminMonitor"] = true
+ c.Data["Processes"] = process.Processes
+ c.Data["Entries"] = cron.ListTasks()
+ c.HTML(200, MONITOR)
+}
diff --git a/routes/admin/auths.go b/routes/admin/auths.go
new file mode 100644
index 00000000..56a0aad6
--- /dev/null
+++ b/routes/admin/auths.go
@@ -0,0 +1,265 @@
+// Copyright 2014 The Gogs 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 admin
+
+import (
+ "fmt"
+
+ "github.com/Unknwon/com"
+ "github.com/go-xorm/core"
+ log "gopkg.in/clog.v1"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/pkg/auth/ldap"
+ "github.com/gogits/gogs/pkg/context"
+ "github.com/gogits/gogs/pkg/form"
+ "github.com/gogits/gogs/pkg/setting"
+)
+
+const (
+ AUTHS = "admin/auth/list"
+ AUTH_NEW = "admin/auth/new"
+ AUTH_EDIT = "admin/auth/edit"
+)
+
+func Authentications(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.authentication")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminAuthentications"] = true
+
+ var err error
+ c.Data["Sources"], err = models.LoginSources()
+ if err != nil {
+ c.Handle(500, "LoginSources", err)
+ return
+ }
+
+ c.Data["Total"] = models.CountLoginSources()
+ c.HTML(200, AUTHS)
+}
+
+type dropdownItem struct {
+ Name string
+ Type interface{}
+}
+
+var (
+ authSources = []dropdownItem{
+ {models.LoginNames[models.LOGIN_LDAP], models.LOGIN_LDAP},
+ {models.LoginNames[models.LOGIN_DLDAP], models.LOGIN_DLDAP},
+ {models.LoginNames[models.LOGIN_SMTP], models.LOGIN_SMTP},
+ {models.LoginNames[models.LOGIN_PAM], models.LOGIN_PAM},
+ }
+ securityProtocols = []dropdownItem{
+ {models.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_UNENCRYPTED], ldap.SECURITY_PROTOCOL_UNENCRYPTED},
+ {models.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_LDAPS], ldap.SECURITY_PROTOCOL_LDAPS},
+ {models.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_START_TLS], ldap.SECURITY_PROTOCOL_START_TLS},
+ }
+)
+
+func NewAuthSource(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.auths.new")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminAuthentications"] = true
+
+ c.Data["type"] = models.LOGIN_LDAP
+ c.Data["CurrentTypeName"] = models.LoginNames[models.LOGIN_LDAP]
+ c.Data["CurrentSecurityProtocol"] = models.SecurityProtocolNames[ldap.SECURITY_PROTOCOL_UNENCRYPTED]
+ c.Data["smtp_auth"] = "PLAIN"
+ c.Data["is_active"] = true
+ c.Data["AuthSources"] = authSources
+ c.Data["SecurityProtocols"] = securityProtocols
+ c.Data["SMTPAuths"] = models.SMTPAuths
+ c.HTML(200, AUTH_NEW)
+}
+
+func parseLDAPConfig(f form.Authentication) *models.LDAPConfig {
+ return &models.LDAPConfig{
+ Source: &ldap.Source{
+ Name: f.Name,
+ Host: f.Host,
+ Port: f.Port,
+ SecurityProtocol: ldap.SecurityProtocol(f.SecurityProtocol),
+ SkipVerify: f.SkipVerify,
+ BindDN: f.BindDN,
+ UserDN: f.UserDN,
+ BindPassword: f.BindPassword,
+ UserBase: f.UserBase,
+ AttributeUsername: f.AttributeUsername,
+ AttributeName: f.AttributeName,
+ AttributeSurname: f.AttributeSurname,
+ AttributeMail: f.AttributeMail,
+ AttributesInBind: f.AttributesInBind,
+ Filter: f.Filter,
+ GroupEnabled: f.GroupEnabled,
+ GroupDN: f.GroupDN,
+ GroupFilter: f.GroupFilter,
+ GroupMemberUID: f.GroupMemberUID,
+ UserUID: f.UserUID,
+ AdminFilter: f.AdminFilter,
+ Enabled: true,
+ },
+ }
+}
+
+func parseSMTPConfig(f form.Authentication) *models.SMTPConfig {
+ return &models.SMTPConfig{
+ Auth: f.SMTPAuth,
+ Host: f.SMTPHost,
+ Port: f.SMTPPort,
+ AllowedDomains: f.AllowedDomains,
+ TLS: f.TLS,
+ SkipVerify: f.SkipVerify,
+ }
+}
+
+func NewAuthSourcePost(c *context.Context, f form.Authentication) {
+ c.Data["Title"] = c.Tr("admin.auths.new")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminAuthentications"] = true
+
+ c.Data["CurrentTypeName"] = models.LoginNames[models.LoginType(f.Type)]
+ c.Data["CurrentSecurityProtocol"] = models.SecurityProtocolNames[ldap.SecurityProtocol(f.SecurityProtocol)]
+ c.Data["AuthSources"] = authSources
+ c.Data["SecurityProtocols"] = securityProtocols
+ c.Data["SMTPAuths"] = models.SMTPAuths
+
+ hasTLS := false
+ var config core.Conversion
+ switch models.LoginType(f.Type) {
+ case models.LOGIN_LDAP, models.LOGIN_DLDAP:
+ config = parseLDAPConfig(f)
+ hasTLS = ldap.SecurityProtocol(f.SecurityProtocol) > ldap.SECURITY_PROTOCOL_UNENCRYPTED
+ case models.LOGIN_SMTP:
+ config = parseSMTPConfig(f)
+ hasTLS = true
+ case models.LOGIN_PAM:
+ config = &models.PAMConfig{
+ ServiceName: f.PAMServiceName,
+ }
+ default:
+ c.Error(400)
+ return
+ }
+ c.Data["HasTLS"] = hasTLS
+
+ if c.HasError() {
+ c.HTML(200, AUTH_NEW)
+ return
+ }
+
+ if err := models.CreateLoginSource(&models.LoginSource{
+ Type: models.LoginType(f.Type),
+ Name: f.Name,
+ IsActived: f.IsActive,
+ Cfg: config,
+ }); err != nil {
+ if models.IsErrLoginSourceAlreadyExist(err) {
+ c.Data["Err_Name"] = true
+ c.RenderWithErr(c.Tr("admin.auths.login_source_exist", err.(models.ErrLoginSourceAlreadyExist).Name), AUTH_NEW, f)
+ } else {
+ c.Handle(500, "CreateSource", err)
+ }
+ return
+ }
+
+ log.Trace("Authentication created by admin(%s): %s", c.User.Name, f.Name)
+
+ c.Flash.Success(c.Tr("admin.auths.new_success", f.Name))
+ c.Redirect(setting.AppSubURL + "/admin/auths")
+}
+
+func EditAuthSource(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.auths.edit")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminAuthentications"] = true
+
+ c.Data["SecurityProtocols"] = securityProtocols
+ c.Data["SMTPAuths"] = models.SMTPAuths
+
+ source, err := models.GetLoginSourceByID(c.ParamsInt64(":authid"))
+ if err != nil {
+ c.Handle(500, "GetLoginSourceByID", err)
+ return
+ }
+ c.Data["Source"] = source
+ c.Data["HasTLS"] = source.HasTLS()
+
+ c.HTML(200, AUTH_EDIT)
+}
+
+func EditAuthSourcePost(c *context.Context, f form.Authentication) {
+ c.Data["Title"] = c.Tr("admin.auths.edit")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminAuthentications"] = true
+
+ c.Data["SMTPAuths"] = models.SMTPAuths
+
+ source, err := models.GetLoginSourceByID(c.ParamsInt64(":authid"))
+ if err != nil {
+ c.Handle(500, "GetLoginSourceByID", err)
+ return
+ }
+ c.Data["Source"] = source
+ c.Data["HasTLS"] = source.HasTLS()
+
+ if c.HasError() {
+ c.HTML(200, AUTH_EDIT)
+ return
+ }
+
+ var config core.Conversion
+ switch models.LoginType(f.Type) {
+ case models.LOGIN_LDAP, models.LOGIN_DLDAP:
+ config = parseLDAPConfig(f)
+ case models.LOGIN_SMTP:
+ config = parseSMTPConfig(f)
+ case models.LOGIN_PAM:
+ config = &models.PAMConfig{
+ ServiceName: f.PAMServiceName,
+ }
+ default:
+ c.Error(400)
+ return
+ }
+
+ source.Name = f.Name
+ source.IsActived = f.IsActive
+ source.Cfg = config
+ if err := models.UpdateSource(source); err != nil {
+ c.Handle(500, "UpdateSource", err)
+ return
+ }
+ log.Trace("Authentication changed by admin(%s): %d", c.User.Name, source.ID)
+
+ c.Flash.Success(c.Tr("admin.auths.update_success"))
+ c.Redirect(setting.AppSubURL + "/admin/auths/" + com.ToStr(f.ID))
+}
+
+func DeleteAuthSource(c *context.Context) {
+ source, err := models.GetLoginSourceByID(c.ParamsInt64(":authid"))
+ if err != nil {
+ c.Handle(500, "GetLoginSourceByID", err)
+ return
+ }
+
+ if err = models.DeleteSource(source); err != nil {
+ if models.IsErrLoginSourceInUse(err) {
+ c.Flash.Error(c.Tr("admin.auths.still_in_used"))
+ } else {
+ c.Flash.Error(fmt.Sprintf("DeleteSource: %v", err))
+ }
+ c.JSON(200, map[string]interface{}{
+ "redirect": setting.AppSubURL + "/admin/auths/" + c.Params(":authid"),
+ })
+ return
+ }
+ log.Trace("Authentication deleted by admin(%s): %d", c.User.Name, source.ID)
+
+ c.Flash.Success(c.Tr("admin.auths.deletion_success"))
+ c.JSON(200, map[string]interface{}{
+ "redirect": setting.AppSubURL + "/admin/auths",
+ })
+}
diff --git a/routes/admin/notice.go b/routes/admin/notice.go
new file mode 100644
index 00000000..c743a1da
--- /dev/null
+++ b/routes/admin/notice.go
@@ -0,0 +1,72 @@
+// Copyright 2014 The Gogs 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 admin
+
+import (
+ "github.com/Unknwon/com"
+ "github.com/Unknwon/paginater"
+ log "gopkg.in/clog.v1"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/pkg/context"
+ "github.com/gogits/gogs/pkg/setting"
+)
+
+const (
+ NOTICES = "admin/notice"
+)
+
+func Notices(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.notices")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminNotices"] = true
+
+ total := models.CountNotices()
+ page := c.QueryInt("page")
+ if page <= 1 {
+ page = 1
+ }
+ c.Data["Page"] = paginater.New(int(total), setting.UI.Admin.NoticePagingNum, page, 5)
+
+ notices, err := models.Notices(page, setting.UI.Admin.NoticePagingNum)
+ if err != nil {
+ c.Handle(500, "Notices", err)
+ return
+ }
+ c.Data["Notices"] = notices
+
+ c.Data["Total"] = total
+ c.HTML(200, NOTICES)
+}
+
+func DeleteNotices(c *context.Context) {
+ strs := c.QueryStrings("ids[]")
+ ids := make([]int64, 0, len(strs))
+ for i := range strs {
+ id := com.StrTo(strs[i]).MustInt64()
+ if id > 0 {
+ ids = append(ids, id)
+ }
+ }
+
+ if err := models.DeleteNoticesByIDs(ids); err != nil {
+ c.Flash.Error("DeleteNoticesByIDs: " + err.Error())
+ c.Status(500)
+ } else {
+ c.Flash.Success(c.Tr("admin.notices.delete_success"))
+ c.Status(200)
+ }
+}
+
+func EmptyNotices(c *context.Context) {
+ if err := models.DeleteNotices(0, 0); err != nil {
+ c.Handle(500, "DeleteNotices", err)
+ return
+ }
+
+ log.Trace("System notices deleted by admin (%s): [start: %d]", c.User.Name, 0)
+ c.Flash.Success(c.Tr("admin.notices.delete_success"))
+ c.Redirect(setting.AppSubURL + "/admin/notices")
+}
diff --git a/routes/admin/orgs.go b/routes/admin/orgs.go
new file mode 100644
index 00000000..f42e1fdf
--- /dev/null
+++ b/routes/admin/orgs.go
@@ -0,0 +1,31 @@
+// Copyright 2014 The Gogs 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 admin
+
+import (
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/pkg/context"
+ "github.com/gogits/gogs/pkg/setting"
+ "github.com/gogits/gogs/routes"
+)
+
+const (
+ ORGS = "admin/org/list"
+)
+
+func Organizations(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.organizations")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminOrganizations"] = true
+
+ routes.RenderUserSearch(c, &routes.UserSearchOptions{
+ Type: models.USER_TYPE_ORGANIZATION,
+ Counter: models.CountOrganizations,
+ Ranger: models.Organizations,
+ PageSize: setting.UI.Admin.OrgPagingNum,
+ OrderBy: "id ASC",
+ TplName: ORGS,
+ })
+}
diff --git a/routes/admin/repos.go b/routes/admin/repos.go
new file mode 100644
index 00000000..b4fa2266
--- /dev/null
+++ b/routes/admin/repos.go
@@ -0,0 +1,87 @@
+// Copyright 2014 The Gogs 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 admin
+
+import (
+ "github.com/Unknwon/paginater"
+ log "gopkg.in/clog.v1"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/pkg/context"
+ "github.com/gogits/gogs/pkg/setting"
+)
+
+const (
+ REPOS = "admin/repo/list"
+)
+
+func Repos(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.repositories")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminRepositories"] = true
+
+ page := c.QueryInt("page")
+ if page <= 0 {
+ page = 1
+ }
+
+ var (
+ repos []*models.Repository
+ count int64
+ err error
+ )
+
+ keyword := c.Query("q")
+ if len(keyword) == 0 {
+ repos, err = models.Repositories(page, setting.UI.Admin.RepoPagingNum)
+ if err != nil {
+ c.Handle(500, "Repositories", err)
+ return
+ }
+ count = models.CountRepositories(true)
+ } else {
+ repos, count, err = models.SearchRepositoryByName(&models.SearchRepoOptions{
+ Keyword: keyword,
+ OrderBy: "id ASC",
+ Private: true,
+ Page: page,
+ PageSize: setting.UI.Admin.RepoPagingNum,
+ })
+ if err != nil {
+ c.Handle(500, "SearchRepositoryByName", err)
+ return
+ }
+ }
+ c.Data["Keyword"] = keyword
+ c.Data["Total"] = count
+ c.Data["Page"] = paginater.New(int(count), setting.UI.Admin.RepoPagingNum, page, 5)
+
+ if err = models.RepositoryList(repos).LoadAttributes(); err != nil {
+ c.Handle(500, "LoadAttributes", err)
+ return
+ }
+ c.Data["Repos"] = repos
+
+ c.HTML(200, REPOS)
+}
+
+func DeleteRepo(c *context.Context) {
+ repo, err := models.GetRepositoryByID(c.QueryInt64("id"))
+ if err != nil {
+ c.Handle(500, "GetRepositoryByID", err)
+ return
+ }
+
+ if err := models.DeleteRepository(repo.MustOwner().ID, repo.ID); err != nil {
+ c.Handle(500, "DeleteRepository", err)
+ return
+ }
+ log.Trace("Repository deleted: %s/%s", repo.MustOwner().Name, repo.Name)
+
+ c.Flash.Success(c.Tr("repo.settings.deletion_success"))
+ c.JSON(200, map[string]interface{}{
+ "redirect": setting.AppSubURL + "/admin/repos?page=" + c.Query("page"),
+ })
+}
diff --git a/routes/admin/users.go b/routes/admin/users.go
new file mode 100644
index 00000000..cfeb73de
--- /dev/null
+++ b/routes/admin/users.go
@@ -0,0 +1,262 @@
+// Copyright 2014 The Gogs 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 admin
+
+import (
+ "strings"
+
+ "github.com/Unknwon/com"
+ log "gopkg.in/clog.v1"
+
+ "github.com/gogits/gogs/models"
+ "github.com/gogits/gogs/pkg/context"
+ "github.com/gogits/gogs/pkg/form"
+ "github.com/gogits/gogs/pkg/mailer"
+ "github.com/gogits/gogs/pkg/setting"
+ "github.com/gogits/gogs/routes"
+)
+
+const (
+ USERS = "admin/user/list"
+ USER_NEW = "admin/user/new"
+ USER_EDIT = "admin/user/edit"
+)
+
+func Users(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.users")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminUsers"] = true
+
+ routes.RenderUserSearch(c, &routes.UserSearchOptions{
+ Type: models.USER_TYPE_INDIVIDUAL,
+ Counter: models.CountUsers,
+ Ranger: models.Users,
+ PageSize: setting.UI.Admin.UserPagingNum,
+ OrderBy: "id ASC",
+ TplName: USERS,
+ })
+}
+
+func NewUser(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.users.new_account")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminUsers"] = true
+
+ c.Data["login_type"] = "0-0"
+
+ sources, err := models.LoginSources()
+ if err != nil {
+ c.Handle(500, "LoginSources", err)
+ return
+ }
+ c.Data["Sources"] = sources
+
+ c.Data["CanSendEmail"] = setting.MailService != nil
+ c.HTML(200, USER_NEW)
+}
+
+func NewUserPost(c *context.Context, f form.AdminCrateUser) {
+ c.Data["Title"] = c.Tr("admin.users.new_account")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminUsers"] = true
+
+ sources, err := models.LoginSources()
+ if err != nil {
+ c.Handle(500, "LoginSources", err)
+ return
+ }
+ c.Data["Sources"] = sources
+
+ c.Data["CanSendEmail"] = setting.MailService != nil
+
+ if c.HasError() {
+ c.HTML(200, USER_NEW)
+ return
+ }
+
+ u := &models.User{
+ Name: f.UserName,
+ Email: f.Email,
+ Passwd: f.Password,
+ IsActive: true,
+ LoginType: models.LOGIN_PLAIN,
+ }
+
+ if len(f.LoginType) > 0 {
+ fields := strings.Split(f.LoginType, "-")
+ if len(fields) == 2 {
+ u.LoginType = models.LoginType(com.StrTo(fields[0]).MustInt())
+ u.LoginSource = com.StrTo(fields[1]).MustInt64()
+ u.LoginName = f.LoginName
+ }
+ }
+
+ if err := models.CreateUser(u); err != nil {
+ switch {
+ case models.IsErrUserAlreadyExist(err):
+ c.Data["Err_UserName"] = true
+ c.RenderWithErr(c.Tr("form.username_been_taken"), USER_NEW, &f)
+ case models.IsErrEmailAlreadyUsed(err):
+ c.Data["Err_Email"] = true
+ c.RenderWithErr(c.Tr("form.email_been_used"), USER_NEW, &f)
+ case models.IsErrNameReserved(err):
+ c.Data["Err_UserName"] = true
+ c.RenderWithErr(c.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), USER_NEW, &f)
+ case models.IsErrNamePatternNotAllowed(err):
+ c.Data["Err_UserName"] = true
+ c.RenderWithErr(c.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), USER_NEW, &f)
+ default:
+ c.Handle(500, "CreateUser", err)
+ }
+ return
+ }
+ log.Trace("Account created by admin (%s): %s", c.User.Name, u.Name)
+
+ // Send email notification.
+ if f.SendNotify && setting.MailService != nil {
+ mailer.SendRegisterNotifyMail(c.Context, models.NewMailerUser(u))
+ }
+
+ c.Flash.Success(c.Tr("admin.users.new_success", u.Name))
+ c.Redirect(setting.AppSubURL + "/admin/users/" + com.ToStr(u.ID))
+}
+
+func prepareUserInfo(c *context.Context) *models.User {
+ u, err := models.GetUserByID(c.ParamsInt64(":userid"))
+ if err != nil {
+ c.Handle(500, "GetUserByID", err)
+ return nil
+ }
+ c.Data["User"] = u
+
+ if u.LoginSource > 0 {
+ c.Data["LoginSource"], err = models.GetLoginSourceByID(u.LoginSource)
+ if err != nil {
+ c.Handle(500, "GetLoginSourceByID", err)
+ return nil
+ }
+ } else {
+ c.Data["LoginSource"] = &models.LoginSource{}
+ }
+
+ sources, err := models.LoginSources()
+ if err != nil {
+ c.Handle(500, "LoginSources", err)
+ return nil
+ }
+ c.Data["Sources"] = sources
+
+ return u
+}
+
+func EditUser(c *context.Context) {
+ c.Data["Title"] = c.Tr("admin.users.edit_account")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminUsers"] = true
+ c.Data["EnableLocalPathMigration"] = setting.Repository.EnableLocalPathMigration
+
+ prepareUserInfo(c)
+ if c.Written() {
+ return
+ }
+
+ c.HTML(200, USER_EDIT)
+}
+
+func EditUserPost(c *context.Context, f form.AdminEditUser) {
+ c.Data["Title"] = c.Tr("admin.users.edit_account")
+ c.Data["PageIsAdmin"] = true
+ c.Data["PageIsAdminUsers"] = true
+ c.Data["EnableLocalPathMigration"] = setting.Repository.EnableLocalPathMigration
+
+ u := prepareUserInfo(c)
+ if c.Written() {
+ return
+ }
+
+ if c.HasError() {
+ c.HTML(200, USER_EDIT)
+ return
+ }
+
+ fields := strings.Split(f.LoginType, "-")
+ if len(fields) == 2 {
+ loginType := models.LoginType(com.StrTo(fields[0]).MustInt())
+ loginSource := com.StrTo(fields[1]).MustInt64()
+
+ if u.LoginSource != loginSource {
+ u.LoginSource = loginSource
+ u.LoginType = loginType
+ }
+ }
+
+ if len(f.Password) > 0 {
+ u.Passwd = f.Password
+ var err error
+ if u.Salt, err = models.GetUserSalt(); err != nil {
+ c.Handle(500, "UpdateUser", err)
+ return
+ }
+ u.EncodePasswd()
+ }
+
+ u.LoginName = f.LoginName
+ u.FullName = f.FullName
+ u.Email = f.Email
+ u.Website = f.Website
+ u.Location = f.Location
+ u.MaxRepoCreation = f.MaxRepoCreation
+ u.IsActive = f.Active
+ u.IsAdmin = f.Admin
+ u.AllowGitHook = f.AllowGitHook
+ u.AllowImportLocal = f.AllowImportLocal
+ u.ProhibitLogin = f.ProhibitLogin
+
+ if err := models.UpdateUser(u); err != nil {
+ if models.IsErrEmailAlreadyUsed(err) {
+ c.Data["Err_Email"] = true
+ c.RenderWithErr(c.Tr("form.email_been_used"), USER_EDIT, &f)
+ } else {
+ c.Handle(500, "UpdateUser", err)
+ }
+ return
+ }
+ log.Trace("Account profile updated by admin (%s): %s", c.User.Name, u.Name)
+
+ c.Flash.Success(c.Tr("admin.users.update_profile_success"))
+ c.Redirect(setting.AppSubURL + "/admin/users/" + c.Params(":userid"))
+}
+
+func DeleteUser(c *context.Context) {
+ u, err := models.GetUserByID(c.ParamsInt64(":userid"))
+ if err != nil {
+ c.Handle(500, "GetUserByID", err)
+ return
+ }
+
+ if err = models.DeleteUser(u); err != nil {
+ switch {
+ case models.IsErrUserOwnRepos(err):
+ c.Flash.Error(c.Tr("admin.users.still_own_repo"))
+ c.JSON(200, map[string]interface{}{
+ "redirect": setting.AppSubURL + "/admin/users/" + c.Params(":userid"),
+ })
+ case models.IsErrUserHasOrgs(err):
+ c.Flash.Error(c.Tr("admin.users.still_has_org"))
+ c.JSON(200, map[string]interface{}{
+ "redirect": setting.AppSubURL + "/admin/users/" + c.Params(":userid"),
+ })
+ default:
+ c.Handle(500, "DeleteUser", err)
+ }
+ return
+ }
+ log.Trace("Account deleted by admin (%s): %s", c.User.Name, u.Name)
+
+ c.Flash.Success(c.Tr("admin.users.deletion_success"))
+ c.JSON(200, map[string]interface{}{
+ "redirect": setting.AppSubURL + "/admin/users",
+ })
+}