diff options
author | Unknwon <u@gogs.io> | 2017-06-11 00:34:14 -0400 |
---|---|---|
committer | Unknwon <u@gogs.io> | 2017-06-11 00:34:14 -0400 |
commit | 4400d2fdd933204044aeb18ce7d8613c53aa87c0 (patch) | |
tree | 841e91d5294c49b7335170fbc4b9ff79e882f91a /routers | |
parent | 6197a7639a88f7fb0fee8927e1d501504ae770ff (diff) |
Refactoring: rename package routers -> routes
Diffstat (limited to 'routers')
57 files changed, 0 insertions, 12967 deletions
diff --git a/routers/admin/admin.go b/routers/admin/admin.go deleted file mode 100644 index 0d5eb7a6..00000000 --- a/routers/admin/admin.go +++ /dev/null @@ -1,258 +0,0 @@ -// 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/routers/admin/auths.go b/routers/admin/auths.go deleted file mode 100644 index 56a0aad6..00000000 --- a/routers/admin/auths.go +++ /dev/null @@ -1,265 +0,0 @@ -// 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/routers/admin/notice.go b/routers/admin/notice.go deleted file mode 100644 index c743a1da..00000000 --- a/routers/admin/notice.go +++ /dev/null @@ -1,72 +0,0 @@ -// 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/routers/admin/orgs.go b/routers/admin/orgs.go deleted file mode 100644 index 4b995acd..00000000 --- a/routers/admin/orgs.go +++ /dev/null @@ -1,31 +0,0 @@ -// 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/routers" -) - -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 - - routers.RenderUserSearch(c, &routers.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/routers/admin/repos.go b/routers/admin/repos.go deleted file mode 100644 index b4fa2266..00000000 --- a/routers/admin/repos.go +++ /dev/null @@ -1,87 +0,0 @@ -// 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/routers/admin/users.go b/routers/admin/users.go deleted file mode 100644 index 237f2dc6..00000000 --- a/routers/admin/users.go +++ /dev/null @@ -1,262 +0,0 @@ -// 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/routers" -) - -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 - - routers.RenderUserSearch(c, &routers.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", - }) -} diff --git a/routers/api/v1/admin/org.go b/routers/api/v1/admin/org.go deleted file mode 100644 index 996a83bf..00000000 --- a/routers/api/v1/admin/org.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2015 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 ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/routers/api/v1/convert" - "github.com/gogits/gogs/routers/api/v1/user" -) - -// https://github.com/gogits/go-gogs-client/wiki/Administration-Organizations#create-a-new-organization -func CreateOrg(c *context.APIContext, form api.CreateOrgOption) { - u := user.GetUserByParams(c) - if c.Written() { - return - } - - org := &models.User{ - Name: form.UserName, - FullName: form.FullName, - Description: form.Description, - Website: form.Website, - Location: form.Location, - IsActive: true, - Type: models.USER_TYPE_ORGANIZATION, - } - if err := models.CreateOrganization(org, u); err != nil { - if models.IsErrUserAlreadyExist(err) || - models.IsErrNameReserved(err) || - models.IsErrNamePatternNotAllowed(err) { - c.Error(422, "", err) - } else { - c.Error(500, "CreateOrganization", err) - } - return - } - - c.JSON(201, convert.ToOrganization(org)) -} diff --git a/routers/api/v1/admin/org_repo.go b/routers/api/v1/admin/org_repo.go deleted file mode 100644 index 7abad1a8..00000000 --- a/routers/api/v1/admin/org_repo.go +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2016 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/models/errors" - "github.com/gogits/gogs/pkg/context" -) - -func GetRepositoryByParams(c *context.APIContext) *models.Repository { - repo, err := models.GetRepositoryByName(c.Org.Team.OrgID, c.Params(":reponame")) - if err != nil { - if errors.IsRepoNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetRepositoryByName", err) - } - return nil - } - return repo -} - -func AddTeamRepository(c *context.APIContext) { - repo := GetRepositoryByParams(c) - if c.Written() { - return - } - if err := c.Org.Team.AddRepository(repo); err != nil { - c.Error(500, "AddRepository", err) - return - } - - c.Status(204) -} - -func RemoveTeamRepository(c *context.APIContext) { - repo := GetRepositoryByParams(c) - if c.Written() { - return - } - if err := c.Org.Team.RemoveRepository(repo.ID); err != nil { - c.Error(500, "RemoveRepository", err) - return - } - - c.Status(204) -} diff --git a/routers/api/v1/admin/org_team.go b/routers/api/v1/admin/org_team.go deleted file mode 100644 index 7ec6c08a..00000000 --- a/routers/api/v1/admin/org_team.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2016 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 ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/routers/api/v1/convert" - "github.com/gogits/gogs/routers/api/v1/user" -) - -func CreateTeam(c *context.APIContext, form api.CreateTeamOption) { - team := &models.Team{ - OrgID: c.Org.Organization.ID, - Name: form.Name, - Description: form.Description, - Authorize: models.ParseAccessMode(form.Permission), - } - if err := models.NewTeam(team); err != nil { - if models.IsErrTeamAlreadyExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "NewTeam", err) - } - return - } - - c.JSON(201, convert.ToTeam(team)) -} - -func AddTeamMember(c *context.APIContext) { - u := user.GetUserByParams(c) - if c.Written() { - return - } - if err := c.Org.Team.AddMember(u.ID); err != nil { - c.Error(500, "AddMember", err) - return - } - - c.Status(204) -} - -func RemoveTeamMember(c *context.APIContext) { - u := user.GetUserByParams(c) - if c.Written() { - return - } - - if err := c.Org.Team.RemoveMember(u.ID); err != nil { - c.Error(500, "RemoveMember", err) - return - } - - c.Status(204) -} diff --git a/routers/api/v1/admin/repo.go b/routers/api/v1/admin/repo.go deleted file mode 100644 index 6c8e8e8d..00000000 --- a/routers/api/v1/admin/repo.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 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 ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/routers/api/v1/repo" - "github.com/gogits/gogs/routers/api/v1/user" -) - -// https://github.com/gogits/go-gogs-client/wiki/Administration-Repositories#create-a-new-repository -func CreateRepo(c *context.APIContext, form api.CreateRepoOption) { - owner := user.GetUserByParams(c) - if c.Written() { - return - } - - repo.CreateUserRepo(c, owner, form) -} diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go deleted file mode 100644 index 8776217d..00000000 --- a/routers/api/v1/admin/user.go +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2015 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 ( - log "gopkg.in/clog.v1" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/mailer" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/routers/api/v1/user" -) - -func parseLoginSource(c *context.APIContext, u *models.User, sourceID int64, loginName string) { - if sourceID == 0 { - return - } - - source, err := models.GetLoginSourceByID(sourceID) - if err != nil { - if models.IsErrLoginSourceNotExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "GetLoginSourceByID", err) - } - return - } - - u.LoginType = source.Type - u.LoginSource = source.ID - u.LoginName = loginName -} - -// https://github.com/gogits/go-gogs-client/wiki/Administration-Users#create-a-new-user -func CreateUser(c *context.APIContext, form api.CreateUserOption) { - u := &models.User{ - Name: form.Username, - FullName: form.FullName, - Email: form.Email, - Passwd: form.Password, - IsActive: true, - LoginType: models.LOGIN_PLAIN, - } - - parseLoginSource(c, u, form.SourceID, form.LoginName) - if c.Written() { - return - } - - if err := models.CreateUser(u); err != nil { - if models.IsErrUserAlreadyExist(err) || - models.IsErrEmailAlreadyUsed(err) || - models.IsErrNameReserved(err) || - models.IsErrNamePatternNotAllowed(err) { - c.Error(422, "", err) - } else { - c.Error(500, "CreateUser", err) - } - return - } - log.Trace("Account created by admin (%s): %s", c.User.Name, u.Name) - - // Send email notification. - if form.SendNotify && setting.MailService != nil { - mailer.SendRegisterNotifyMail(c.Context.Context, models.NewMailerUser(u)) - } - - c.JSON(201, u.APIFormat()) -} - -// https://github.com/gogits/go-gogs-client/wiki/Administration-Users#edit-an-existing-user -func EditUser(c *context.APIContext, form api.EditUserOption) { - u := user.GetUserByParams(c) - if c.Written() { - return - } - - parseLoginSource(c, u, form.SourceID, form.LoginName) - if c.Written() { - return - } - - if len(form.Password) > 0 { - u.Passwd = form.Password - var err error - if u.Salt, err = models.GetUserSalt(); err != nil { - c.Error(500, "UpdateUser", err) - return - } - u.EncodePasswd() - } - - u.LoginName = form.LoginName - u.FullName = form.FullName - u.Email = form.Email - u.Website = form.Website - u.Location = form.Location - if form.Active != nil { - u.IsActive = *form.Active - } - if form.Admin != nil { - u.IsAdmin = *form.Admin - } - if form.AllowGitHook != nil { - u.AllowGitHook = *form.AllowGitHook - } - if form.AllowImportLocal != nil { - u.AllowImportLocal = *form.AllowImportLocal - } - if form.MaxRepoCreation != nil { - u.MaxRepoCreation = *form.MaxRepoCreation - } - - if err := models.UpdateUser(u); err != nil { - if models.IsErrEmailAlreadyUsed(err) { - c.Error(422, "", err) - } else { - c.Error(500, "UpdateUser", err) - } - return - } - log.Trace("Account profile updated by admin (%s): %s", c.User.Name, u.Name) - - c.JSON(200, u.APIFormat()) -} - -// https://github.com/gogits/go-gogs-client/wiki/Administration-Users#delete-a-user -func DeleteUser(c *context.APIContext) { - u := user.GetUserByParams(c) - if c.Written() { - return - } - - if err := models.DeleteUser(u); err != nil { - if models.IsErrUserOwnRepos(err) || - models.IsErrUserHasOrgs(err) { - c.Error(422, "", err) - } else { - c.Error(500, "DeleteUser", err) - } - return - } - log.Trace("Account deleted by admin(%s): %s", c.User.Name, u.Name) - - c.Status(204) -} - -// https://github.com/gogits/go-gogs-client/wiki/Administration-Users#create-a-public-key-for-user -func CreatePublicKey(c *context.APIContext, form api.CreateKeyOption) { - u := user.GetUserByParams(c) - if c.Written() { - return - } - user.CreateUserPublicKey(c, form, u.ID) -} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go deleted file mode 100644 index 35ca861a..00000000 --- a/routers/api/v1/api.go +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2015 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 v1 - -import ( - "strings" - - "github.com/go-macaron/binding" - "gopkg.in/macaron.v1" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/routers/api/v1/admin" - "github.com/gogits/gogs/routers/api/v1/misc" - "github.com/gogits/gogs/routers/api/v1/org" - "github.com/gogits/gogs/routers/api/v1/repo" - "github.com/gogits/gogs/routers/api/v1/user" -) - -func repoAssignment() macaron.Handler { - return func(c *context.APIContext) { - userName := c.Params(":username") - repoName := c.Params(":reponame") - - var ( - owner *models.User - err error - ) - - // Check if the user is the same as the repository owner. - if c.IsLogged && c.User.LowerName == strings.ToLower(userName) { - owner = c.User - } else { - owner, err = models.GetUserByName(userName) - if err != nil { - if errors.IsUserNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetUserByName", err) - } - return - } - } - c.Repo.Owner = owner - - // Get repository. - repo, err := models.GetRepositoryByName(owner.ID, repoName) - if err != nil { - if errors.IsRepoNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetRepositoryByName", err) - } - return - } else if err = repo.GetOwner(); err != nil { - c.Error(500, "GetOwner", err) - return - } - - if c.IsLogged && c.User.IsAdmin { - c.Repo.AccessMode = models.ACCESS_MODE_OWNER - } else { - mode, err := models.AccessLevel(c.User.ID, repo) - if err != nil { - c.Error(500, "AccessLevel", err) - return - } - c.Repo.AccessMode = mode - } - - if !c.Repo.HasAccess() { - c.Status(404) - return - } - - c.Repo.Repository = repo - } -} - -// Contexter middleware already checks token for user sign in process. -func reqToken() macaron.Handler { - return func(c *context.Context) { - if !c.IsLogged { - c.Error(401) - return - } - } -} - -func reqBasicAuth() macaron.Handler { - return func(c *context.Context) { - if !c.IsBasicAuth { - c.Error(401) - return - } - } -} - -func reqAdmin() macaron.Handler { - return func(c *context.Context) { - if !c.IsLogged || !c.User.IsAdmin { - c.Error(403) - return - } - } -} - -func reqRepoWriter() macaron.Handler { - return func(c *context.Context) { - if !c.Repo.IsWriter() { - c.Error(403) - return - } - } -} - -func orgAssignment(args ...bool) macaron.Handler { - var ( - assignOrg bool - assignTeam bool - ) - if len(args) > 0 { - assignOrg = args[0] - } - if len(args) > 1 { - assignTeam = args[1] - } - return func(c *context.APIContext) { - c.Org = new(context.APIOrganization) - - var err error - if assignOrg { - c.Org.Organization, err = models.GetUserByName(c.Params(":orgname")) - if err != nil { - if errors.IsUserNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetUserByName", err) - } - return - } - } - - if assignTeam { - c.Org.Team, err = models.GetTeamByID(c.ParamsInt64(":teamid")) - if err != nil { - if errors.IsUserNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetTeamById", err) - } - return - } - } - } -} - -func mustEnableIssues(c *context.APIContext) { - if !c.Repo.Repository.EnableIssues || c.Repo.Repository.EnableExternalTracker { - c.Status(404) - return - } -} - -// RegisterRoutes registers all v1 APIs routes to web application. -// FIXME: custom form error response -func RegisterRoutes(m *macaron.Macaron) { - bind := binding.Bind - - m.Group("/v1", func() { - // Handle preflight OPTIONS request - m.Options("/*", func() {}) - - // Miscellaneous - m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown) - m.Post("/markdown/raw", misc.MarkdownRaw) - - // Users - m.Group("/users", func() { - m.Get("/search", user.Search) - - m.Group("/:username", func() { - m.Get("", user.GetInfo) - - m.Group("/tokens", func() { - m.Combo("").Get(user.ListAccessTokens). - Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken) - }, reqBasicAuth()) - }) - }) - - m.Group("/users", func() { - m.Group("/:username", func() { - m.Get("/keys", user.ListPublicKeys) - - m.Get("/followers", user.ListFollowers) - m.Group("/following", func() { - m.Get("", user.ListFollowing) - m.Get("/:target", user.CheckFollowing) - }) - }) - }, reqToken()) - - m.Group("/user", func() { - m.Get("", user.GetAuthenticatedUser) - m.Combo("/emails").Get(user.ListEmails). - Post(bind(api.CreateEmailOption{}), user.AddEmail). - Delete(bind(api.CreateEmailOption{}), user.DeleteEmail) - - m.Get("/followers", user.ListMyFollowers) - m.Group("/following", func() { - m.Get("", user.ListMyFollowing) - m.Combo("/:username").Get(user.CheckMyFollowing).Put(user.Follow).Delete(user.Unfollow) - }) - - m.Group("/keys", func() { - m.Combo("").Get(user.ListMyPublicKeys). - Post(bind(api.CreateKeyOption{}), user.CreatePublicKey) - m.Combo("/:id").Get(user.GetPublicKey). - Delete(user.DeletePublicKey) - }) - - m.Combo("/issues").Get(repo.ListUserIssues) - }, reqToken()) - - // Repositories - m.Get("/users/:username/repos", reqToken(), repo.ListUserRepositories) - m.Get("/orgs/:org/repos", reqToken(), repo.ListOrgRepositories) - m.Combo("/user/repos", reqToken()).Get(repo.ListMyRepos). - Post(bind(api.CreateRepoOption{}), repo.Create) - m.Post("/org/:org/repos", reqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepo) - - m.Group("/repos", func() { - m.Get("/search", repo.Search) - }) - - m.Group("/repos", func() { - m.Post("/migrate", bind(form.MigrateRepo{}), repo.Migrate) - m.Combo("/:username/:reponame", repoAssignment()).Get(repo.Get). - Delete(repo.Delete) - - m.Group("/:username/:reponame", func() { - m.Group("/hooks", func() { - m.Combo("").Get(repo.ListHooks). - Post(bind(api.CreateHookOption{}), repo.CreateHook) - m.Combo("/:id").Patch(bind(api.EditHookOption{}), repo.EditHook). - Delete(repo.DeleteHook) - }) - m.Group("/collaborators", func() { - m.Get("", repo.ListCollaborators) - m.Combo("/:collaborator").Get(repo.IsCollaborator).Put(bind(api.AddCollaboratorOption{}), repo.AddCollaborator). - Delete(repo.DeleteCollaborator) - }) - m.Get("/raw/*", context.RepoRef(), repo.GetRawFile) - m.Get("/archive/*", repo.GetArchive) - m.Get("/forks", repo.ListForks) - m.Group("/branches", func() { - m.Get("", repo.ListBranches) - m.Get("/*", repo.GetBranch) - }) - m.Group("/keys", func() { - m.Combo("").Get(repo.ListDeployKeys). - Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey) - m.Combo("/:id").Get(repo.GetDeployKey). - Delete(repo.DeleteDeploykey) - }) - m.Group("/issues", func() { - m.Combo("").Get(repo.ListIssues).Post(bind(api.CreateIssueOption{}), repo.CreateIssue) - m.Group("/comments", func() { - m.Get("", repo.ListRepoIssueComments) - m.Combo("/:id").Patch(bind(api.EditIssueCommentOption{}), repo.EditIssueComment) - }) - m.Group("/:index", func() { - m.Combo("").Get(repo.GetIssue).Patch(bind(api.EditIssueOption{}), repo.EditIssue) - - m.Group("/comments", func() { - m.Combo("").Get(repo.ListIssueComments).Post(bind(api.CreateIssueCommentOption{}), repo.CreateIssueComment) - m.Combo("/:id").Patch(bind(api.EditIssueCommentOption{}), repo.EditIssueComment). - Delete(repo.DeleteIssueComment) - }) - - m.Group("/labels", func() { - m.Combo("").Get(repo.ListIssueLabels). - Post(bind(api.IssueLabelsOption{}), repo.AddIssueLabels). - Put(bind(api.IssueLabelsOption{}), repo.ReplaceIssueLabels). - Delete(repo.ClearIssueLabels) - m.Delete("/:id", repo.DeleteIssueLabel) - }) - - }) - }, mustEnableIssues) - m.Group("/labels", func() { - m.Combo("").Get(repo.ListLabels). - Post(bind(api.CreateLabelOption{}), repo.CreateLabel) - m.Combo("/:id").Get(repo.GetLabel).Patch(bind(api.EditLabelOption{}), repo.EditLabel). - Delete(repo.DeleteLabel) - }) - m.Group("/milestones", func() { - m.Combo("").Get(repo.ListMilestones). - Post(reqRepoWriter(), bind(api.CreateMilestoneOption{}), repo.CreateMilestone) - m.Combo("/:id").Get(repo.GetMilestone). - Patch(reqRepoWriter(), bind(api.EditMilestoneOption{}), repo.EditMilestone). - Delete(reqRepoWriter(), repo.DeleteMilestone) - }) - m.Post("/mirror-sync", repo.MirrorSync) - m.Get("/editorconfig/:filename", context.RepoRef(), repo.GetEditorconfig) - }, repoAssignment()) - }, reqToken()) - - m.Get("/issues", reqToken(), repo.ListUserIssues) - - // Organizations - m.Get("/user/orgs", reqToken(), org.ListMyOrgs) - m.Get("/users/:username/orgs", org.ListUserOrgs) - m.Group("/orgs/:orgname", func() { - m.Combo("").Get(org.Get).Patch(bind(api.EditOrgOption{}), org.Edit) - m.Combo("/teams").Get(org.ListTeams) - }, orgAssignment(true)) - - m.Any("/*", func(c *context.Context) { - c.Error(404) - }) - - m.Group("/admin", func() { - m.Group("/users", func() { - m.Post("", bind(api.CreateUserOption{}), admin.CreateUser) - - m.Group("/:username", func() { - m.Combo("").Patch(bind(api.EditUserOption{}), admin.EditUser). - Delete(admin.DeleteUser) - m.Post("/keys", bind(api.CreateKeyOption{}), admin.CreatePublicKey) - m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg) - m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo) - }) - }) - - m.Group("/orgs/:orgname", func() { - m.Group("/teams", func() { - m.Post("", orgAssignment(true), bind(api.CreateTeamOption{}), admin.CreateTeam) - }) - }) - m.Group("/teams", func() { - m.Group("/:teamid", func() { - m.Combo("/members/:username").Put(admin.AddTeamMember).Delete(admin.RemoveTeamMember) - m.Combo("/repos/:reponame").Put(admin.AddTeamRepository).Delete(admin.RemoveTeamRepository) - }, orgAssignment(false, true)) - }) - }, reqAdmin()) - }, context.APIContexter()) -} diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go deleted file mode 100644 index fcadb51f..00000000 --- a/routers/api/v1/convert/convert.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright 2015 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 convert - -import ( - "fmt" - - "github.com/Unknwon/com" - - "github.com/gogits/git-module" - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" -) - -func ToEmail(email *models.EmailAddress) *api.Email { - return &api.Email{ - Email: email.Email, - Verified: email.IsActivated, - Primary: email.IsPrimary, - } -} - -func ToBranch(b *models.Branch, c *git.Commit) *api.Branch { - return &api.Branch{ - Name: b.Name, - Commit: ToCommit(c), - } -} - -func ToCommit(c *git.Commit) *api.PayloadCommit { - authorUsername := "" - author, err := models.GetUserByEmail(c.Author.Email) - if err == nil { - authorUsername = author.Name - } - committerUsername := "" - committer, err := models.GetUserByEmail(c.Committer.Email) - if err == nil { - committerUsername = committer.Name - } - return &api.PayloadCommit{ - ID: c.ID.String(), - Message: c.Message(), - URL: "Not implemented", - Author: &api.PayloadUser{ - Name: c.Author.Name, - Email: c.Author.Email, - UserName: authorUsername, - }, - Committer: &api.PayloadUser{ - Name: c.Committer.Name, - Email: c.Committer.Email, - UserName: committerUsername, - }, - Timestamp: c.Author.When, - } -} - -func ToPublicKey(apiLink string, key *models.PublicKey) *api.PublicKey { - return &api.PublicKey{ - ID: key.ID, - Key: key.Content, - URL: apiLink + com.ToStr(key.ID), - Title: key.Name, - Created: key.Created, - } -} - -func ToHook(repoLink string, w *models.Webhook) *api.Hook { - config := map[string]string{ - "url": w.URL, - "content_type": w.ContentType.Name(), - } - if w.HookTaskType == models.SLACK { - s := w.GetSlackHook() - config["channel"] = s.Channel - config["username"] = s.Username - config["icon_url"] = s.IconURL - config["color"] = s.Color - } - - return &api.Hook{ - ID: w.ID, - Type: w.HookTaskType.Name(), - URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID), - Active: w.IsActive, - Config: config, - Events: w.EventsArray(), - Updated: w.Updated, - Created: w.Created, - } -} - -func ToDeployKey(apiLink string, key *models.DeployKey) *api.DeployKey { - return &api.DeployKey{ - ID: key.ID, - Key: key.Content, - URL: apiLink + com.ToStr(key.ID), - Title: key.Name, - Created: key.Created, - ReadOnly: true, // All deploy keys are read-only. - } -} - -func ToOrganization(org *models.User) *api.Organization { - return &api.Organization{ - ID: org.ID, - AvatarUrl: org.AvatarLink(), - UserName: org.Name, - FullName: org.FullName, - Description: org.Description, - Website: org.Website, - Location: org.Location, - } -} - -func ToTeam(team *models.Team) *api.Team { - return &api.Team{ - ID: team.ID, - Name: team.Name, - Description: team.Description, - Permission: team.Authorize.String(), - } -} diff --git a/routers/api/v1/convert/utils.go b/routers/api/v1/convert/utils.go deleted file mode 100644 index d0beab3d..00000000 --- a/routers/api/v1/convert/utils.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2016 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 convert - -import ( - "github.com/gogits/gogs/pkg/setting" -) - -// ToCorrectPageSize makes sure page size is in allowed range. -func ToCorrectPageSize(size int) int { - if size <= 0 { - size = 10 - } else if size > setting.API.MaxResponseItems { - size = setting.API.MaxResponseItems - } - return size -} diff --git a/routers/api/v1/misc/markdown.go b/routers/api/v1/misc/markdown.go deleted file mode 100644 index 98bfd7d0..00000000 --- a/routers/api/v1/misc/markdown.go +++ /dev/null @@ -1,42 +0,0 @@ -// 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 misc - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/markup" -) - -// https://github.com/gogits/go-gogs-client/wiki/Miscellaneous#render-an-arbitrary-markdown-document -func Markdown(c *context.APIContext, form api.MarkdownOption) { - if c.HasApiError() { - c.Error(422, "", c.GetErrMsg()) - return - } - - if len(form.Text) == 0 { - c.Write([]byte("")) - return - } - - switch form.Mode { - case "gfm": - c.Write(markup.Markdown([]byte(form.Text), form.Context, nil)) - default: - c.Write(markup.RawMarkdown([]byte(form.Text), "")) - } -} - -// https://github.com/gogits/go-gogs-client/wiki/Miscellaneous#render-a-markdown-document-in-raw-mode -func MarkdownRaw(c *context.APIContext) { - body, err := c.Req.Body().Bytes() - if err != nil { - c.Error(422, "", err) - return - } - c.Write(markup.RawMarkdown(body, "")) -} diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go deleted file mode 100644 index 107fc19c..00000000 --- a/routers/api/v1/org/org.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2015 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 org - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/routers/api/v1/convert" - "github.com/gogits/gogs/routers/api/v1/user" -) - -func listUserOrgs(c *context.APIContext, u *models.User, all bool) { - if err := u.GetOrganizations(all); err != nil { - c.Error(500, "GetOrganizations", err) - return - } - - apiOrgs := make([]*api.Organization, len(u.Orgs)) - for i := range u.Orgs { - apiOrgs[i] = convert.ToOrganization(u.Orgs[i]) - } - c.JSON(200, &apiOrgs) -} - -// https://github.com/gogits/go-gogs-client/wiki/Organizations#list-your-organizations -func ListMyOrgs(c *context.APIContext) { - listUserOrgs(c, c.User, true) -} - -// https://github.com/gogits/go-gogs-client/wiki/Organizations#list-user-organizations -func ListUserOrgs(c *context.APIContext) { - u := user.GetUserByParams(c) - if c.Written() { - return - } - listUserOrgs(c, u, false) -} - -// https://github.com/gogits/go-gogs-client/wiki/Organizations#get-an-organization -func Get(c *context.APIContext) { - c.JSON(200, convert.ToOrganization(c.Org.Organization)) -} - -// https://github.com/gogits/go-gogs-client/wiki/Organizations#edit-an-organization -func Edit(c *context.APIContext, form api.EditOrgOption) { - org := c.Org.Organization - if !org.IsOwnedBy(c.User.ID) { - c.Status(403) - return - } - - org.FullName = form.FullName - org.Description = form.Description - org.Website = form.Website - org.Location = form.Location - if err := models.UpdateUser(org); err != nil { - c.Error(500, "UpdateUser", err) - return - } - - c.JSON(200, convert.ToOrganization(org)) -} diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go deleted file mode 100644 index a952ea53..00000000 --- a/routers/api/v1/org/team.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2016 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 org - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/routers/api/v1/convert" -) - -func ListTeams(c *context.APIContext) { - org := c.Org.Organization - if err := org.GetTeams(); err != nil { - c.Error(500, "GetTeams", err) - return - } - - apiTeams := make([]*api.Team, len(org.Teams)) - for i := range org.Teams { - apiTeams[i] = convert.ToTeam(org.Teams[i]) - } - c.JSON(200, apiTeams) -} diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go deleted file mode 100644 index 3d5e646c..00000000 --- a/routers/api/v1/repo/branch.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016 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 repo - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/routers/api/v1/convert" -) - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#get-branch -func GetBranch(c *context.APIContext) { - branch, err := c.Repo.Repository.GetBranch(c.Params("*")) - if err != nil { - if models.IsErrBranchNotExist(err) { - c.Error(404, "GetBranch", err) - } else { - c.Error(500, "GetBranch", err) - } - return - } - - commit, err := branch.GetCommit() - if err != nil { - c.Error(500, "GetCommit", err) - return - } - - c.JSON(200, convert.ToBranch(branch, commit)) -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#list-branches -func ListBranches(c *context.APIContext) { - branches, err := c.Repo.Repository.GetBranches() - if err != nil { - c.Error(500, "GetBranches", err) - return - } - - apiBranches := make([]*api.Branch, len(branches)) - for i := range branches { - commit, err := branches[i].GetCommit() - if err != nil { - c.Error(500, "GetCommit", err) - return - } - apiBranches[i] = convert.ToBranch(branches[i], commit) - } - - c.JSON(200, &apiBranches) -} diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go deleted file mode 100644 index d295ac0f..00000000 --- a/routers/api/v1/repo/collaborators.go +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2016 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 repo - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" -) - -func ListCollaborators(c *context.APIContext) { - collaborators, err := c.Repo.Repository.GetCollaborators() - if err != nil { - if errors.IsUserNotExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "GetCollaborators", err) - } - return - } - - apiCollaborators := make([]*api.Collaborator, len(collaborators)) - for i := range collaborators { - apiCollaborators[i] = collaborators[i].APIFormat() - } - c.JSON(200, &apiCollaborators) -} - -func AddCollaborator(c *context.APIContext, form api.AddCollaboratorOption) { - collaborator, err := models.GetUserByName(c.Params(":collaborator")) - if err != nil { - if errors.IsUserNotExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "GetUserByName", err) - } - return - } - - if err := c.Repo.Repository.AddCollaborator(collaborator); err != nil { - c.Error(500, "AddCollaborator", err) - return - } - - if form.Permission != nil { - if err := c.Repo.Repository.ChangeCollaborationAccessMode(collaborator.ID, models.ParseAccessMode(*form.Permission)); err != nil { - c.Error(500, "ChangeCollaborationAccessMode", err) - return - } - } - - c.Status(204) -} - -func IsCollaborator(c *context.APIContext) { - collaborator, err := models.GetUserByName(c.Params(":collaborator")) - if err != nil { - if errors.IsUserNotExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "GetUserByName", err) - } - return - } - - if !c.Repo.Repository.IsCollaborator(collaborator.ID) { - c.Status(404) - } else { - c.Status(204) - } -} - -func DeleteCollaborator(c *context.APIContext) { - collaborator, err := models.GetUserByName(c.Params(":collaborator")) - if err != nil { - if errors.IsUserNotExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "GetUserByName", err) - } - return - } - - if err := c.Repo.Repository.DeleteCollaboration(collaborator.ID); err != nil { - c.Error(500, "DeleteCollaboration", err) - return - } - - c.Status(204) -} diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go deleted file mode 100644 index df6a4857..00000000 --- a/routers/api/v1/repo/file.go +++ /dev/null @@ -1,72 +0,0 @@ -// 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 repo - -import ( - "github.com/gogits/git-module" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/routers/repo" -) - -// https://github.com/gogits/go-gogs-client/wiki/Repositories-Contents#download-raw-content -func GetRawFile(c *context.APIContext) { - if !c.Repo.HasAccess() { - c.Status(404) - return - } - - if c.Repo.Repository.IsBare { - c.Status(404) - return - } - - blob, err := c.Repo.Commit.GetBlobByPath(c.Repo.TreePath) - if err != nil { - if git.IsErrNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetBlobByPath", err) - } - return - } - if err = repo.ServeBlob(c.Context, blob); err != nil { - c.Error(500, "ServeBlob", err) - } -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories-Contents#download-archive -func GetArchive(c *context.APIContext) { - repoPath := models.RepoPath(c.Params(":username"), c.Params(":reponame")) - gitRepo, err := git.OpenRepository(repoPath) - if err != nil { - c.Error(500, "OpenRepository", err) - return - } - c.Repo.GitRepo = gitRepo - - repo.Download(c.Context) -} - -func GetEditorconfig(c *context.APIContext) { - ec, err := c.Repo.GetEditorconfig() - if err != nil { - if git.IsErrNotExist(err) { - c.Error(404, "GetEditorconfig", err) - } else { - c.Error(500, "GetEditorconfig", err) - } - return - } - - fileName := c.Params("filename") - def := ec.GetDefinitionForFilename(fileName) - if def == nil { - c.Error(404, "GetDefinitionForFilename", err) - return - } - c.JSON(200, def) -} diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go deleted file mode 100644 index 7c2b293e..00000000 --- a/routers/api/v1/repo/hook.go +++ /dev/null @@ -1,186 +0,0 @@ -// 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 repo - -import ( - "encoding/json" - - "github.com/Unknwon/com" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/routers/api/v1/convert" -) - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#list-hooks -func ListHooks(c *context.APIContext) { - hooks, err := models.GetWebhooksByRepoID(c.Repo.Repository.ID) - if err != nil { - c.Error(500, "GetWebhooksByRepoID", err) - return - } - - apiHooks := make([]*api.Hook, len(hooks)) - for i := range hooks { - apiHooks[i] = convert.ToHook(c.Repo.RepoLink, hooks[i]) - } - c.JSON(200, &apiHooks) -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#create-a-hook -func CreateHook(c *context.APIContext, form api.CreateHookOption) { - if !models.IsValidHookTaskType(form.Type) { - c.Error(422, "", "Invalid hook type") - return - } - for _, name := range []string{"url", "content_type"} { - if _, ok := form.Config[name]; !ok { - c.Error(422, "", "Missing config option: "+name) - return - } - } - if !models.IsValidHookContentType(form.Config["content_type"]) { - c.Error(422, "", "Invalid content type") - return - } - - if len(form.Events) == 0 { - form.Events = []string{"push"} - } - w := &models.Webhook{ - RepoID: c.Repo.Repository.ID, - URL: form.Config["url"], - ContentType: models.ToHookContentType(form.Config["content_type"]), - Secret: form.Config["secret"], - HookEvent: &models.HookEvent{ - ChooseEvents: true, - HookEvents: models.HookEvents{ - Create: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_CREATE)), - Delete: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_DELETE)), - Fork: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_FORK)), - Push: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_PUSH)), - Issues: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_ISSUES)), - IssueComment: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_ISSUE_COMMENT)), - PullRequest: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_PULL_REQUEST)), - Release: com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_RELEASE)), - }, - }, - IsActive: form.Active, - HookTaskType: models.ToHookTaskType(form.Type), - } - if w.HookTaskType == models.SLACK { - channel, ok := form.Config["channel"] - if !ok { - c.Error(422, "", "Missing config option: channel") - return - } - meta, err := json.Marshal(&models.SlackMeta{ - Channel: channel, - Username: form.Config["username"], - IconURL: form.Config["icon_url"], - Color: form.Config["color"], - }) - if err != nil { - c.Error(500, "slack: JSON marshal failed", err) - return - } - w.Meta = string(meta) - } - - if err := w.UpdateEvent(); err != nil { - c.Error(500, "UpdateEvent", err) - return - } else if err := models.CreateWebhook(w); err != nil { - c.Error(500, "CreateWebhook", err) - return - } - - c.JSON(201, convert.ToHook(c.Repo.RepoLink, w)) -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#edit-a-hook -func EditHook(c *context.APIContext, form api.EditHookOption) { - w, err := models.GetWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - if err != nil { - if errors.IsWebhookNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetWebhookOfRepoByID", err) - } - return - } - - if form.Config != nil { - if url, ok := form.Config["url"]; ok { - w.URL = url - } - if ct, ok := form.Config["content_type"]; ok { - if !models.IsValidHookContentType(ct) { - c.Error(422, "", "Invalid content type") - return - } - w.ContentType = models.ToHookContentType(ct) - } - - if w.HookTaskType == models.SLACK { - if channel, ok := form.Config["channel"]; ok { - meta, err := json.Marshal(&models.SlackMeta{ - Channel: channel, - Username: form.Config["username"], - IconURL: form.Config["icon_url"], - Color: form.Config["color"], - }) - if err != nil { - c.Error(500, "slack: JSON marshal failed", err) - return - } - w.Meta = string(meta) - } - } - } - - // Update events - if len(form.Events) == 0 { - form.Events = []string{"push"} - } - w.PushOnly = false - w.SendEverything = false - w.ChooseEvents = true - w.Create = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_CREATE)) - w.Delete = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_DELETE)) - w.Fork = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_FORK)) - w.Push = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_PUSH)) - w.Issues = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_ISSUES)) - w.IssueComment = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_ISSUE_COMMENT)) - w.PullRequest = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_PULL_REQUEST)) - w.Release = com.IsSliceContainsStr(form.Events, string(models.HOOK_EVENT_RELEASE)) - if err = w.UpdateEvent(); err != nil { - c.Error(500, "UpdateEvent", err) - return - } - - if form.Active != nil { - w.IsActive = *form.Active - } - - if err := models.UpdateWebhook(w); err != nil { - c.Error(500, "UpdateWebhook", err) - return - } - - c.JSON(200, convert.ToHook(c.Repo.RepoLink, w)) -} - -func DeleteHook(c *context.APIContext) { - if err := models.DeleteWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")); err != nil { - c.Error(500, "DeleteWebhookByRepoID", err) - return - } - - c.Status(204) -} diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go deleted file mode 100644 index d6ae7b4d..00000000 --- a/routers/api/v1/repo/issue.go +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright 2016 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 repo - -import ( - "fmt" - "strings" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" -) - -func listIssues(c *context.APIContext, opts *models.IssuesOptions) { - issues, err := models.Issues(opts) - if err != nil { - c.Error(500, "Issues", err) - return - } - - count, err := models.IssuesCount(opts) - if err != nil { - c.Error(500, "IssuesCount", err) - return - } - - // FIXME: use IssueList to improve performance. - apiIssues := make([]*api.Issue, len(issues)) - for i := range issues { - if err = issues[i].LoadAttributes(); err != nil { - c.Error(500, "LoadAttributes", err) - return - } - apiIssues[i] = issues[i].APIFormat() - } - - c.SetLinkHeader(int(count), setting.UI.IssuePagingNum) - c.JSON(200, &apiIssues) -} - -func ListUserIssues(c *context.APIContext) { - opts := models.IssuesOptions{ - AssigneeID: c.User.ID, - Page: c.QueryInt("page"), - IsClosed: api.StateType(c.Query("state")) == api.STATE_CLOSED, - } - - listIssues(c, &opts) -} - -func ListIssues(c *context.APIContext) { - opts := models.IssuesOptions{ - RepoID: c.Repo.Repository.ID, - Page: c.QueryInt("page"), - IsClosed: api.StateType(c.Query("state")) == api.STATE_CLOSED, - } - - listIssues(c, &opts) -} - -func GetIssue(c *context.APIContext) { - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - if errors.IsIssueNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetIssueByIndex", err) - } - return - } - c.JSON(200, issue.APIFormat()) -} - -func CreateIssue(c *context.APIContext, form api.CreateIssueOption) { - issue := &models.Issue{ - RepoID: c.Repo.Repository.ID, - Title: form.Title, - PosterID: c.User.ID, - Poster: c.User, - Content: form.Body, - } - - if c.Repo.IsWriter() { - if len(form.Assignee) > 0 { - assignee, err := models.GetUserByName(form.Assignee) - if err != nil { - if errors.IsUserNotExist(err) { - c.Error(422, "", fmt.Sprintf("Assignee does not exist: [name: %s]", form.Assignee)) - } else { - c.Error(500, "GetUserByName", err) - } - return - } - issue.AssigneeID = assignee.ID - } - issue.MilestoneID = form.Milestone - } else { - form.Labels = nil - } - - if err := models.NewIssue(c.Repo.Repository, issue, form.Labels, nil); err != nil { - c.Error(500, "NewIssue", err) - return - } - - if form.Closed { - if err := issue.ChangeStatus(c.User, c.Repo.Repository, true); err != nil { - c.Error(500, "ChangeStatus", err) - return - } - } - - // Refetch from database to assign some automatic values - var err error - issue, err = models.GetIssueByID(issue.ID) - if err != nil { - c.Error(500, "GetIssueByID", err) - return - } - c.JSON(201, issue.APIFormat()) -} - -func EditIssue(c *context.APIContext, form api.EditIssueOption) { - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - if errors.IsIssueNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetIssueByIndex", err) - } - return - } - - if !issue.IsPoster(c.User.ID) && !c.Repo.IsWriter() { - c.Status(403) - return - } - - if len(form.Title) > 0 { - issue.Title = form.Title - } - if form.Body != nil { - issue.Content = *form.Body - } - - if c.Repo.IsWriter() && form.Assignee != nil && - (issue.Assignee == nil || issue.Assignee.LowerName != strings.ToLower(*form.Assignee)) { - if len(*form.Assignee) == 0 { - issue.AssigneeID = 0 - } else { - assignee, err := models.GetUserByName(*form.Assignee) - if err != nil { - if errors.IsUserNotExist(err) { - c.Error(422, "", fmt.Sprintf("assignee does not exist: [name: %s]", *form.Assignee)) - } else { - c.Error(500, "GetUserByName", err) - } - return - } - issue.AssigneeID = assignee.ID - } - - if err = models.UpdateIssueUserByAssignee(issue); err != nil { - c.Error(500, "UpdateIssueUserByAssignee", err) - return - } - } - if c.Repo.IsWriter() && form.Milestone != nil && - issue.MilestoneID != *form.Milestone { - oldMilestoneID := issue.MilestoneID - issue.MilestoneID = *form.Milestone - if err = models.ChangeMilestoneAssign(c.User, issue, oldMilestoneID); err != nil { - c.Error(500, "ChangeMilestoneAssign", err) - return - } - } - - if err = models.UpdateIssue(issue); err != nil { - c.Error(500, "UpdateIssue", err) - return - } - if form.State != nil { - if err = issue.ChangeStatus(c.User, c.Repo.Repository, api.STATE_CLOSED == api.StateType(*form.State)); err != nil { - c.Error(500, "ChangeStatus", err) - return - } - } - - // Refetch from database to assign some automatic values - issue, err = models.GetIssueByID(issue.ID) - if err != nil { - c.Error(500, "GetIssueByID", err) - return - } - c.JSON(201, issue.APIFormat()) -} diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go deleted file mode 100644 index 4a057d76..00000000 --- a/routers/api/v1/repo/issue_comment.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2015 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 repo - -import ( - "time" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" -) - -func ListIssueComments(c *context.APIContext) { - var since time.Time - if len(c.Query("since")) > 0 { - since, _ = time.Parse(time.RFC3339, c.Query("since")) - } - - // comments,err:=models.GetCommentsByIssueIDSince(, since) - issue, err := models.GetRawIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - c.Error(500, "GetRawIssueByIndex", err) - return - } - - comments, err := models.GetCommentsByIssueIDSince(issue.ID, since.Unix()) - if err != nil { - c.Error(500, "GetCommentsByIssueIDSince", err) - return - } - - apiComments := make([]*api.Comment, len(comments)) - for i := range comments { - apiComments[i] = comments[i].APIFormat() - } - c.JSON(200, &apiComments) -} - -func ListRepoIssueComments(c *context.APIContext) { - var since time.Time - if len(c.Query("since")) > 0 { - since, _ = time.Parse(time.RFC3339, c.Query("since")) - } - - comments, err := models.GetCommentsByRepoIDSince(c.Repo.Repository.ID, since.Unix()) - if err != nil { - c.Error(500, "GetCommentsByRepoIDSince", err) - return - } - - apiComments := make([]*api.Comment, len(comments)) - for i := range comments { - apiComments[i] = comments[i].APIFormat() - } - c.JSON(200, &apiComments) -} - -func CreateIssueComment(c *context.APIContext, form api.CreateIssueCommentOption) { - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - c.Error(500, "GetIssueByIndex", err) - return - } - - comment, err := models.CreateIssueComment(c.User, c.Repo.Repository, issue, form.Body, nil) - if err != nil { - c.Error(500, "CreateIssueComment", err) - return - } - - c.JSON(201, comment.APIFormat()) -} - -func EditIssueComment(c *context.APIContext, form api.EditIssueCommentOption) { - comment, err := models.GetCommentByID(c.ParamsInt64(":id")) - if err != nil { - if models.IsErrCommentNotExist(err) { - c.Error(404, "GetCommentByID", err) - } else { - c.Error(500, "GetCommentByID", err) - } - return - } - - if c.User.ID != comment.PosterID && !c.Repo.IsAdmin() { - c.Status(403) - return - } else if comment.Type != models.COMMENT_TYPE_COMMENT { - c.Status(204) - return - } - - oldContent := comment.Content - comment.Content = form.Body - if err := models.UpdateComment(c.User, comment, oldContent); err != nil { - c.Error(500, "UpdateComment", err) - return - } - c.JSON(200, comment.APIFormat()) -} - -func DeleteIssueComment(c *context.APIContext) { - comment, err := models.GetCommentByID(c.ParamsInt64(":id")) - if err != nil { - if models.IsErrCommentNotExist(err) { - c.Error(404, "GetCommentByID", err) - } else { - c.Error(500, "GetCommentByID", err) - } - return - } - - if c.User.ID != comment.PosterID && !c.Repo.IsAdmin() { - c.Status(403) - return - } else if comment.Type != models.COMMENT_TYPE_COMMENT { - c.Status(204) - return - } - - if err = models.DeleteCommentByID(c.User, comment.ID); err != nil { - c.Error(500, "DeleteCommentByID", err) - return - } - c.Status(204) -} diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go deleted file mode 100644 index f3f2d730..00000000 --- a/routers/api/v1/repo/issue_label.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2016 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 repo - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" -) - -func ListIssueLabels(c *context.APIContext) { - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - if errors.IsIssueNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetIssueByIndex", err) - } - return - } - - apiLabels := make([]*api.Label, len(issue.Labels)) - for i := range issue.Labels { - apiLabels[i] = issue.Labels[i].APIFormat() - } - c.JSON(200, &apiLabels) -} - -func AddIssueLabels(c *context.APIContext, form api.IssueLabelsOption) { - if !c.Repo.IsWriter() { - c.Status(403) - return - } - - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - if errors.IsIssueNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetIssueByIndex", err) - } - return - } - - labels, err := models.GetLabelsInRepoByIDs(c.Repo.Repository.ID, form.Labels) - if err != nil { - c.Error(500, "GetLabelsInRepoByIDs", err) - return - } - - if err = issue.AddLabels(c.User, labels); err != nil { - c.Error(500, "AddLabels", err) - return - } - - labels, err = models.GetLabelsByIssueID(issue.ID) - if err != nil { - c.Error(500, "GetLabelsByIssueID", err) - return - } - - apiLabels := make([]*api.Label, len(labels)) - for i := range labels { - apiLabels[i] = issue.Labels[i].APIFormat() - } - c.JSON(200, &apiLabels) -} - -func DeleteIssueLabel(c *context.APIContext) { - if !c.Repo.IsWriter() { - c.Status(403) - return - } - - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - if errors.IsIssueNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetIssueByIndex", err) - } - return - } - - label, err := models.GetLabelOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - if err != nil { - if models.IsErrLabelNotExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "GetLabelInRepoByID", err) - } - return - } - - if err := models.DeleteIssueLabel(issue, label); err != nil { - c.Error(500, "DeleteIssueLabel", err) - return - } - - c.Status(204) -} - -func ReplaceIssueLabels(c *context.APIContext, form api.IssueLabelsOption) { - if !c.Repo.IsWriter() { - c.Status(403) - return - } - - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - if errors.IsIssueNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetIssueByIndex", err) - } - return - } - - labels, err := models.GetLabelsInRepoByIDs(c.Repo.Repository.ID, form.Labels) - if err != nil { - c.Error(500, "GetLabelsInRepoByIDs", err) - return - } - - if err := issue.ReplaceLabels(labels); err != nil { - c.Error(500, "ReplaceLabels", err) - return - } - - labels, err = models.GetLabelsByIssueID(issue.ID) - if err != nil { - c.Error(500, "GetLabelsByIssueID", err) - return - } - - apiLabels := make([]*api.Label, len(labels)) - for i := range labels { - apiLabels[i] = issue.Labels[i].APIFormat() - } - c.JSON(200, &apiLabels) -} - -func ClearIssueLabels(c *context.APIContext) { - if !c.Repo.IsWriter() { - c.Status(403) - return - } - - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - if errors.IsIssueNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetIssueByIndex", err) - } - return - } - - if err := issue.ClearLabels(c.User); err != nil { - c.Error(500, "ClearLabels", err) - return - } - - c.Status(204) -} diff --git a/routers/api/v1/repo/key.go b/routers/api/v1/repo/key.go deleted file mode 100644 index 901df4c7..00000000 --- a/routers/api/v1/repo/key.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2015 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 repo - -import ( - "fmt" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/routers/api/v1/convert" -) - -func composeDeployKeysAPILink(repoPath string) string { - return setting.AppURL + "api/v1/repos/" + repoPath + "/keys/" -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories-Deploy-Keys#list-deploy-keys -func ListDeployKeys(c *context.APIContext) { - keys, err := models.ListDeployKeys(c.Repo.Repository.ID) - if err != nil { - c.Error(500, "ListDeployKeys", err) - return - } - - apiLink := composeDeployKeysAPILink(c.Repo.Owner.Name + "/" + c.Repo.Repository.Name) - apiKeys := make([]*api.DeployKey, len(keys)) - for i := range keys { - if err = keys[i].GetContent(); err != nil { - c.Error(500, "GetContent", err) - return - } - apiKeys[i] = convert.ToDeployKey(apiLink, keys[i]) - } - - c.JSON(200, &apiKeys) -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories-Deploy-Keys#get-a-deploy-key -func GetDeployKey(c *context.APIContext) { - key, err := models.GetDeployKeyByID(c.ParamsInt64(":id")) - if err != nil { - if models.IsErrDeployKeyNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetDeployKeyByID", err) - } - return - } - - if err = key.GetContent(); err != nil { - c.Error(500, "GetContent", err) - return - } - - apiLink := composeDeployKeysAPILink(c.Repo.Owner.Name + "/" + c.Repo.Repository.Name) - c.JSON(200, convert.ToDeployKey(apiLink, key)) -} - -func HandleCheckKeyStringError(c *context.APIContext, err error) { - if models.IsErrKeyUnableVerify(err) { - c.Error(422, "", "Unable to verify key content") - } else { - c.Error(422, "", fmt.Errorf("Invalid key content: %v", err)) - } -} - -func HandleAddKeyError(c *context.APIContext, err error) { - switch { - case models.IsErrKeyAlreadyExist(err): - c.Error(422, "", "Key content has been used as non-deploy key") - case models.IsErrKeyNameAlreadyUsed(err): - c.Error(422, "", "Key title has been used") - default: - c.Error(500, "AddKey", err) - } -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories-Deploy-Keys#add-a-new-deploy-key -func CreateDeployKey(c *context.APIContext, form api.CreateKeyOption) { - content, err := models.CheckPublicKeyString(form.Key) - if err != nil { - HandleCheckKeyStringError(c, err) - return - } - - key, err := models.AddDeployKey(c.Repo.Repository.ID, form.Title, content) - if err != nil { - HandleAddKeyError(c, err) - return - } - - key.Content = content - apiLink := composeDeployKeysAPILink(c.Repo.Owner.Name + "/" + c.Repo.Repository.Name) - c.JSON(201, convert.ToDeployKey(apiLink, key)) -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories-Deploy-Keys#remove-a-deploy-key -func DeleteDeploykey(c *context.APIContext) { - if err := models.DeleteDeployKey(c.User, c.ParamsInt64(":id")); err != nil { - if models.IsErrKeyAccessDenied(err) { - c.Error(403, "", "You do not have access to this key") - } else { - c.Error(500, "DeleteDeployKey", err) - } - return - } - - c.Status(204) -} diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go deleted file mode 100644 index 1161d633..00000000 --- a/routers/api/v1/repo/label.go +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2016 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 repo - -import ( - "github.com/Unknwon/com" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" -) - -func ListLabels(c *context.APIContext) { - labels, err := models.GetLabelsByRepoID(c.Repo.Repository.ID) - if err != nil { - c.Error(500, "GetLabelsByRepoID", err) - return - } - - apiLabels := make([]*api.Label, len(labels)) - for i := range labels { - apiLabels[i] = labels[i].APIFormat() - } - c.JSON(200, &apiLabels) -} - -func GetLabel(c *context.APIContext) { - var label *models.Label - var err error - idStr := c.Params(":id") - if id := com.StrTo(idStr).MustInt64(); id > 0 { - label, err = models.GetLabelOfRepoByID(c.Repo.Repository.ID, id) - } else { - label, err = models.GetLabelOfRepoByName(c.Repo.Repository.ID, idStr) - } - if err != nil { - if models.IsErrLabelNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetLabelByRepoID", err) - } - return - } - - c.JSON(200, label.APIFormat()) -} - -func CreateLabel(c *context.APIContext, form api.CreateLabelOption) { - if !c.Repo.IsWriter() { - c.Status(403) - return - } - - label := &models.Label{ - Name: form.Name, - Color: form.Color, - RepoID: c.Repo.Repository.ID, - } - if err := models.NewLabels(label); err != nil { - c.Error(500, "NewLabel", err) - return - } - c.JSON(201, label.APIFormat()) -} - -func EditLabel(c *context.APIContext, form api.EditLabelOption) { - if !c.Repo.IsWriter() { - c.Status(403) - return - } - - label, err := models.GetLabelOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - if err != nil { - if models.IsErrLabelNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetLabelByRepoID", err) - } - return - } - - if form.Name != nil { - label.Name = *form.Name - } - if form.Color != nil { - label.Color = *form.Color - } - if err := models.UpdateLabel(label); err != nil { - c.Handle(500, "UpdateLabel", err) - return - } - c.JSON(200, label.APIFormat()) -} - -func DeleteLabel(c *context.APIContext) { - if !c.Repo.IsWriter() { - c.Status(403) - return - } - - if err := models.DeleteLabel(c.Repo.Repository.ID, c.ParamsInt64(":id")); err != nil { - c.Error(500, "DeleteLabel", err) - return - } - - c.Status(204) -} diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go deleted file mode 100644 index baf8eb2f..00000000 --- a/routers/api/v1/repo/milestone.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2016 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 repo - -import ( - "time" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" -) - -func ListMilestones(c *context.APIContext) { - milestones, err := models.GetMilestonesByRepoID(c.Repo.Repository.ID) - if err != nil { - c.Error(500, "GetMilestonesByRepoID", err) - return - } - - apiMilestones := make([]*api.Milestone, len(milestones)) - for i := range milestones { - apiMilestones[i] = milestones[i].APIFormat() - } - c.JSON(200, &apiMilestones) -} - -func GetMilestone(c *context.APIContext) { - milestone, err := models.GetMilestoneByRepoID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - if err != nil { - if models.IsErrMilestoneNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetMilestoneByRepoID", err) - } - return - } - c.JSON(200, milestone.APIFormat()) -} - -func CreateMilestone(c *context.APIContext, form api.CreateMilestoneOption) { - if form.Deadline == nil { - defaultDeadline, _ := time.ParseInLocation("2006-01-02", "9999-12-31", time.Local) - form.Deadline = &defaultDeadline - } - - milestone := &models.Milestone{ - RepoID: c.Repo.Repository.ID, - Name: form.Title, - Content: form.Description, - Deadline: *form.Deadline, - } - - if err := models.NewMilestone(milestone); err != nil { - c.Error(500, "NewMilestone", err) - return - } - c.JSON(201, milestone.APIFormat()) -} - -func EditMilestone(c *context.APIContext, form api.EditMilestoneOption) { - milestone, err := models.GetMilestoneByRepoID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - if err != nil { - if models.IsErrMilestoneNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetMilestoneByRepoID", err) - } - return - } - - if len(form.Title) > 0 { - milestone.Name = form.Title - } - if form.Description != nil { - milestone.Content = *form.Description - } - if form.Deadline != nil && !form.Deadline.IsZero() { - milestone.Deadline = *form.Deadline - } - - if form.State != nil { - if err = milestone.ChangeStatus(api.STATE_CLOSED == api.StateType(*form.State)); err != nil { - c.Error(500, "ChangeStatus", err) - return - } - } else if err = models.UpdateMilestone(milestone); err != nil { - c.Handle(500, "UpdateMilestone", err) - return - } - - c.JSON(200, milestone.APIFormat()) -} - -func DeleteMilestone(c *context.APIContext) { - if err := models.DeleteMilestoneOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")); err != nil { - c.Error(500, "DeleteMilestoneByRepoID", err) - return - } - c.Status(204) -} diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go deleted file mode 100644 index 727e1678..00000000 --- a/routers/api/v1/repo/repo.go +++ /dev/null @@ -1,380 +0,0 @@ -// 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 repo - -import ( - "path" - - log "gopkg.in/clog.v1" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/routers/api/v1/convert" -) - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#search-repositories -func Search(c *context.APIContext) { - opts := &models.SearchRepoOptions{ - Keyword: path.Base(c.Query("q")), - OwnerID: c.QueryInt64("uid"), - PageSize: convert.ToCorrectPageSize(c.QueryInt("limit")), - } - - // Check visibility. - if c.IsLogged && opts.OwnerID > 0 { - if c.User.ID == opts.OwnerID { - opts.Private = true - } else { - u, err := models.GetUserByID(opts.OwnerID) - if err != nil { - c.JSON(500, map[string]interface{}{ - "ok": false, - "error": err.Error(), - }) - return - } - if u.IsOrganization() && u.IsOwnedBy(c.User.ID) { - opts.Private = true - } - // FIXME: how about collaborators? - } - } - - repos, count, err := models.SearchRepositoryByName(opts) - if err != nil { - c.JSON(500, map[string]interface{}{ - "ok": false, - "error": err.Error(), - }) - return - } - - if err = models.RepositoryList(repos).LoadAttributes(); err != nil { - c.JSON(500, map[string]interface{}{ - "ok": false, - "error": err.Error(), - }) - return - } - - results := make([]*api.Repository, len(repos)) - for i := range repos { - results[i] = repos[i].APIFormat(nil) - } - - c.SetLinkHeader(int(count), setting.API.MaxResponseItems) - c.JSON(200, map[string]interface{}{ - "ok": true, - "data": results, - }) -} - -func listUserRepositories(c *context.APIContext, username string) { - user, err := models.GetUserByName(username) - if err != nil { - c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err) - return - } - - // Only list public repositories if user requests someone else's repository list, - // or an organization isn't a member of. - var ownRepos []*models.Repository - if user.IsOrganization() { - ownRepos, _, err = user.GetUserRepositories(c.User.ID, 1, user.NumRepos) - } else { - ownRepos, err = models.GetUserRepositories(&models.UserRepoOptions{ - UserID: user.ID, - Private: c.User.ID == user.ID, - Page: 1, - PageSize: user.NumRepos, - }) - } - if err != nil { - c.Error(500, "GetUserRepositories", err) - return - } - - if c.User.ID != user.ID { - repos := make([]*api.Repository, len(ownRepos)) - for i := range ownRepos { - repos[i] = ownRepos[i].APIFormat(&api.Permission{true, true, true}) - } - c.JSON(200, &repos) - return - } - - accessibleRepos, err := user.GetRepositoryAccesses() - if err != nil { - c.Error(500, "GetRepositoryAccesses", err) - return - } - - numOwnRepos := len(ownRepos) - repos := make([]*api.Repository, numOwnRepos+len(accessibleRepos)) - for i := range ownRepos { - repos[i] = ownRepos[i].APIFormat(&api.Permission{true, true, true}) - } - - i := numOwnRepos - for repo, access := range accessibleRepos { - repos[i] = repo.APIFormat(&api.Permission{ - Admin: access >= models.ACCESS_MODE_ADMIN, - Push: access >= models.ACCESS_MODE_WRITE, - Pull: true, - }) - i++ - } - - c.JSON(200, &repos) -} - -func ListMyRepos(c *context.APIContext) { - listUserRepositories(c, c.User.Name) -} - -func ListUserRepositories(c *context.APIContext) { - listUserRepositories(c, c.Params(":username")) -} - -func ListOrgRepositories(c *context.APIContext) { - listUserRepositories(c, c.Params(":org")) -} - -func CreateUserRepo(c *context.APIContext, owner *models.User, opt api.CreateRepoOption) { - repo, err := models.CreateRepository(c.User, owner, models.CreateRepoOptions{ - Name: opt.Name, - Description: opt.Description, - Gitignores: opt.Gitignores, - License: opt.License, - Readme: opt.Readme, - IsPrivate: opt.Private, - AutoInit: opt.AutoInit, - }) - if err != nil { - if models.IsErrRepoAlreadyExist(err) || - models.IsErrNameReserved(err) || - models.IsErrNamePatternNotAllowed(err) { - c.Error(422, "", err) - } else { - if repo != nil { - if err = models.DeleteRepository(c.User.ID, repo.ID); err != nil { - log.Error(2, "DeleteRepository: %v", err) - } - } - c.Error(500, "CreateRepository", err) - } - return - } - - c.JSON(201, repo.APIFormat(&api.Permission{true, true, true})) -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#create -func Create(c *context.APIContext, opt api.CreateRepoOption) { - // Shouldn't reach this condition, but just in case. - if c.User.IsOrganization() { - c.Error(422, "", "not allowed creating repository for organization") - return - } - CreateUserRepo(c, c.User, opt) -} - -func CreateOrgRepo(c *context.APIContext, opt api.CreateRepoOption) { - org, err := models.GetOrgByName(c.Params(":org")) - if err != nil { - if errors.IsUserNotExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "GetOrgByName", err) - } - return - } - - if !org.IsOwnedBy(c.User.ID) { - c.Error(403, "", "Given user is not owner of organization.") - return - } - CreateUserRepo(c, org, opt) -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#migrate -func Migrate(c *context.APIContext, f form.MigrateRepo) { - ctxUser := c.User - // Not equal means context user is an organization, - // or is another user/organization if current user is admin. - if f.Uid != ctxUser.ID { - org, err := models.GetUserByID(f.Uid) - if err != nil { - if errors.IsUserNotExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "GetUserByID", err) - } - return - } else if !org.IsOrganization() && !c.User.IsAdmin { - c.Error(403, "", "Given user is not an organization") - return - } - ctxUser = org - } - - if c.HasError() { - c.Error(422, "", c.GetErrMsg()) - return - } - - if ctxUser.IsOrganization() && !c.User.IsAdmin { - // Check ownership of organization. - if !ctxUser.IsOwnedBy(c.User.ID) { - c.Error(403, "", "Given user is not owner of organization") - return - } - } - - remoteAddr, err := f.ParseRemoteAddr(c.User) - if err != nil { - if models.IsErrInvalidCloneAddr(err) { - addrErr := err.(models.ErrInvalidCloneAddr) - switch { - case addrErr.IsURLError: - c.Error(422, "", err) - case addrErr.IsPermissionDenied: - c.Error(422, "", "You are not allowed to import local repositories") - case addrErr.IsInvalidPath: - c.Error(422, "", "Invalid local path, it does not exist or not a directory") - default: - c.Error(500, "ParseRemoteAddr", "Unknown error type (ErrInvalidCloneAddr): "+err.Error()) - } - } else { - c.Error(500, "ParseRemoteAddr", err) - } - return - } - - repo, err := models.MigrateRepository(c.User, ctxUser, models.MigrateRepoOptions{ - Name: f.RepoName, - Description: f.Description, - IsPrivate: f.Private || setting.Repository.ForcePrivate, - IsMirror: f.Mirror, - RemoteAddr: remoteAddr, - }) - if err != nil { - if repo != nil { - if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil { - log.Error(2, "DeleteRepository: %v", errDelete) - } - } - - if errors.IsReachLimitOfRepo(err) { - c.Error(422, "", err) - } else { - c.Error(500, "MigrateRepository", models.HandleMirrorCredentials(err.Error(), true)) - } - return - } - - log.Trace("Repository migrated: %s/%s", ctxUser.Name, f.RepoName) - c.JSON(201, repo.APIFormat(&api.Permission{true, true, true})) -} - -func parseOwnerAndRepo(c *context.APIContext) (*models.User, *models.Repository) { - owner, err := models.GetUserByName(c.Params(":username")) - if err != nil { - if errors.IsUserNotExist(err) { - c.Error(422, "", err) - } else { - c.Error(500, "GetUserByName", err) - } - return nil, nil - } - - repo, err := models.GetRepositoryByName(owner.ID, c.Params(":reponame")) - if err != nil { - if errors.IsRepoNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetRepositoryByName", err) - } - return nil, nil - } - - return owner, repo -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#get -func Get(c *context.APIContext) { - _, repo := parseOwnerAndRepo(c) - if c.Written() { - return - } - - c.JSON(200, repo.APIFormat(&api.Permission{ - Admin: c.Repo.IsAdmin(), - Push: c.Repo.IsWriter(), - Pull: true, - })) -} - -// https://github.com/gogits/go-gogs-client/wiki/Repositories#delete -func Delete(c *context.APIContext) { - owner, repo := parseOwnerAndRepo(c) - if c.Written() { - return - } - - if owner.IsOrganization() && !owner.IsOwnedBy(c.User.ID) { - c.Error(403, "", "Given user is not owner of organization.") - return - } - - if err := models.DeleteRepository(owner.ID, repo.ID); err != nil { - c.Error(500, "DeleteRepository", err) - return - } - - log.Trace("Repository deleted: %s/%s", owner.Name, repo.Name) - c.Status(204) -} - -func ListForks(c *context.APIContext) { - forks, err := c.Repo.Repository.GetForks() - if err != nil { - c.Error(500, "GetForks", err) - return - } - - apiForks := make([]*api.Repository, len(forks)) - for i := range forks { - if err := forks[i].GetOwner(); err != nil { - c.Error(500, "GetOwner", err) - return - } - apiForks[i] = forks[i].APIFormat(&api.Permission{ - Admin: c.User.IsAdminOfRepo(forks[i]), - Push: c.User.IsWriterOfRepo(forks[i]), - Pull: true, - }) - } - - c.JSON(200, &apiForks) -} - -func MirrorSync(c *context.APIContext) { - _, repo := parseOwnerAndRepo(c) - if c.Written() { - return - } else if !repo.IsMirror { - c.Status(404) - return - } - - go models.MirrorQueue.Add(repo.ID) - c.Status(202) -} diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go deleted file mode 100644 index bda1e23f..00000000 --- a/routers/api/v1/user/app.go +++ /dev/null @@ -1,40 +0,0 @@ -// 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 user - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" -) - -// https://github.com/gogits/go-gogs-client/wiki/Users#list-access-tokens-for-a-user -func ListAccessTokens(c *context.APIContext) { - tokens, err := models.ListAccessTokens(c.User.ID) - if err != nil { - c.Error(500, "ListAccessTokens", err) - return - } - - apiTokens := make([]*api.AccessToken, len(tokens)) - for i := range tokens { - apiTokens[i] = &api.AccessToken{tokens[i].Name, tokens[i].Sha1} - } - c.JSON(200, &apiTokens) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users#create-a-access-token -func CreateAccessToken(c *context.APIContext, form api.CreateAccessTokenOption) { - t := &models.AccessToken{ - UID: c.User.ID, - Name: form.Name, - } - if err := models.NewAccessToken(t); err != nil { - c.Error(500, "NewAccessToken", err) - return - } - c.JSON(201, &api.AccessToken{t.Name, t.Sha1}) -} diff --git a/routers/api/v1/user/email.go b/routers/api/v1/user/email.go deleted file mode 100644 index 7c527a1a..00000000 --- a/routers/api/v1/user/email.go +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2015 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 user - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/routers/api/v1/convert" -) - -// https://github.com/gogits/go-gogs-client/wiki/Users-Emails#list-email-addresses-for-a-user -func ListEmails(c *context.APIContext) { - emails, err := models.GetEmailAddresses(c.User.ID) - if err != nil { - c.Error(500, "GetEmailAddresses", err) - return - } - apiEmails := make([]*api.Email, len(emails)) - for i := range emails { - apiEmails[i] = convert.ToEmail(emails[i]) - } - c.JSON(200, &apiEmails) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Emails#add-email-addresses -func AddEmail(c *context.APIContext, form api.CreateEmailOption) { - if len(form.Emails) == 0 { - c.Status(422) - return - } - - emails := make([]*models.EmailAddress, len(form.Emails)) - for i := range form.Emails { - emails[i] = &models.EmailAddress{ - UID: c.User.ID, - Email: form.Emails[i], - IsActivated: !setting.Service.RegisterEmailConfirm, - } - } - - if err := models.AddEmailAddresses(emails); err != nil { - if models.IsErrEmailAlreadyUsed(err) { - c.Error(422, "", "Email address has been used: "+err.(models.ErrEmailAlreadyUsed).Email) - } else { - c.Error(500, "AddEmailAddresses", err) - } - return - } - - apiEmails := make([]*api.Email, len(emails)) - for i := range emails { - apiEmails[i] = convert.ToEmail(emails[i]) - } - c.JSON(201, &apiEmails) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Emails#delete-email-addresses -func DeleteEmail(c *context.APIContext, form api.CreateEmailOption) { - if len(form.Emails) == 0 { - c.Status(204) - return - } - - emails := make([]*models.EmailAddress, len(form.Emails)) - for i := range form.Emails { - emails[i] = &models.EmailAddress{ - UID: c.User.ID, - Email: form.Emails[i], - } - } - - if err := models.DeleteEmailAddresses(emails); err != nil { - c.Error(500, "DeleteEmailAddresses", err) - return - } - c.Status(204) -} diff --git a/routers/api/v1/user/follower.go b/routers/api/v1/user/follower.go deleted file mode 100644 index 6bbd4c7e..00000000 --- a/routers/api/v1/user/follower.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2015 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 user - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" -) - -func responseApiUsers(c *context.APIContext, users []*models.User) { - apiUsers := make([]*api.User, len(users)) - for i := range users { - apiUsers[i] = users[i].APIFormat() - } - c.JSON(200, &apiUsers) -} - -func listUserFollowers(c *context.APIContext, u *models.User) { - users, err := u.GetFollowers(c.QueryInt("page")) - if err != nil { - c.Error(500, "GetUserFollowers", err) - return - } - responseApiUsers(c, users) -} - -func ListMyFollowers(c *context.APIContext) { - listUserFollowers(c, c.User) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Followers#list-followers-of-a-user -func ListFollowers(c *context.APIContext) { - u := GetUserByParams(c) - if c.Written() { - return - } - listUserFollowers(c, u) -} - -func listUserFollowing(c *context.APIContext, u *models.User) { - users, err := u.GetFollowing(c.QueryInt("page")) - if err != nil { - c.Error(500, "GetFollowing", err) - return - } - responseApiUsers(c, users) -} - -func ListMyFollowing(c *context.APIContext) { - listUserFollowing(c, c.User) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Followers#list-users-followed-by-another-user -func ListFollowing(c *context.APIContext) { - u := GetUserByParams(c) - if c.Written() { - return - } - listUserFollowing(c, u) -} - -func checkUserFollowing(c *context.APIContext, u *models.User, followID int64) { - if u.IsFollowing(followID) { - c.Status(204) - } else { - c.Status(404) - } -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Followers#check-if-you-are-following-a-user -func CheckMyFollowing(c *context.APIContext) { - target := GetUserByParams(c) - if c.Written() { - return - } - checkUserFollowing(c, c.User, target.ID) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Followers#check-if-one-user-follows-another -func CheckFollowing(c *context.APIContext) { - u := GetUserByParams(c) - if c.Written() { - return - } - target := GetUserByParamsName(c, ":target") - if c.Written() { - return - } - checkUserFollowing(c, u, target.ID) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Followers#follow-a-user -func Follow(c *context.APIContext) { - target := GetUserByParams(c) - if c.Written() { - return - } - if err := models.FollowUser(c.User.ID, target.ID); err != nil { - c.Error(500, "FollowUser", err) - return - } - c.Status(204) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Followers#unfollow-a-user -func Unfollow(c *context.APIContext) { - target := GetUserByParams(c) - if c.Written() { - return - } - if err := models.UnfollowUser(c.User.ID, target.ID); err != nil { - c.Error(500, "UnfollowUser", err) - return - } - c.Status(204) -} diff --git a/routers/api/v1/user/key.go b/routers/api/v1/user/key.go deleted file mode 100644 index f0c833f5..00000000 --- a/routers/api/v1/user/key.go +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2015 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 user - -import ( - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/routers/api/v1/convert" - "github.com/gogits/gogs/routers/api/v1/repo" -) - -func GetUserByParamsName(c *context.APIContext, name string) *models.User { - user, err := models.GetUserByName(c.Params(name)) - if err != nil { - if errors.IsUserNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetUserByName", err) - } - return nil - } - return user -} - -// GetUserByParams returns user whose name is presented in URL paramenter. -func GetUserByParams(c *context.APIContext) *models.User { - return GetUserByParamsName(c, ":username") -} - -func composePublicKeysAPILink() string { - return setting.AppURL + "api/v1/user/keys/" -} - -func listPublicKeys(c *context.APIContext, uid int64) { - keys, err := models.ListPublicKeys(uid) - if err != nil { - c.Error(500, "ListPublicKeys", err) - return - } - - apiLink := composePublicKeysAPILink() - apiKeys := make([]*api.PublicKey, len(keys)) - for i := range keys { - apiKeys[i] = convert.ToPublicKey(apiLink, keys[i]) - } - - c.JSON(200, &apiKeys) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#list-your-public-keys -func ListMyPublicKeys(c *context.APIContext) { - listPublicKeys(c, c.User.ID) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#list-public-keys-for-a-user -func ListPublicKeys(c *context.APIContext) { - user := GetUserByParams(c) - if c.Written() { - return - } - listPublicKeys(c, user.ID) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#get-a-single-public-key -func GetPublicKey(c *context.APIContext) { - key, err := models.GetPublicKeyByID(c.ParamsInt64(":id")) - if err != nil { - if models.IsErrKeyNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetPublicKeyByID", err) - } - return - } - - apiLink := composePublicKeysAPILink() - c.JSON(200, convert.ToPublicKey(apiLink, key)) -} - -// CreateUserPublicKey creates new public key to given user by ID. -func CreateUserPublicKey(c *context.APIContext, form api.CreateKeyOption, uid int64) { - content, err := models.CheckPublicKeyString(form.Key) - if err != nil { - repo.HandleCheckKeyStringError(c, err) - return - } - - key, err := models.AddPublicKey(uid, form.Title, content) - if err != nil { - repo.HandleAddKeyError(c, err) - return - } - apiLink := composePublicKeysAPILink() - c.JSON(201, convert.ToPublicKey(apiLink, key)) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#create-a-public-key -func CreatePublicKey(c *context.APIContext, form api.CreateKeyOption) { - CreateUserPublicKey(c, form, c.User.ID) -} - -// https://github.com/gogits/go-gogs-client/wiki/Users-Public-Keys#delete-a-public-key -func DeletePublicKey(c *context.APIContext) { - if err := models.DeletePublicKey(c.User, c.ParamsInt64(":id")); err != nil { - if models.IsErrKeyAccessDenied(err) { - c.Error(403, "", "You do not have access to this key") - } else { - c.Error(500, "DeletePublicKey", err) - } - return - } - - c.Status(204) -} diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go deleted file mode 100644 index dbf727de..00000000 --- a/routers/api/v1/user/user.go +++ /dev/null @@ -1,75 +0,0 @@ -// 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 user - -import ( - "github.com/Unknwon/com" - - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" -) - -func Search(c *context.APIContext) { - opts := &models.SearchUserOptions{ - Keyword: c.Query("q"), - Type: models.USER_TYPE_INDIVIDUAL, - PageSize: com.StrTo(c.Query("limit")).MustInt(), - } - if opts.PageSize == 0 { - opts.PageSize = 10 - } - - users, _, err := models.SearchUserByName(opts) - if err != nil { - c.JSON(500, map[string]interface{}{ - "ok": false, - "error": err.Error(), - }) - return - } - - results := make([]*api.User, len(users)) - for i := range users { - results[i] = &api.User{ - ID: users[i].ID, - UserName: users[i].Name, - AvatarUrl: users[i].AvatarLink(), - FullName: users[i].FullName, - } - if c.IsLogged { - results[i].Email = users[i].Email - } - } - - c.JSON(200, map[string]interface{}{ - "ok": true, - "data": results, - }) -} - -func GetInfo(c *context.APIContext) { - u, err := models.GetUserByName(c.Params(":username")) - if err != nil { - if errors.IsUserNotExist(err) { - c.Status(404) - } else { - c.Error(500, "GetUserByName", err) - } - return - } - - // Hide user e-mail when API caller isn't signed in. - if !c.IsLogged { - u.Email = "" - } - c.JSON(200, u.APIFormat()) -} - -func GetAuthenticatedUser(c *context.APIContext) { - c.JSON(200, c.User.APIFormat()) -} diff --git a/routers/dev/template.go b/routers/dev/template.go deleted file mode 100644 index 00afa5c4..00000000 --- a/routers/dev/template.go +++ /dev/null @@ -1,24 +0,0 @@ -// 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 dev - -import ( - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" -) - -func TemplatePreview(c *context.Context) { - c.Data["User"] = models.User{Name: "Unknown"} - c.Data["AppName"] = setting.AppName - c.Data["AppVer"] = setting.AppVer - c.Data["AppURL"] = setting.AppURL - c.Data["Code"] = "2014031910370000009fff6782aadb2162b4a997acb69d4400888e0b9274657374" - c.Data["ActiveCodeLives"] = setting.Service.ActiveCodeLives / 60 - c.Data["ResetPwdCodeLives"] = setting.Service.ResetPwdCodeLives / 60 - c.Data["CurDbValue"] = "" - - c.HTML(200, (c.Params("*"))) -} diff --git a/routers/home.go b/routers/home.go deleted file mode 100644 index bb43dc58..00000000 --- a/routers/home.go +++ /dev/null @@ -1,163 +0,0 @@ -// 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 routers - -import ( - "github.com/Unknwon/paginater" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/routers/user" -) - -const ( - HOME = "home" - EXPLORE_REPOS = "explore/repos" - EXPLORE_USERS = "explore/users" - EXPLORE_ORGANIZATIONS = "explore/organizations" -) - -func Home(c *context.Context) { - if c.IsLogged { - if !c.User.IsActive && setting.Service.RegisterEmailConfirm { - c.Data["Title"] = c.Tr("auth.active_your_account") - c.HTML(200, user.ACTIVATE) - } else { - user.Dashboard(c) - } - return - } - - // Check auto-login. - uname := c.GetCookie(setting.CookieUserName) - if len(uname) != 0 { - c.Redirect(setting.AppSubURL + "/user/login") - return - } - - c.Data["PageIsHome"] = true - c.HTML(200, HOME) -} - -func ExploreRepos(c *context.Context) { - c.Data["Title"] = c.Tr("explore") - c.Data["PageIsExplore"] = true - c.Data["PageIsExploreRepositories"] = true - - page := c.QueryInt("page") - if page <= 0 { - page = 1 - } - - keyword := c.Query("q") - repos, count, err := models.SearchRepositoryByName(&models.SearchRepoOptions{ - Keyword: keyword, - UserID: c.UserID(), - OrderBy: "updated_unix DESC", - Page: page, - PageSize: setting.UI.ExplorePagingNum, - }) - 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.ExplorePagingNum, page, 5) - - if err = models.RepositoryList(repos).LoadAttributes(); err != nil { - c.Handle(500, "LoadAttributes", err) - return - } - c.Data["Repos"] = repos - - c.HTML(200, EXPLORE_REPOS) -} - -type UserSearchOptions struct { - Type models.UserType - Counter func() int64 - Ranger func(int, int) ([]*models.User, error) - PageSize int - OrderBy string - TplName string -} - -func RenderUserSearch(c *context.Context, opts *UserSearchOptions) { - page := c.QueryInt("page") - if page <= 1 { - page = 1 - } - - var ( - users []*models.User - count int64 - err error - ) - - keyword := c.Query("q") - if len(keyword) == 0 { - users, err = opts.Ranger(page, opts.PageSize) - if err != nil { - c.Handle(500, "opts.Ranger", err) - return - } - count = opts.Counter() - } else { - users, count, err = models.SearchUserByName(&models.SearchUserOptions{ - Keyword: keyword, - Type: opts.Type, - OrderBy: opts.OrderBy, - Page: page, - PageSize: opts.PageSize, - }) - if err != nil { - c.Handle(500, "SearchUserByName", err) - return - } - } - c.Data["Keyword"] = keyword - c.Data["Total"] = count - c.Data["Page"] = paginater.New(int(count), opts.PageSize, page, 5) - c.Data["Users"] = users - - c.HTML(200, opts.TplName) -} - -func ExploreUsers(c *context.Context) { - c.Data["Title"] = c.Tr("explore") - c.Data["PageIsExplore"] = true - c.Data["PageIsExploreUsers"] = true - - RenderUserSearch(c, &UserSearchOptions{ - Type: models.USER_TYPE_INDIVIDUAL, - Counter: models.CountUsers, - Ranger: models.Users, - PageSize: setting.UI.ExplorePagingNum, - OrderBy: "updated_unix DESC", - TplName: EXPLORE_USERS, - }) -} - -func ExploreOrganizations(c *context.Context) { - c.Data["Title"] = c.Tr("explore") - c.Data["PageIsExplore"] = true - c.Data["PageIsExploreOrganizations"] = true - - RenderUserSearch(c, &UserSearchOptions{ - Type: models.USER_TYPE_ORGANIZATION, - Counter: models.CountOrganizations, - Ranger: models.Organizations, - PageSize: setting.UI.ExplorePagingNum, - OrderBy: "updated_unix DESC", - TplName: EXPLORE_ORGANIZATIONS, - }) -} - -func NotFound(c *context.Context) { - c.Data["Title"] = "Page Not Found" - c.NotFound() -} diff --git a/routers/install.go b/routers/install.go deleted file mode 100644 index 3b48d8d3..00000000 --- a/routers/install.go +++ /dev/null @@ -1,392 +0,0 @@ -// 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 routers - -import ( - "net/mail" - "os" - "os/exec" - "path/filepath" - "strings" - - "github.com/Unknwon/com" - "github.com/go-xorm/xorm" - log "gopkg.in/clog.v1" - "gopkg.in/ini.v1" - "gopkg.in/macaron.v1" - - "github.com/gogits/git-module" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/cron" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/mailer" - "github.com/gogits/gogs/pkg/markup" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/pkg/ssh" - "github.com/gogits/gogs/pkg/template/highlight" - "github.com/gogits/gogs/pkg/tool" - "github.com/gogits/gogs/pkg/user" -) - -const ( - INSTALL = "install" -) - -func checkRunMode() { - if setting.ProdMode { - macaron.Env = macaron.PROD - macaron.ColorLog = false - } else { - git.Debug = true - } - log.Info("Run Mode: %s", strings.Title(macaron.Env)) -} - -func NewServices() { - setting.NewServices() - mailer.NewContext() -} - -// GlobalInit is for global configuration reload-able. -func GlobalInit() { - setting.NewContext() - log.Trace("Custom path: %s", setting.CustomPath) - log.Trace("Log path: %s", setting.LogRootPath) - models.LoadConfigs() - NewServices() - - if setting.InstallLock { - highlight.NewContext() - markup.NewSanitizer() - if err := models.NewEngine(); err != nil { - log.Fatal(2, "Fail to initialize ORM engine: %v", err) - } - models.HasEngine = true - - models.LoadRepoConfig() - models.NewRepoContext() - - // Booting long running goroutines. - cron.NewContext() - models.InitSyncMirrors() - models.InitDeliverHooks() - models.InitTestPullRequests() - } - if models.EnableSQLite3 { - log.Info("SQLite3 Supported") - } - if setting.SupportMiniWinService { - log.Info("Builtin Windows Service Supported") - } - checkRunMode() - - if setting.InstallLock && setting.SSH.StartBuiltinServer { - ssh.Listen(setting.SSH.ListenHost, setting.SSH.ListenPort, setting.SSH.ServerCiphers) - log.Info("SSH server started on %s:%v", setting.SSH.ListenHost, setting.SSH.ListenPort) - log.Trace("SSH server cipher list: %v", setting.SSH.ServerCiphers) - } -} - -func InstallInit(c *context.Context) { - if setting.InstallLock { - c.NotFound() - return - } - - c.Title("install.install") - c.PageIs("Install") - - dbOpts := []string{"MySQL", "PostgreSQL", "MSSQL"} - if models.EnableSQLite3 { - dbOpts = append(dbOpts, "SQLite3") - } - c.Data["DbOptions"] = dbOpts -} - -func Install(c *context.Context) { - f := form.Install{} - - // Database settings - f.DbHost = models.DbCfg.Host - f.DbUser = models.DbCfg.User - f.DbName = models.DbCfg.Name - f.DbPath = models.DbCfg.Path - - c.Data["CurDbOption"] = "MySQL" - switch models.DbCfg.Type { - case "postgres": - c.Data["CurDbOption"] = "PostgreSQL" - case "mssql": - c.Data["CurDbOption"] = "MSSQL" - case "sqlite3": - if models.EnableSQLite3 { - c.Data["CurDbOption"] = "SQLite3" - } - } - - // Application general settings - f.AppName = setting.AppName - f.RepoRootPath = setting.RepoRootPath - - // Note(unknwon): it's hard for Windows users change a running user, - // so just use current one if config says default. - if setting.IsWindows && setting.RunUser == "git" { - f.RunUser = user.CurrentUsername() - } else { - f.RunUser = setting.RunUser - } - - f.Domain = setting.Domain - f.SSHPort = setting.SSH.Port - f.UseBuiltinSSHServer = setting.SSH.StartBuiltinServer - f.HTTPPort = setting.HTTPPort - f.AppUrl = setting.AppURL - f.LogRootPath = setting.LogRootPath - - // E-mail service settings - if setting.MailService != nil { - f.SMTPHost = setting.MailService.Host - f.SMTPFrom = setting.MailService.From - f.SMTPUser = setting.MailService.User - } - f.RegisterConfirm = setting.Service.RegisterEmailConfirm - f.MailNotify = setting.Service.EnableNotifyMail - - // Server and other services settings - f.OfflineMode = setting.OfflineMode - f.DisableGravatar = setting.DisableGravatar - f.EnableFederatedAvatar = setting.EnableFederatedAvatar - f.DisableRegistration = setting.Service.DisableRegistration - f.EnableCaptcha = setting.Service.EnableCaptcha - f.RequireSignInView = setting.Service.RequireSignInView - - form.Assign(f, c.Data) - c.Success(INSTALL) -} - -func InstallPost(c *context.Context, f form.Install) { - c.Data["CurDbOption"] = f.DbType - - if c.HasError() { - if c.HasValue("Err_SMTPEmail") { - c.FormErr("SMTP") - } - if c.HasValue("Err_AdminName") || - c.HasValue("Err_AdminPasswd") || - c.HasValue("Err_AdminEmail") { - c.FormErr("Admin") - } - - c.Success(INSTALL) - return - } - - if _, err := exec.LookPath("git"); err != nil { - c.RenderWithErr(c.Tr("install.test_git_failed", err), INSTALL, &f) - return - } - - // Pass basic check, now test configuration. - // Test database setting. - dbTypes := map[string]string{"MySQL": "mysql", "PostgreSQL": "postgres", "MSSQL": "mssql", "SQLite3": "sqlite3", "TiDB": "tidb"} - models.DbCfg.Type = dbTypes[f.DbType] - models.DbCfg.Host = f.DbHost - models.DbCfg.User = f.DbUser - models.DbCfg.Passwd = f.DbPasswd - models.DbCfg.Name = f.DbName - models.DbCfg.SSLMode = f.SSLMode - models.DbCfg.Path = f.DbPath - - if models.DbCfg.Type == "sqlite3" && len(models.DbCfg.Path) == 0 { - c.FormErr("DbPath") - c.RenderWithErr(c.Tr("install.err_empty_db_path"), INSTALL, &f) - return - } - - // Set test engine. - var x *xorm.Engine - if err := models.NewTestEngine(x); err != nil { - if strings.Contains(err.Error(), `Unknown database type: sqlite3`) { - c.FormErr("DbType") - c.RenderWithErr(c.Tr("install.sqlite3_not_available", "https://gogs.io/docs/installation/install_from_binary.html"), INSTALL, &f) - } else { - c.FormErr("DbSetting") - c.RenderWithErr(c.Tr("install.invalid_db_setting", err), INSTALL, &f) - } - return - } - - // Test repository root path. - f.RepoRootPath = strings.Replace(f.RepoRootPath, "\\", "/", -1) - if err := os.MkdirAll(f.RepoRootPath, os.ModePerm); err != nil { - c.FormErr("RepoRootPath") - c.RenderWithErr(c.Tr("install.invalid_repo_path", err), INSTALL, &f) - return - } - - // Test log root path. - f.LogRootPath = strings.Replace(f.LogRootPath, "\\", "/", -1) - if err := os.MkdirAll(f.LogRootPath, os.ModePerm); err != nil { - c.FormErr("LogRootPath") - c.RenderWithErr(c.Tr("install.invalid_log_root_path", err), INSTALL, &f) - return - } - - currentUser, match := setting.IsRunUserMatchCurrentUser(f.RunUser) - if !match { - c.FormErr("RunUser") - c.RenderWithErr(c.Tr("install.run_user_not_match", f.RunUser, currentUser), INSTALL, &f) - return - } - - // Check host address and port - if len(f.SMTPHost) > 0 && !strings.Contains(f.SMTPHost, ":") { - c.FormErr("SMTP", "SMTPHost") - c.RenderWithErr(c.Tr("install.smtp_host_missing_port"), INSTALL, &f) - return - } - - // Make sure FROM field is valid - if len(f.SMTPFrom) > 0 { - _, err := mail.ParseAddress(f.SMTPFrom) - if err != nil { - c.FormErr("SMTP", "SMTPFrom") - c.RenderWithErr(c.Tr("install.invalid_smtp_from", err), INSTALL, &f) - return - } - } - - // Check logic loophole between disable self-registration and no admin account. - if f.DisableRegistration && len(f.AdminName) == 0 { - c.FormErr("Services", "Admin") - c.RenderWithErr(c.Tr("install.no_admin_and_disable_registration"), INSTALL, f) - return - } - - // Check admin password. - if len(f.AdminName) > 0 && len(f.AdminPasswd) == 0 { - c.FormErr("Admin", "AdminPasswd") - c.RenderWithErr(c.Tr("install.err_empty_admin_password"), INSTALL, f) - return - } - if f.AdminPasswd != f.AdminConfirmPasswd { - c.FormErr("Admin", "AdminPasswd") - c.RenderWithErr(c.Tr("form.password_not_match"), INSTALL, f) - return - } - - if f.AppUrl[len(f.AppUrl)-1] != '/' { - f.AppUrl += "/" - } - - // Save settings. - cfg := ini.Empty() - if com.IsFile(setting.CustomConf) { - // Keeps custom settings if there is already something. - if err := cfg.Append(setting.CustomConf); err != nil { - log.Error(2, "Fail to load custom conf '%s': %v", setting.CustomConf, err) - } - } - cfg.Section("database").Key("DB_TYPE").SetValue(models.DbCfg.Type) - cfg.Section("database").Key("HOST").SetValue(models.DbCfg.Host) - cfg.Section("database").Key("NAME").SetValue(models.DbCfg.Name) - cfg.Section("database").Key("USER").SetValue(models.DbCfg.User) - cfg.Section("database").Key("PASSWD").SetValue(models.DbCfg.Passwd) - cfg.Section("database").Key("SSL_MODE").SetValue(models.DbCfg.SSLMode) - cfg.Section("database").Key("PATH").SetValue(models.DbCfg.Path) - - cfg.Section("").Key("APP_NAME").SetValue(f.AppName) - cfg.Section("repository").Key("ROOT").SetValue(f.RepoRootPath) - cfg.Section("").Key("RUN_USER").SetValue(f.RunUser) - cfg.Section("server").Key("DOMAIN").SetValue(f.Domain) - cfg.Section("server").Key("HTTP_PORT").SetValue(f.HTTPPort) - cfg.Section("server").Key("ROOT_URL").SetValue(f.AppUrl) - - if f.SSHPort == 0 { - cfg.Section("server").Key("DISABLE_SSH").SetValue("true") - } else { - cfg.Section("server").Key("DISABLE_SSH").SetValue("false") - cfg.Section("server").Key("SSH_PORT").SetValue(com.ToStr(f.SSHPort)) - cfg.Section("server").Key("START_SSH_SERVER").SetValue(com.ToStr(f.UseBuiltinSSHServer)) - } - - if len(strings.TrimSpace(f.SMTPHost)) > 0 { - cfg.Section("mailer").Key("ENABLED").SetValue("true") - cfg.Section("mailer").Key("HOST").SetValue(f.SMTPHost) - cfg.Section("mailer").Key("FROM").SetValue(f.SMTPFrom) - cfg.Section("mailer").Key("USER").SetValue(f.SMTPUser) - cfg.Section("mailer").Key("PASSWD").SetValue(f.SMTPPasswd) - } else { - cfg.Section("mailer").Key("ENABLED").SetValue("false") - } - cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").SetValue(com.ToStr(f.RegisterConfirm)) - cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").SetValue(com.ToStr(f.MailNotify)) - - cfg.Section("server").Key("OFFLINE_MODE").SetValue(com.ToStr(f.OfflineMode)) - cfg.Section("picture").Key("DISABLE_GRAVATAR").SetValue(com.ToStr(f.DisableGravatar)) - cfg.Section("picture").Key("ENABLE_FEDERATED_AVATAR").SetValue(com.ToStr(f.EnableFederatedAvatar)) - cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(com.ToStr(f.DisableRegistration)) - cfg.Section("service").Key("ENABLE_CAPTCHA").SetValue(com.ToStr(f.EnableCaptcha)) - cfg.Section("service").Key("REQUIRE_SIGNIN_VIEW").SetValue(com.ToStr(f.RequireSignInView)) - - cfg.Section("").Key("RUN_MODE").SetValue("prod") - - cfg.Section("session").Key("PROVIDER").SetValue("file") - - mode := "file" - if f.EnableConsoleMode { - mode = "console, file" - } - cfg.Section("log").Key("MODE").SetValue(mode) - cfg.Section("log").Key("LEVEL").SetValue("Info") - cfg.Section("log").Key("ROOT_PATH").SetValue(f.LogRootPath) - - cfg.Section("security").Key("INSTALL_LOCK").SetValue("true") - secretKey, err := tool.RandomString(15) - if err != nil { - c.RenderWithErr(c.Tr("install.secret_key_failed", err), INSTALL, &f) - return - } - cfg.Section("security").Key("SECRET_KEY").SetValue(secretKey) - - os.MkdirAll(filepath.Dir(setting.CustomConf), os.ModePerm) - if err := cfg.SaveTo(setting.CustomConf); err != nil { - c.RenderWithErr(c.Tr("install.save_config_failed", err), INSTALL, &f) - return - } - - GlobalInit() - - // Create admin account - if len(f.AdminName) > 0 { - u := &models.User{ - Name: f.AdminName, - Email: f.AdminEmail, - Passwd: f.AdminPasswd, - IsAdmin: true, - IsActive: true, - } - if err := models.CreateUser(u); err != nil { - if !models.IsErrUserAlreadyExist(err) { - setting.InstallLock = false - c.FormErr("AdminName", "AdminEmail") - c.RenderWithErr(c.Tr("install.invalid_admin_setting", err), INSTALL, &f) - return - } - log.Info("Admin account already exist") - u, _ = models.GetUserByName(u.Name) - } - - // Auto-login for admin - c.Session.Set("uid", u.ID) - c.Session.Set("uname", u.Name) - } - - log.Info("First-time run install finished!") - c.Flash.Success(c.Tr("install.install_success")) - c.Redirect(f.AppUrl + "user/login") -} diff --git a/routers/org/members.go b/routers/org/members.go deleted file mode 100644 index b529748c..00000000 --- a/routers/org/members.go +++ /dev/null @@ -1,123 +0,0 @@ -// 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 org - -import ( - "github.com/Unknwon/com" - log "gopkg.in/clog.v1" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" -) - -const ( - MEMBERS = "org/member/members" - MEMBER_INVITE = "org/member/invite" -) - -func Members(c *context.Context) { - org := c.Org.Organization - c.Data["Title"] = org.FullName - c.Data["PageIsOrgMembers"] = true - - if err := org.GetMembers(); err != nil { - c.Handle(500, "GetMembers", err) - return - } - c.Data["Members"] = org.Members - - c.HTML(200, MEMBERS) -} - -func MembersAction(c *context.Context) { - uid := com.StrTo(c.Query("uid")).MustInt64() - if uid == 0 { - c.Redirect(c.Org.OrgLink + "/members") - return - } - - org := c.Org.Organization - var err error - switch c.Params(":action") { - case "private": - if c.User.ID != uid && !c.Org.IsOwner { - c.Error(404) - return - } - err = models.ChangeOrgUserStatus(org.ID, uid, false) - case "public": - if c.User.ID != uid && !c.Org.IsOwner { - c.Error(404) - return - } - err = models.ChangeOrgUserStatus(org.ID, uid, true) - case "remove": - if !c.Org.IsOwner { - c.Error(404) - return - } - err = org.RemoveMember(uid) - if models.IsErrLastOrgOwner(err) { - c.Flash.Error(c.Tr("form.last_org_owner")) - c.Redirect(c.Org.OrgLink + "/members") - return - } - case "leave": - err = org.RemoveMember(c.User.ID) - if models.IsErrLastOrgOwner(err) { - c.Flash.Error(c.Tr("form.last_org_owner")) - c.Redirect(c.Org.OrgLink + "/members") - return - } - } - - if err != nil { - log.Error(4, "Action(%s): %v", c.Params(":action"), err) - c.JSON(200, map[string]interface{}{ - "ok": false, - "err": err.Error(), - }) - return - } - - if c.Params(":action") != "leave" { - c.Redirect(c.Org.OrgLink + "/members") - } else { - c.Redirect(setting.AppSubURL + "/") - } -} - -func Invitation(c *context.Context) { - org := c.Org.Organization - c.Data["Title"] = org.FullName - c.Data["PageIsOrgMembers"] = true - - if c.Req.Method == "POST" { - uname := c.Query("uname") - u, err := models.GetUserByName(uname) - if err != nil { - if errors.IsUserNotExist(err) { - c.Flash.Error(c.Tr("form.user_not_exist")) - c.Redirect(c.Org.OrgLink + "/invitations/new") - } else { - c.Handle(500, " GetUserByName", err) - } - return - } - - if err = org.AddMember(u.ID); err != nil { - c.Handle(500, " AddMember", err) - return - } - - log.Trace("New member added(%s): %s", org.Name, u.Name) - c.Redirect(c.Org.OrgLink + "/members") - return - } - - c.HTML(200, MEMBER_INVITE) -} diff --git a/routers/org/org.go b/routers/org/org.go deleted file mode 100644 index 775e9915..00000000 --- a/routers/org/org.go +++ /dev/null @@ -1,56 +0,0 @@ -// 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 org - -import ( - 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/setting" -) - -const ( - CREATE = "org/create" -) - -func Create(c *context.Context) { - c.Data["Title"] = c.Tr("new_org") - c.HTML(200, CREATE) -} - -func CreatePost(c *context.Context, f form.CreateOrg) { - c.Data["Title"] = c.Tr("new_org") - - if c.HasError() { - c.HTML(200, CREATE) - return - } - - org := &models.User{ - Name: f.OrgName, - IsActive: true, - Type: models.USER_TYPE_ORGANIZATION, - } - - if err := models.CreateOrganization(org, c.User); err != nil { - c.Data["Err_OrgName"] = true - switch { - case models.IsErrUserAlreadyExist(err): - c.RenderWithErr(c.Tr("form.org_name_been_taken"), CREATE, &f) - case models.IsErrNameReserved(err): - c.RenderWithErr(c.Tr("org.form.name_reserved", err.(models.ErrNameReserved).Name), CREATE, &f) - case models.IsErrNamePatternNotAllowed(err): - c.RenderWithErr(c.Tr("org.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), CREATE, &f) - default: - c.Handle(500, "CreateOrganization", err) - } - return - } - log.Trace("Organization created: %s", org.Name) - - c.Redirect(setting.AppSubURL + "/org/" + f.OrgName + "/dashboard") -} diff --git a/routers/org/setting.go b/routers/org/setting.go deleted file mode 100644 index 8e2e556f..00000000 --- a/routers/org/setting.go +++ /dev/null @@ -1,168 +0,0 @@ -// 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 org - -import ( - "strings" - - log "gopkg.in/clog.v1" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/routers/user" -) - -const ( - SETTINGS_OPTIONS = "org/settings/options" - SETTINGS_DELETE = "org/settings/delete" - SETTINGS_WEBHOOKS = "org/settings/webhooks" -) - -func Settings(c *context.Context) { - c.Data["Title"] = c.Tr("org.settings") - c.Data["PageIsSettingsOptions"] = true - c.HTML(200, SETTINGS_OPTIONS) -} - -func SettingsPost(c *context.Context, f form.UpdateOrgSetting) { - c.Data["Title"] = c.Tr("org.settings") - c.Data["PageIsSettingsOptions"] = true - - if c.HasError() { - c.HTML(200, SETTINGS_OPTIONS) - return - } - - org := c.Org.Organization - - // Check if organization name has been changed. - if org.LowerName != strings.ToLower(f.Name) { - isExist, err := models.IsUserExist(org.ID, f.Name) - if err != nil { - c.Handle(500, "IsUserExist", err) - return - } else if isExist { - c.Data["OrgName"] = true - c.RenderWithErr(c.Tr("form.username_been_taken"), SETTINGS_OPTIONS, &f) - return - } else if err = models.ChangeUserName(org, f.Name); err != nil { - c.Data["OrgName"] = true - switch { - case models.IsErrNameReserved(err): - c.RenderWithErr(c.Tr("user.form.name_reserved"), SETTINGS_OPTIONS, &f) - case models.IsErrNamePatternNotAllowed(err): - c.RenderWithErr(c.Tr("user.form.name_pattern_not_allowed"), SETTINGS_OPTIONS, &f) - default: - c.Handle(500, "ChangeUserName", err) - } - return - } - // reset c.org.OrgLink with new name - c.Org.OrgLink = setting.AppSubURL + "/org/" + f.Name - log.Trace("Organization name changed: %s -> %s", org.Name, f.Name) - } - // In case it's just a case change. - org.Name = f.Name - org.LowerName = strings.ToLower(f.Name) - - if c.User.IsAdmin { - org.MaxRepoCreation = f.MaxRepoCreation - } - - org.FullName = f.FullName - org.Description = f.Description - org.Website = f.Website - org.Location = f.Location - if err := models.UpdateUser(org); err != nil { - c.Handle(500, "UpdateUser", err) - return - } - log.Trace("Organization setting updated: %s", org.Name) - c.Flash.Success(c.Tr("org.settings.update_setting_success")) - c.Redirect(c.Org.OrgLink + "/settings") -} - -func SettingsAvatar(c *context.Context, f form.Avatar) { - f.Source = form.AVATAR_LOCAL - if err := user.UpdateAvatarSetting(c, f, c.Org.Organization); err != nil { - c.Flash.Error(err.Error()) - } else { - c.Flash.Success(c.Tr("org.settings.update_avatar_success")) - } - - c.Redirect(c.Org.OrgLink + "/settings") -} - -func SettingsDeleteAvatar(c *context.Context) { - if err := c.Org.Organization.DeleteAvatar(); err != nil { - c.Flash.Error(err.Error()) - } - - c.Redirect(c.Org.OrgLink + "/settings") -} - -func SettingsDelete(c *context.Context) { - c.Data["Title"] = c.Tr("org.settings") - c.Data["PageIsSettingsDelete"] = true - - org := c.Org.Organization - if c.Req.Method == "POST" { - if _, err := models.UserSignIn(c.User.Name, c.Query("password")); err != nil { - if errors.IsUserNotExist(err) { - c.RenderWithErr(c.Tr("form.enterred_invalid_password"), SETTINGS_DELETE, nil) - } else { - c.Handle(500, "UserSignIn", err) - } - return - } - - if err := models.DeleteOrganization(org); err != nil { - if models.IsErrUserOwnRepos(err) { - c.Flash.Error(c.Tr("form.org_still_own_repo")) - c.Redirect(c.Org.OrgLink + "/settings/delete") - } else { - c.Handle(500, "DeleteOrganization", err) - } - } else { - log.Trace("Organization deleted: %s", org.Name) - c.Redirect(setting.AppSubURL + "/") - } - return - } - - c.HTML(200, SETTINGS_DELETE) -} - -func Webhooks(c *context.Context) { - c.Data["Title"] = c.Tr("org.settings") - c.Data["PageIsSettingsHooks"] = true - c.Data["BaseLink"] = c.Org.OrgLink - c.Data["Description"] = c.Tr("org.settings.hooks_desc") - c.Data["Types"] = setting.Webhook.Types - - ws, err := models.GetWebhooksByOrgID(c.Org.Organization.ID) - if err != nil { - c.Handle(500, "GetWebhooksByOrgId", err) - return - } - - c.Data["Webhooks"] = ws - c.HTML(200, SETTINGS_WEBHOOKS) -} - -func DeleteWebhook(c *context.Context) { - if err := models.DeleteWebhookOfOrgByID(c.Org.Organization.ID, c.QueryInt64("id")); err != nil { - c.Flash.Error("DeleteWebhookByOrgID: " + err.Error()) - } else { - c.Flash.Success(c.Tr("repo.settings.webhook_deletion_success")) - } - - c.JSON(200, map[string]interface{}{ - "redirect": c.Org.OrgLink + "/settings/hooks", - }) -} diff --git a/routers/org/teams.go b/routers/org/teams.go deleted file mode 100644 index c97d470d..00000000 --- a/routers/org/teams.go +++ /dev/null @@ -1,271 +0,0 @@ -// 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 org - -import ( - "path" - - "github.com/Unknwon/com" - log "gopkg.in/clog.v1" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" -) - -const ( - TEAMS = "org/team/teams" - TEAM_NEW = "org/team/new" - TEAM_MEMBERS = "org/team/members" - TEAM_REPOSITORIES = "org/team/repositories" -) - -func Teams(c *context.Context) { - org := c.Org.Organization - c.Data["Title"] = org.FullName - c.Data["PageIsOrgTeams"] = true - - for _, t := range org.Teams { - if err := t.GetMembers(); err != nil { - c.Handle(500, "GetMembers", err) - return - } - } - c.Data["Teams"] = org.Teams - - c.HTML(200, TEAMS) -} - -func TeamsAction(c *context.Context) { - uid := com.StrTo(c.Query("uid")).MustInt64() - if uid == 0 { - c.Redirect(c.Org.OrgLink + "/teams") - return - } - - page := c.Query("page") - var err error - switch c.Params(":action") { - case "join": - if !c.Org.IsOwner { - c.Error(404) - return - } - err = c.Org.Team.AddMember(c.User.ID) - case "leave": - err = c.Org.Team.RemoveMember(c.User.ID) - case "remove": - if !c.Org.IsOwner { - c.Error(404) - return - } - err = c.Org.Team.RemoveMember(uid) - page = "team" - case "add": - if !c.Org.IsOwner { - c.Error(404) - return - } - uname := c.Query("uname") - var u *models.User - u, err = models.GetUserByName(uname) - if err != nil { - if errors.IsUserNotExist(err) { - c.Flash.Error(c.Tr("form.user_not_exist")) - c.Redirect(c.Org.OrgLink + "/teams/" + c.Org.Team.LowerName) - } else { - c.Handle(500, " GetUserByName", err) - } - return - } - - err = c.Org.Team.AddMember(u.ID) - page = "team" - } - - if err != nil { - if models.IsErrLastOrgOwner(err) { - c.Flash.Error(c.Tr("form.last_org_owner")) - } else { - log.Error(3, "Action(%s): %v", c.Params(":action"), err) - c.JSON(200, map[string]interface{}{ - "ok": false, - "err": err.Error(), - }) - return - } - } - - switch page { - case "team": - c.Redirect(c.Org.OrgLink + "/teams/" + c.Org.Team.LowerName) - default: - c.Redirect(c.Org.OrgLink + "/teams") - } -} - -func TeamsRepoAction(c *context.Context) { - if !c.Org.IsOwner { - c.Error(404) - return - } - - var err error - switch c.Params(":action") { - case "add": - repoName := path.Base(c.Query("repo_name")) - var repo *models.Repository - repo, err = models.GetRepositoryByName(c.Org.Organization.ID, repoName) - if err != nil { - if errors.IsRepoNotExist(err) { - c.Flash.Error(c.Tr("org.teams.add_nonexistent_repo")) - c.Redirect(c.Org.OrgLink + "/teams/" + c.Org.Team.LowerName + "/repositories") - return - } - c.Handle(500, "GetRepositoryByName", err) - return - } - err = c.Org.Team.AddRepository(repo) - case "remove": - err = c.Org.Team.RemoveRepository(com.StrTo(c.Query("repoid")).MustInt64()) - } - - if err != nil { - log.Error(3, "Action(%s): '%s' %v", c.Params(":action"), c.Org.Team.Name, err) - c.Handle(500, "TeamsRepoAction", err) - return - } - c.Redirect(c.Org.OrgLink + "/teams/" + c.Org.Team.LowerName + "/repositories") -} - -func NewTeam(c *context.Context) { - c.Data["Title"] = c.Org.Organization.FullName - c.Data["PageIsOrgTeams"] = true - c.Data["PageIsOrgTeamsNew"] = true - c.Data["Team"] = &models.Team{} - c.HTML(200, TEAM_NEW) -} - -func NewTeamPost(c *context.Context, f form.CreateTeam) { - c.Data["Title"] = c.Org.Organization.FullName - c.Data["PageIsOrgTeams"] = true - c.Data["PageIsOrgTeamsNew"] = true - - t := &models.Team{ - OrgID: c.Org.Organization.ID, - Name: f.TeamName, - Description: f.Description, - Authorize: models.ParseAccessMode(f.Permission), - } - c.Data["Team"] = t - - if c.HasError() { - c.HTML(200, TEAM_NEW) - return - } - - if err := models.NewTeam(t); err != nil { - c.Data["Err_TeamName"] = true - switch { - case models.IsErrTeamAlreadyExist(err): - c.RenderWithErr(c.Tr("form.team_name_been_taken"), TEAM_NEW, &f) - case models.IsErrNameReserved(err): - c.RenderWithErr(c.Tr("org.form.team_name_reserved", err.(models.ErrNameReserved).Name), TEAM_NEW, &f) - default: - c.Handle(500, "NewTeam", err) - } - return - } - log.Trace("Team created: %s/%s", c.Org.Organization.Name, t.Name) - c.Redirect(c.Org.OrgLink + "/teams/" + t.LowerName) -} - -func TeamMembers(c *context.Context) { - c.Data["Title"] = c.Org.Team.Name - c.Data["PageIsOrgTeams"] = true - if err := c.Org.Team.GetMembers(); err != nil { - c.Handle(500, "GetMembers", err) - return - } - c.HTML(200, TEAM_MEMBERS) -} - -func TeamRepositories(c *context.Context) { - c.Data["Title"] = c.Org.Team.Name - c.Data["PageIsOrgTeams"] = true - if err := c.Org.Team.GetRepositories(); err != nil { - c.Handle(500, "GetRepositories", err) - return - } - c.HTML(200, TEAM_REPOSITORIES) -} - -func EditTeam(c *context.Context) { - c.Data["Title"] = c.Org.Organization.FullName - c.Data["PageIsOrgTeams"] = true - c.Data["team_name"] = c.Org.Team.Name - c.Data["desc"] = c.Org.Team.Description - c.HTML(200, TEAM_NEW) -} - -func EditTeamPost(c *context.Context, f form.CreateTeam) { - t := c.Org.Team - c.Data["Title"] = c.Org.Organization.FullName - c.Data["PageIsOrgTeams"] = true - c.Data["Team"] = t - - if c.HasError() { - c.HTML(200, TEAM_NEW) - return - } - - isAuthChanged := false - if !t.IsOwnerTeam() { - // Validate permission level. - var auth models.AccessMode - switch f.Permission { - case "read": - auth = models.ACCESS_MODE_READ - case "write": - auth = models.ACCESS_MODE_WRITE - case "admin": - auth = models.ACCESS_MODE_ADMIN - default: - c.Error(401) - return - } - - t.Name = f.TeamName - if t.Authorize != auth { - isAuthChanged = true - t.Authorize = auth - } - } - t.Description = f.Description - if err := models.UpdateTeam(t, isAuthChanged); err != nil { - c.Data["Err_TeamName"] = true - switch { - case models.IsErrTeamAlreadyExist(err): - c.RenderWithErr(c.Tr("form.team_name_been_taken"), TEAM_NEW, &f) - default: - c.Handle(500, "UpdateTeam", err) - } - return - } - c.Redirect(c.Org.OrgLink + "/teams/" + t.LowerName) -} - -func DeleteTeam(c *context.Context) { - if err := models.DeleteTeam(c.Org.Team); err != nil { - c.Flash.Error("DeleteTeam: " + err.Error()) - } else { - c.Flash.Success(c.Tr("org.teams.delete_team_success")) - } - - c.JSON(200, map[string]interface{}{ - "redirect": c.Org.OrgLink + "/teams", - }) -} diff --git a/routers/repo/branch.go b/routers/repo/branch.go deleted file mode 100644 index 685df2e7..00000000 --- a/routers/repo/branch.go +++ /dev/null @@ -1,142 +0,0 @@ -// 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 repo - -import ( - "time" - - log "gopkg.in/clog.v1" - - "github.com/gogits/git-module" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" -) - -const ( - BRANCHES_OVERVIEW = "repo/branches/overview" - BRANCHES_ALL = "repo/branches/all" -) - -type Branch struct { - Name string - Commit *git.Commit - IsProtected bool -} - -func loadBranches(c *context.Context) []*Branch { - rawBranches, err := c.Repo.Repository.GetBranches() - if err != nil { - c.Handle(500, "GetBranches", err) - return nil - } - - protectBranches, err := models.GetProtectBranchesByRepoID(c.Repo.Repository.ID) - if err != nil { - c.Handle(500, "GetProtectBranchesByRepoID", err) - return nil - } - - branches := make([]*Branch, len(rawBranches)) - for i := range rawBranches { - commit, err := rawBranches[i].GetCommit() - if err != nil { - c.Handle(500, "GetCommit", err) - return nil - } - - branches[i] = &Branch{ - Name: rawBranches[i].Name, - Commit: commit, - } - - for j := range protectBranches { - if branches[i].Name == protectBranches[j].Name { - branches[i].IsProtected = true - break - } - } - } - - c.Data["AllowPullRequest"] = c.Repo.Repository.AllowsPulls() - return branches -} - -func Branches(c *context.Context) { - c.Data["Title"] = c.Tr("repo.git_branches") - c.Data["PageIsBranchesOverview"] = true - - branches := loadBranches(c) - if c.Written() { - return - } - - now := time.Now() - activeBranches := make([]*Branch, 0, 3) - staleBranches := make([]*Branch, 0, 3) - for i := range branches { - switch { - case branches[i].Name == c.Repo.BranchName: - c.Data["DefaultBranch"] = branches[i] - case branches[i].Commit.Committer.When.Add(30 * 24 * time.Hour).After(now): // 30 days - activeBranches = append(activeBranches, branches[i]) - case branches[i].Commit.Committer.When.Add(3 * 30 * 24 * time.Hour).Before(now): // 90 days - staleBranches = append(staleBranches, branches[i]) - } - } - - c.Data["ActiveBranches"] = activeBranches - c.Data["StaleBranches"] = staleBranches - c.HTML(200, BRANCHES_OVERVIEW) -} - -func AllBranches(c *context.Context) { - c.Data["Title"] = c.Tr("repo.git_branches") - c.Data["PageIsBranchesAll"] = true - - branches := loadBranches(c) - if c.Written() { - return - } - c.Data["Branches"] = branches - - c.HTML(200, BRANCHES_ALL) -} - -func DeleteBranchPost(c *context.Context) { - branchName := c.Params("*") - commitID := c.Query("commit") - - defer func() { - redirectTo := c.Query("redirect_to") - if len(redirectTo) == 0 { - redirectTo = c.Repo.RepoLink - } - c.Redirect(redirectTo) - }() - - if !c.Repo.GitRepo.IsBranchExist(branchName) { - return - } - if len(commitID) > 0 { - branchCommitID, err := c.Repo.GitRepo.GetBranchCommitID(branchName) - if err != nil { - log.Error(2, "GetBranchCommitID: %v", err) - return - } - - if branchCommitID != commitID { - c.Flash.Error(c.Tr("repo.pulls.delete_branch_has_new_commits")) - return - } - } - - if err := c.Repo.GitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{ - Force: true, - }); err != nil { - log.Error(2, "DeleteBranch '%s': %v", branchName, err) - return - } -} diff --git a/routers/repo/commit.go b/routers/repo/commit.go deleted file mode 100644 index 17ea5dbe..00000000 --- a/routers/repo/commit.go +++ /dev/null @@ -1,239 +0,0 @@ -// 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 repo - -import ( - "container/list" - "path" - - "github.com/gogits/git-module" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/pkg/tool" -) - -const ( - COMMITS = "repo/commits" - DIFF = "repo/diff/page" -) - -func RefCommits(c *context.Context) { - c.Data["PageIsViewFiles"] = true - switch { - case len(c.Repo.TreePath) == 0: - Commits(c) - case c.Repo.TreePath == "search": - SearchCommits(c) - default: - FileHistory(c) - } -} - -func RenderIssueLinks(oldCommits *list.List, repoLink string) *list.List { - newCommits := list.New() - for e := oldCommits.Front(); e != nil; e = e.Next() { - c := e.Value.(*git.Commit) - newCommits.PushBack(c) - } - return newCommits -} - -func renderCommits(c *context.Context, filename string) { - c.Data["Title"] = c.Tr("repo.commits.commit_history") + " · " + c.Repo.Repository.FullName() - c.Data["PageIsCommits"] = true - - page := c.QueryInt("page") - if page < 1 { - page = 1 - } - pageSize := c.QueryInt("pageSize") - if pageSize < 1 { - pageSize = git.DefaultCommitsPageSize - } - - // Both 'git log branchName' and 'git log commitID' work. - var err error - var commits *list.List - if len(filename) == 0 { - commits, err = c.Repo.Commit.CommitsByRangeSize(page, pageSize) - } else { - commits, err = c.Repo.GitRepo.CommitsByFileAndRangeSize(c.Repo.BranchName, filename, page, pageSize) - } - if err != nil { - c.Handle(500, "CommitsByRangeSize/CommitsByFileAndRangeSize", err) - return - } - commits = RenderIssueLinks(commits, c.Repo.RepoLink) - commits = models.ValidateCommitsWithEmails(commits) - c.Data["Commits"] = commits - - if page > 1 { - c.Data["HasPrevious"] = true - c.Data["PreviousPage"] = page - 1 - } - if commits.Len() == pageSize { - c.Data["HasNext"] = true - c.Data["NextPage"] = page + 1 - } - c.Data["PageSize"] = pageSize - - c.Data["Username"] = c.Repo.Owner.Name - c.Data["Reponame"] = c.Repo.Repository.Name - c.HTML(200, COMMITS) -} - -func Commits(c *context.Context) { - renderCommits(c, "") -} - -func SearchCommits(c *context.Context) { - c.Data["PageIsCommits"] = true - - keyword := c.Query("q") - if len(keyword) == 0 { - c.Redirect(c.Repo.RepoLink + "/commits/" + c.Repo.BranchName) - return - } - - commits, err := c.Repo.Commit.SearchCommits(keyword) - if err != nil { - c.Handle(500, "SearchCommits", err) - return - } - commits = RenderIssueLinks(commits, c.Repo.RepoLink) - commits = models.ValidateCommitsWithEmails(commits) - c.Data["Commits"] = commits - - c.Data["Keyword"] = keyword - c.Data["Username"] = c.Repo.Owner.Name - c.Data["Reponame"] = c.Repo.Repository.Name - c.Data["Branch"] = c.Repo.BranchName - c.HTML(200, COMMITS) -} - -func FileHistory(c *context.Context) { - renderCommits(c, c.Repo.TreePath) -} - -func Diff(c *context.Context) { - c.Data["PageIsDiff"] = true - c.Data["RequireHighlightJS"] = true - - userName := c.Repo.Owner.Name - repoName := c.Repo.Repository.Name - commitID := c.Params(":sha") - - commit, err := c.Repo.GitRepo.GetCommit(commitID) - if err != nil { - if git.IsErrNotExist(err) { - c.Handle(404, "Repo.GitRepo.GetCommit", err) - } else { - c.Handle(500, "Repo.GitRepo.GetCommit", err) - } - return - } - - diff, err := models.GetDiffCommit(models.RepoPath(userName, repoName), - commitID, setting.Git.MaxGitDiffLines, - setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles) - if err != nil { - c.NotFoundOrServerError("GetDiffCommit", git.IsErrNotExist, err) - return - } - - parents := make([]string, commit.ParentCount()) - for i := 0; i < commit.ParentCount(); i++ { - sha, err := commit.ParentID(i) - parents[i] = sha.String() - if err != nil { - c.Handle(404, "repo.Diff", err) - return - } - } - - setEditorconfigIfExists(c) - if c.Written() { - return - } - - c.Data["CommitID"] = commitID - c.Data["IsSplitStyle"] = c.Query("style") == "split" - c.Data["Username"] = userName - c.Data["Reponame"] = repoName - c.Data["IsImageFile"] = commit.IsImageFile - c.Data["Title"] = commit.Summary() + " · " + tool.ShortSHA1(commitID) - c.Data["Commit"] = commit - c.Data["Author"] = models.ValidateCommitWithEmail(commit) - c.Data["Diff"] = diff - c.Data["Parents"] = parents - c.Data["DiffNotAvailable"] = diff.NumFiles() == 0 - c.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", commitID) - if commit.ParentCount() > 0 { - c.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", parents[0]) - } - c.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", commitID) - c.HTML(200, DIFF) -} - -func RawDiff(c *context.Context) { - if err := git.GetRawDiff( - models.RepoPath(c.Repo.Owner.Name, c.Repo.Repository.Name), - c.Params(":sha"), - git.RawDiffType(c.Params(":ext")), - c.Resp, - ); err != nil { - c.NotFoundOrServerError("GetRawDiff", git.IsErrNotExist, err) - return - } -} - -func CompareDiff(c *context.Context) { - c.Data["IsDiffCompare"] = true - userName := c.Repo.Owner.Name - repoName := c.Repo.Repository.Name - beforeCommitID := c.Params(":before") - afterCommitID := c.Params(":after") - - commit, err := c.Repo.GitRepo.GetCommit(afterCommitID) - if err != nil { - c.Handle(404, "GetCommit", err) - return - } - - diff, err := models.GetDiffRange(models.RepoPath(userName, repoName), beforeCommitID, - afterCommitID, setting.Git.MaxGitDiffLines, - setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles) - if err != nil { - c.Handle(404, "GetDiffRange", err) - return - } - - commits, err := commit.CommitsBeforeUntil(beforeCommitID) - if err != nil { - c.Handle(500, "CommitsBeforeUntil", err) - return - } - commits = models.ValidateCommitsWithEmails(commits) - - c.Data["IsSplitStyle"] = c.Query("style") == "split" - c.Data["CommitRepoLink"] = c.Repo.RepoLink - c.Data["Commits"] = commits - c.Data["CommitsCount"] = commits.Len() - c.Data["BeforeCommitID"] = beforeCommitID - c.Data["AfterCommitID"] = afterCommitID - c.Data["Username"] = userName - c.Data["Reponame"] = repoName - c.Data["IsImageFile"] = commit.IsImageFile - c.Data["Title"] = "Comparing " + tool.ShortSHA1(beforeCommitID) + "..." + tool.ShortSHA1(afterCommitID) + " · " + userName + "/" + repoName - c.Data["Commit"] = commit - c.Data["Diff"] = diff - c.Data["DiffNotAvailable"] = diff.NumFiles() == 0 - c.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", afterCommitID) - c.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "src", beforeCommitID) - c.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(userName, repoName, "raw", afterCommitID) - c.HTML(200, DIFF) -} diff --git a/routers/repo/download.go b/routers/repo/download.go deleted file mode 100644 index e9a29989..00000000 --- a/routers/repo/download.go +++ /dev/null @@ -1,60 +0,0 @@ -// 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 repo - -import ( - "io" - "path" - - "github.com/gogits/git-module" - - "github.com/gogits/gogs/pkg/tool" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" -) - -func ServeData(c *context.Context, name string, reader io.Reader) error { - buf := make([]byte, 1024) - n, _ := reader.Read(buf) - if n >= 0 { - buf = buf[:n] - } - - if !tool.IsTextFile(buf) { - if !tool.IsImageFile(buf) { - c.Resp.Header().Set("Content-Disposition", "attachment; filename=\""+name+"\"") - c.Resp.Header().Set("Content-Transfer-Encoding", "binary") - } - } else if !setting.Repository.EnableRawFileRenderMode || !c.QueryBool("render") { - c.Resp.Header().Set("Content-Type", "text/plain; charset=utf-8") - } - c.Resp.Write(buf) - _, err := io.Copy(c.Resp, reader) - return err -} - -func ServeBlob(c *context.Context, blob *git.Blob) error { - dataRc, err := blob.Data() - if err != nil { - return err - } - - return ServeData(c, path.Base(c.Repo.TreePath), dataRc) -} - -func SingleDownload(c *context.Context) { - blob, err := c.Repo.Commit.GetBlobByPath(c.Repo.TreePath) - if err != nil { - if git.IsErrNotExist(err) { - c.Handle(404, "GetBlobByPath", nil) - } else { - c.Handle(500, "GetBlobByPath", err) - } - return - } - if err = ServeBlob(c, blob); err != nil { - c.Handle(500, "ServeBlob", err) - } -} diff --git a/routers/repo/editor.go b/routers/repo/editor.go deleted file mode 100644 index 4cd78d70..00000000 --- a/routers/repo/editor.go +++ /dev/null @@ -1,571 +0,0 @@ -// Copyright 2016 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 repo - -import ( - "fmt" - "io/ioutil" - "net/http" - "path" - "strings" - - log "gopkg.in/clog.v1" - - "github.com/gogits/git-module" - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/pkg/template" - "github.com/gogits/gogs/pkg/tool" -) - -const ( - EDIT_FILE = "repo/editor/edit" - EDIT_DIFF_PREVIEW = "repo/editor/diff_preview" - DELETE_FILE = "repo/editor/delete" - UPLOAD_FILE = "repo/editor/upload" -) - -// getParentTreeFields returns list of parent tree names and corresponding tree paths -// based on given tree path. -func getParentTreeFields(treePath string) (treeNames []string, treePaths []string) { - if len(treePath) == 0 { - return treeNames, treePaths - } - - treeNames = strings.Split(treePath, "/") - treePaths = make([]string, len(treeNames)) - for i := range treeNames { - treePaths[i] = strings.Join(treeNames[:i+1], "/") - } - return treeNames, treePaths -} - -func editFile(c *context.Context, isNewFile bool) { - c.PageIs("Edit") - c.RequireHighlightJS() - c.RequireSimpleMDE() - c.Data["IsNewFile"] = isNewFile - - treeNames, treePaths := getParentTreeFields(c.Repo.TreePath) - - if !isNewFile { - entry, err := c.Repo.Commit.GetTreeEntryByPath(c.Repo.TreePath) - if err != nil { - c.NotFoundOrServerError("GetTreeEntryByPath", git.IsErrNotExist, err) - return - } - - // No way to edit a directory online. - if entry.IsDir() { - c.NotFound() - return - } - - blob := entry.Blob() - dataRc, err := blob.Data() - if err != nil { - c.ServerError("blob.Data", err) - return - } - - c.Data["FileSize"] = blob.Size() - c.Data["FileName"] = blob.Name() - - buf := make([]byte, 1024) - n, _ := dataRc.Read(buf) - buf = buf[:n] - - // Only text file are editable online. - if !tool.IsTextFile(buf) { - c.NotFound() - return - } - - d, _ := ioutil.ReadAll(dataRc) - buf = append(buf, d...) - if err, content := template.ToUTF8WithErr(buf); err != nil { - if err != nil { - log.Error(2, "ToUTF8WithErr: %v", err) - } - c.Data["FileContent"] = string(buf) - } else { - c.Data["FileContent"] = content - } - } else { - treeNames = append(treeNames, "") // Append empty string to allow user name the new file. - } - - c.Data["ParentTreePath"] = path.Dir(c.Repo.TreePath) - c.Data["TreeNames"] = treeNames - c.Data["TreePaths"] = treePaths - c.Data["BranchLink"] = c.Repo.RepoLink + "/src/" + c.Repo.BranchName - c.Data["commit_summary"] = "" - c.Data["commit_message"] = "" - c.Data["commit_choice"] = "direct" - c.Data["new_branch_name"] = "" - c.Data["last_commit"] = c.Repo.Commit.ID - c.Data["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",") - c.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") - c.Data["PreviewableFileModes"] = strings.Join(setting.Repository.Editor.PreviewableFileModes, ",") - c.Data["EditorconfigURLPrefix"] = fmt.Sprintf("%s/api/v1/repos/%s/editorconfig/", setting.AppSubURL, c.Repo.Repository.FullName()) - - c.Success(EDIT_FILE) -} - -func EditFile(c *context.Context) { - editFile(c, false) -} - -func NewFile(c *context.Context) { - editFile(c, true) -} - -func editFilePost(c *context.Context, f form.EditRepoFile, isNewFile bool) { - c.PageIs("Edit") - c.RequireHighlightJS() - c.RequireSimpleMDE() - c.Data["IsNewFile"] = isNewFile - - oldBranchName := c.Repo.BranchName - branchName := oldBranchName - oldTreePath := c.Repo.TreePath - lastCommit := f.LastCommit - f.LastCommit = c.Repo.Commit.ID.String() - - if f.IsNewBrnach() { - branchName = f.NewBranchName - } - - f.TreePath = strings.Trim(f.TreePath, " /") - treeNames, treePaths := getParentTreeFields(f.TreePath) - - c.Data["ParentTreePath"] = path.Dir(c.Repo.TreePath) - c.Data["TreePath"] = f.TreePath - c.Data["TreeNames"] = treeNames - c.Data["TreePaths"] = treePaths - c.Data["BranchLink"] = c.Repo.RepoLink + "/src/" + branchName - c.Data["FileContent"] = f.Content - c.Data["commit_summary"] = f.CommitSummary - c.Data["commit_message"] = f.CommitMessage - c.Data["commit_choice"] = f.CommitChoice - c.Data["new_branch_name"] = branchName - c.Data["last_commit"] = f.LastCommit - c.Data["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",") - c.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") - c.Data["PreviewableFileModes"] = strings.Join(setting.Repository.Editor.PreviewableFileModes, ",") - - if c.HasError() { - c.Success(EDIT_FILE) - return - } - - if len(f.TreePath) == 0 { - c.FormErr("TreePath") - c.RenderWithErr(c.Tr("repo.editor.filename_cannot_be_empty"), EDIT_FILE, &f) - return - } - - if oldBranchName != branchName { - if _, err := c.Repo.Repository.GetBranch(branchName); err == nil { - c.FormErr("NewBranchName") - c.RenderWithErr(c.Tr("repo.editor.branch_already_exists", branchName), EDIT_FILE, &f) - return - } - } - - var newTreePath string - for index, part := range treeNames { - newTreePath = path.Join(newTreePath, part) - entry, err := c.Repo.Commit.GetTreeEntryByPath(newTreePath) - if err != nil { - if git.IsErrNotExist(err) { - // Means there is no item with that name, so we're good - break - } - - c.ServerError("Repo.Commit.GetTreeEntryByPath", err) - return - } - if index != len(treeNames)-1 { - if !entry.IsDir() { - c.FormErr("TreePath") - c.RenderWithErr(c.Tr("repo.editor.directory_is_a_file", part), EDIT_FILE, &f) - return - } - } else { - if entry.IsLink() { - c.FormErr("TreePath") - c.RenderWithErr(c.Tr("repo.editor.file_is_a_symlink", part), EDIT_FILE, &f) - return - } else if entry.IsDir() { - c.FormErr("TreePath") - c.RenderWithErr(c.Tr("repo.editor.filename_is_a_directory", part), EDIT_FILE, &f) - return - } - } - } - - if !isNewFile { - _, err := c.Repo.Commit.GetTreeEntryByPath(oldTreePath) - if err != nil { - if git.IsErrNotExist(err) { - c.FormErr("TreePath") - c.RenderWithErr(c.Tr("repo.editor.file_editing_no_longer_exists", oldTreePath), EDIT_FILE, &f) - } else { - c.ServerError("GetTreeEntryByPath", err) - } - return - } - if lastCommit != c.Repo.CommitID { - files, err := c.Repo.Commit.GetFilesChangedSinceCommit(lastCommit) - if err != nil { - c.ServerError("GetFilesChangedSinceCommit", err) - return - } - - for _, file := range files { - if file == f.TreePath { - c.RenderWithErr(c.Tr("repo.editor.file_changed_while_editing", c.Repo.RepoLink+"/compare/"+lastCommit+"..."+c.Repo.CommitID), EDIT_FILE, &f) - return - } - } - } - } - - if oldTreePath != f.TreePath { - // We have a new filename (rename or completely new file) so we need to make sure it doesn't already exist, can't clobber. - entry, err := c.Repo.Commit.GetTreeEntryByPath(f.TreePath) - if err != nil { - if !git.IsErrNotExist(err) { - c.ServerError("GetTreeEntryByPath", err) - return - } - } - if entry != nil { - c.FormErr("TreePath") - c.RenderWithErr(c.Tr("repo.editor.file_already_exists", f.TreePath), EDIT_FILE, &f) - return - } - } - - message := strings.TrimSpace(f.CommitSummary) - if len(message) == 0 { - if isNewFile { - message = c.Tr("repo.editor.add", f.TreePath) - } else { - message = c.Tr("repo.editor.update", f.TreePath) - } - } - - f.CommitMessage = strings.TrimSpace(f.CommitMessage) - if len(f.CommitMessage) > 0 { - message += "\n\n" + f.CommitMessage - } - - if err := c.Repo.Repository.UpdateRepoFile(c.User, models.UpdateRepoFileOptions{ - LastCommitID: lastCommit, - OldBranch: oldBranchName, - NewBranch: branchName, - OldTreeName: oldTreePath, - NewTreeName: f.TreePath, - Message: message, - Content: strings.Replace(f.Content, "\r", "", -1), - IsNewFile: isNewFile, - }); err != nil { - c.FormErr("TreePath") - c.RenderWithErr(c.Tr("repo.editor.fail_to_update_file", f.TreePath, err), EDIT_FILE, &f) - return - } - - if f.IsNewBrnach() && c.Repo.PullRequest.Allowed { - c.Redirect(c.Repo.PullRequestURL(oldBranchName, f.NewBranchName)) - } else { - c.Redirect(c.Repo.RepoLink + "/src/" + branchName + "/" + template.EscapePound(f.TreePath)) - } -} - -func EditFilePost(c *context.Context, f form.EditRepoFile) { - editFilePost(c, f, false) -} - -func NewFilePost(c *context.Context, f form.EditRepoFile) { - editFilePost(c, f, true) -} - -func DiffPreviewPost(c *context.Context, f form.EditPreviewDiff) { - treePath := c.Repo.TreePath - - entry, err := c.Repo.Commit.GetTreeEntryByPath(treePath) - if err != nil { - c.Error(500, "GetTreeEntryByPath: "+err.Error()) - return - } else if entry.IsDir() { - c.Error(422) - return - } - - diff, err := c.Repo.Repository.GetDiffPreview(c.Repo.BranchName, treePath, f.Content) - if err != nil { - c.Error(500, "GetDiffPreview: "+err.Error()) - return - } - - if diff.NumFiles() == 0 { - c.PlainText(200, []byte(c.Tr("repo.editor.no_changes_to_show"))) - return - } - c.Data["File"] = diff.Files[0] - - c.HTML(200, EDIT_DIFF_PREVIEW) -} - -func DeleteFile(c *context.Context) { - c.Data["PageIsDelete"] = true - c.Data["BranchLink"] = c.Repo.RepoLink + "/src/" + c.Repo.BranchName - c.Data["TreePath"] = c.Repo.TreePath - c.Data["commit_summary"] = "" - c.Data["commit_message"] = "" - c.Data["commit_choice"] = "direct" - c.Data["new_branch_name"] = "" - c.HTML(200, DELETE_FILE) -} - -func DeleteFilePost(c *context.Context, f form.DeleteRepoFile) { - c.Data["PageIsDelete"] = true - c.Data["BranchLink"] = c.Repo.RepoLink + "/src/" + c.Repo.BranchName - c.Data["TreePath"] = c.Repo.TreePath - - oldBranchName := c.Repo.BranchName - branchName := oldBranchName - - if f.IsNewBrnach() { - branchName = f.NewBranchName - } - c.Data["commit_summary"] = f.CommitSummary - c.Data["commit_message"] = f.CommitMessage - c.Data["commit_choice"] = f.CommitChoice - c.Data["new_branch_name"] = branchName - - if c.HasError() { - c.HTML(200, DELETE_FILE) - return - } - - if oldBranchName != branchName { - if _, err := c.Repo.Repository.GetBranch(branchName); err == nil { - c.Data["Err_NewBranchName"] = true - c.RenderWithErr(c.Tr("repo.editor.branch_already_exists", branchName), DELETE_FILE, &f) - return - } - } - - message := strings.TrimSpace(f.CommitSummary) - if len(message) == 0 { - message = c.Tr("repo.editor.delete", c.Repo.TreePath) - } - - f.CommitMessage = strings.TrimSpace(f.CommitMessage) - if len(f.CommitMessage) > 0 { - message += "\n\n" + f.CommitMessage - } - - if err := c.Repo.Repository.DeleteRepoFile(c.User, models.DeleteRepoFileOptions{ - LastCommitID: c.Repo.CommitID, - OldBranch: oldBranchName, - NewBranch: branchName, - TreePath: c.Repo.TreePath, - Message: message, - }); err != nil { - c.Handle(500, "DeleteRepoFile", err) - return - } - - if f.IsNewBrnach() && c.Repo.PullRequest.Allowed { - c.Redirect(c.Repo.PullRequestURL(oldBranchName, f.NewBranchName)) - } else { - c.Flash.Success(c.Tr("repo.editor.file_delete_success", c.Repo.TreePath)) - c.Redirect(c.Repo.RepoLink + "/src/" + branchName) - } -} - -func renderUploadSettings(c *context.Context) { - c.Data["RequireDropzone"] = true - c.Data["UploadAllowedTypes"] = strings.Join(setting.Repository.Upload.AllowedTypes, ",") - c.Data["UploadMaxSize"] = setting.Repository.Upload.FileMaxSize - c.Data["UploadMaxFiles"] = setting.Repository.Upload.MaxFiles -} - -func UploadFile(c *context.Context) { - c.Data["PageIsUpload"] = true - renderUploadSettings(c) - - treeNames, treePaths := getParentTreeFields(c.Repo.TreePath) - if len(treeNames) == 0 { - // We must at least have one element for user to input. - treeNames = []string{""} - } - - c.Data["TreeNames"] = treeNames - c.Data["TreePaths"] = treePaths - c.Data["BranchLink"] = c.Repo.RepoLink + "/src/" + c.Repo.BranchName - c.Data["commit_summary"] = "" - c.Data["commit_message"] = "" - c.Data["commit_choice"] = "direct" - c.Data["new_branch_name"] = "" - - c.HTML(200, UPLOAD_FILE) -} - -func UploadFilePost(c *context.Context, f form.UploadRepoFile) { - c.Data["PageIsUpload"] = true - renderUploadSettings(c) - - oldBranchName := c.Repo.BranchName - branchName := oldBranchName - - if f.IsNewBrnach() { - branchName = f.NewBranchName - } - - f.TreePath = strings.Trim(f.TreePath, " /") - treeNames, treePaths := getParentTreeFields(f.TreePath) - if len(treeNames) == 0 { - // We must at least have one element for user to input. - treeNames = []string{""} - } - - c.Data["TreePath"] = f.TreePath - c.Data["TreeNames"] = treeNames - c.Data["TreePaths"] = treePaths - c.Data["BranchLink"] = c.Repo.RepoLink + "/src/" + branchName - c.Data["commit_summary"] = f.CommitSummary - c.Data["commit_message"] = f.CommitMessage - c.Data["commit_choice"] = f.CommitChoice - c.Data["new_branch_name"] = branchName - - if c.HasError() { - c.HTML(200, UPLOAD_FILE) - return - } - - if oldBranchName != branchName { - if _, err := c.Repo.Repository.GetBranch(branchName); err == nil { - c.Data["Err_NewBranchName"] = true - c.RenderWithErr(c.Tr("repo.editor.branch_already_exists", branchName), UPLOAD_FILE, &f) - return - } - } - - var newTreePath string - for _, part := range treeNames { - newTreePath = path.Join(newTreePath, part) - entry, err := c.Repo.Commit.GetTreeEntryByPath(newTreePath) - if err != nil { - if git.IsErrNotExist(err) { - // Means there is no item with that name, so we're good - break - } - - c.Handle(500, "Repo.Commit.GetTreeEntryByPath", err) - return - } - - // User can only upload files to a directory. - if !entry.IsDir() { - c.Data["Err_TreePath"] = true - c.RenderWithErr(c.Tr("repo.editor.directory_is_a_file", part), UPLOAD_FILE, &f) - return - } - } - - message := strings.TrimSpace(f.CommitSummary) - if len(message) == 0 { - message = c.Tr("repo.editor.upload_files_to_dir", f.TreePath) - } - - f.CommitMessage = strings.TrimSpace(f.CommitMessage) - if len(f.CommitMessage) > 0 { - message += "\n\n" + f.CommitMessage - } - - if err := c.Repo.Repository.UploadRepoFiles(c.User, models.UploadRepoFileOptions{ - LastCommitID: c.Repo.CommitID, - OldBranch: oldBranchName, - NewBranch: branchName, - TreePath: f.TreePath, - Message: message, - Files: f.Files, - }); err != nil { - c.Data["Err_TreePath"] = true - c.RenderWithErr(c.Tr("repo.editor.unable_to_upload_files", f.TreePath, err), UPLOAD_FILE, &f) - return - } - - if f.IsNewBrnach() && c.Repo.PullRequest.Allowed { - c.Redirect(c.Repo.PullRequestURL(oldBranchName, f.NewBranchName)) - } else { - c.Redirect(c.Repo.RepoLink + "/src/" + branchName + "/" + f.TreePath) - } -} - -func UploadFileToServer(c *context.Context) { - file, header, err := c.Req.FormFile("file") - if err != nil { - c.Error(500, fmt.Sprintf("FormFile: %v", err)) - return - } - defer file.Close() - - buf := make([]byte, 1024) - n, _ := file.Read(buf) - if n > 0 { - buf = buf[:n] - } - fileType := http.DetectContentType(buf) - - if len(setting.Repository.Upload.AllowedTypes) > 0 { - allowed := false - for _, t := range setting.Repository.Upload.AllowedTypes { - t := strings.Trim(t, " ") - if t == "*/*" || t == fileType { - allowed = true - break - } - } - - if !allowed { - c.Error(400, ErrFileTypeForbidden.Error()) - return - } - } - - upload, err := models.NewUpload(header.Filename, buf, file) - if err != nil { - c.Error(500, fmt.Sprintf("NewUpload: %v", err)) - return - } - - log.Trace("New file uploaded: %s", upload.UUID) - c.JSON(200, map[string]string{ - "uuid": upload.UUID, - }) -} - -func RemoveUploadFileFromServer(c *context.Context, f form.RemoveUploadFile) { - if len(f.File) == 0 { - c.Status(204) - return - } - - if err := models.DeleteUploadByUUID(f.File); err != nil { - c.Error(500, fmt.Sprintf("DeleteUploadByUUID: %v", err)) - return - } - - log.Trace("Upload file removed: %s", f.File) - c.Status(204) -} diff --git a/routers/repo/http.go b/routers/repo/http.go deleted file mode 100644 index b8f519ba..00000000 --- a/routers/repo/http.go +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright 2017 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 repo - -import ( - "bytes" - "compress/gzip" - "fmt" - "net/http" - "os" - "os/exec" - "path" - "regexp" - "strconv" - "strings" - "time" - - "github.com/Unknwon/com" - log "gopkg.in/clog.v1" - "gopkg.in/macaron.v1" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/pkg/tool" -) - -const ( - ENV_AUTH_USER_ID = "GOGS_AUTH_USER_ID" - ENV_AUTH_USER_NAME = "GOGS_AUTH_USER_NAME" - ENV_AUTH_USER_EMAIL = "GOGS_AUTH_USER_EMAIL" - ENV_REPO_OWNER_NAME = "GOGS_REPO_OWNER_NAME" - ENV_REPO_OWNER_SALT_MD5 = "GOGS_REPO_OWNER_SALT_MD5" - ENV_REPO_ID = "GOGS_REPO_ID" - ENV_REPO_NAME = "GOGS_REPO_NAME" - ENV_REPO_CUSTOM_HOOKS_PATH = "GOGS_REPO_CUSTOM_HOOKS_PATH" -) - -type HTTPContext struct { - *context.Context - OwnerName string - OwnerSalt string - RepoID int64 - RepoName string - AuthUser *models.User -} - -// askCredentials responses HTTP header and status which informs client to provide credentials. -func askCredentials(c *context.Context, status int, text string) { - c.Resp.Header().Set("WWW-Authenticate", "Basic realm=\".\"") - c.HandleText(status, text) -} - -func HTTPContexter() macaron.Handler { - return func(c *context.Context) { - ownerName := c.Params(":username") - repoName := strings.TrimSuffix(c.Params(":reponame"), ".git") - repoName = strings.TrimSuffix(repoName, ".wiki") - - isPull := c.Query("service") == "git-upload-pack" || - strings.HasSuffix(c.Req.URL.Path, "git-upload-pack") || - c.Req.Method == "GET" - - owner, err := models.GetUserByName(ownerName) - if err != nil { - c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err) - return - } - - repo, err := models.GetRepositoryByName(owner.ID, repoName) - if err != nil { - c.NotFoundOrServerError("GetRepositoryByName", errors.IsRepoNotExist, err) - return - } - - // Authentication is not required for pulling from public repositories. - if isPull && !repo.IsPrivate && !setting.Service.RequireSignInView { - c.Map(&HTTPContext{ - Context: c, - }) - return - } - - // In case user requested a wrong URL and not intended to access Git objects. - action := c.Params("*") - if !strings.Contains(action, "git-") && - !strings.Contains(action, "info/") && - !strings.Contains(action, "HEAD") && - !strings.Contains(action, "objects/") { - c.NotFound() - return - } - - // Handle HTTP Basic Authentication - authHead := c.Req.Header.Get("Authorization") - if len(authHead) == 0 { - askCredentials(c, http.StatusUnauthorized, "") - return - } - - auths := strings.Fields(authHead) - if len(auths) != 2 || auths[0] != "Basic" { - askCredentials(c, http.StatusUnauthorized, "") - return - } - authUsername, authPassword, err := tool.BasicAuthDecode(auths[1]) - if err != nil { - askCredentials(c, http.StatusUnauthorized, "") - return - } - - authUser, err := models.UserSignIn(authUsername, authPassword) - if err != nil && !errors.IsUserNotExist(err) { - c.Handle(http.StatusInternalServerError, "UserSignIn", err) - return - } - - // If username and password combination failed, try again using username as a token. - if authUser == nil { - token, err := models.GetAccessTokenBySHA(authUsername) - if err != nil { - if models.IsErrAccessTokenEmpty(err) || models.IsErrAccessTokenNotExist(err) { - askCredentials(c, http.StatusUnauthorized, "") - } else { - c.Handle(http.StatusInternalServerError, "GetAccessTokenBySHA", err) - } - return - } - token.Updated = time.Now() - - authUser, err = models.GetUserByID(token.UID) - if err != nil { - // Once we found token, we're supposed to find its related user, - // thus any error is unexpected. - c.Handle(http.StatusInternalServerError, "GetUserByID", err) - return - } - } else if authUser.IsEnabledTwoFactor() { - askCredentials(c, http.StatusUnauthorized, `User with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password -Please create and use personal access token on user settings page`) - return - } - - log.Trace("HTTPGit - Authenticated user: %s", authUser.Name) - - mode := models.ACCESS_MODE_WRITE - if isPull { - mode = models.ACCESS_MODE_READ - } - has, err := models.HasAccess(authUser.ID, repo, mode) - if err != nil { - c.Handle(http.StatusInternalServerError, "HasAccess", err) - return - } else if !has { - askCredentials(c, http.StatusForbidden, "User permission denied") - return - } - - if !isPull && repo.IsMirror { - c.HandleText(http.StatusForbidden, "Mirror repository is read-only") - return - } - - c.Map(&HTTPContext{ - Context: c, - OwnerName: ownerName, - OwnerSalt: owner.Salt, - RepoID: repo.ID, - RepoName: repoName, - AuthUser: authUser, - }) - } -} - -type serviceHandler struct { - w http.ResponseWriter - r *http.Request - dir string - file string - - authUser *models.User - ownerName string - ownerSalt string - repoID int64 - repoName string -} - -func (h *serviceHandler) setHeaderNoCache() { - h.w.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT") - h.w.Header().Set("Pragma", "no-cache") - h.w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate") -} - -func (h *serviceHandler) setHeaderCacheForever() { - now := time.Now().Unix() - expires := now + 31536000 - h.w.Header().Set("Date", fmt.Sprintf("%d", now)) - h.w.Header().Set("Expires", fmt.Sprintf("%d", expires)) - h.w.Header().Set("Cache-Control", "public, max-age=31536000") -} - -func (h *serviceHandler) sendFile(contentType string) { - reqFile := path.Join(h.dir, h.file) - fi, err := os.Stat(reqFile) - if os.IsNotExist(err) { - h.w.WriteHeader(http.StatusNotFound) - return - } - - h.w.Header().Set("Content-Type", contentType) - h.w.Header().Set("Content-Length", fmt.Sprintf("%d", fi.Size())) - h.w.Header().Set("Last-Modified", fi.ModTime().Format(http.TimeFormat)) - http.ServeFile(h.w, h.r, reqFile) -} - -type ComposeHookEnvsOptions struct { - AuthUser *models.User - OwnerName string - OwnerSalt string - RepoID int64 - RepoName string - RepoPath string -} - -func ComposeHookEnvs(opts ComposeHookEnvsOptions) []string { - envs := []string{ - "SSH_ORIGINAL_COMMAND=1", - ENV_AUTH_USER_ID + "=" + com.ToStr(opts.AuthUser.ID), - ENV_AUTH_USER_NAME + "=" + opts.AuthUser.Name, - ENV_AUTH_USER_EMAIL + "=" + opts.AuthUser.Email, - ENV_REPO_OWNER_NAME + "=" + opts.OwnerName, - ENV_REPO_OWNER_SALT_MD5 + "=" + tool.MD5(opts.OwnerSalt), - ENV_REPO_ID + "=" + com.ToStr(opts.RepoID), - ENV_REPO_NAME + "=" + opts.RepoName, - ENV_REPO_CUSTOM_HOOKS_PATH + "=" + path.Join(opts.RepoPath, "custom_hooks"), - } - return envs -} - -func serviceRPC(h serviceHandler, service string) { - defer h.r.Body.Close() - - if h.r.Header.Get("Content-Type") != fmt.Sprintf("application/x-git-%s-request", service) { - h.w.WriteHeader(http.StatusUnauthorized) - return - } - h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service)) - - var ( - reqBody = h.r.Body - err error - ) - - // Handle GZIP - if h.r.Header.Get("Content-Encoding") == "gzip" { - reqBody, err = gzip.NewReader(reqBody) - if err != nil { - log.Error(2, "HTTP.Get: fail to create gzip reader: %v", err) - h.w.WriteHeader(http.StatusInternalServerError) - return - } - } - - var stderr bytes.Buffer - cmd := exec.Command("git", service, "--stateless-rpc", h.dir) - if service == "receive-pack" { - cmd.Env = append(os.Environ(), ComposeHookEnvs(ComposeHookEnvsOptions{ - AuthUser: h.authUser, - OwnerName: h.ownerName, - OwnerSalt: h.ownerSalt, - RepoID: h.repoID, - RepoName: h.repoName, - RepoPath: h.dir, - })...) - } - cmd.Dir = h.dir - cmd.Stdout = h.w - cmd.Stderr = &stderr - cmd.Stdin = reqBody - if err = cmd.Run(); err != nil { - log.Error(2, "HTTP.serviceRPC: fail to serve RPC '%s': %v - %s", service, err, stderr) - h.w.WriteHeader(http.StatusInternalServerError) - return - } -} - -func serviceUploadPack(h serviceHandler) { - serviceRPC(h, "upload-pack") -} - -func serviceReceivePack(h serviceHandler) { - serviceRPC(h, "receive-pack") -} - -func getServiceType(r *http.Request) string { - serviceType := r.FormValue("service") - if !strings.HasPrefix(serviceType, "git-") { - return "" - } - return strings.TrimPrefix(serviceType, "git-") -} - -// FIXME: use process module -func gitCommand(dir string, args ...string) []byte { - cmd := exec.Command("git", args...) - cmd.Dir = dir - out, err := cmd.Output() - if err != nil { - log.Error(2, fmt.Sprintf("Git: %v - %s", err, out)) - } - return out -} - -func updateServerInfo(dir string) []byte { - return gitCommand(dir, "update-server-info") -} - -func packetWrite(str string) []byte { - s := strconv.FormatInt(int64(len(str)+4), 16) - if len(s)%4 != 0 { - s = strings.Repeat("0", 4-len(s)%4) + s - } - return []byte(s + str) -} - -func getInfoRefs(h serviceHandler) { - h.setHeaderNoCache() - service := getServiceType(h.r) - if service != "upload-pack" && service != "receive-pack" { - updateServerInfo(h.dir) - h.sendFile("text/plain; charset=utf-8") - return - } - - refs := gitCommand(h.dir, service, "--stateless-rpc", "--advertise-refs", ".") - h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-advertisement", service)) - h.w.WriteHeader(http.StatusOK) - h.w.Write(packetWrite("# service=git-" + service + "\n")) - h.w.Write([]byte("0000")) - h.w.Write(refs) -} - -func getTextFile(h serviceHandler) { - h.setHeaderNoCache() - h.sendFile("text/plain") -} - -func getInfoPacks(h serviceHandler) { - h.setHeaderCacheForever() - h.sendFile("text/plain; charset=utf-8") -} - -func getLooseObject(h serviceHandler) { - h.setHeaderCacheForever() - h.sendFile("application/x-git-loose-object") -} - -func getPackFile(h serviceHandler) { - h.setHeaderCacheForever() - h.sendFile("application/x-git-packed-objects") -} - -func getIdxFile(h serviceHandler) { - h.setHeaderCacheForever() - h.sendFile("application/x-git-packed-objects-toc") -} - -var routes = []struct { - reg *regexp.Regexp - method string - handler func(serviceHandler) -}{ - {regexp.MustCompile("(.*?)/git-upload-pack$"), "POST", serviceUploadPack}, - {regexp.MustCompile("(.*?)/git-receive-pack$"), "POST", serviceReceivePack}, - {regexp.MustCompile("(.*?)/info/refs$"), "GET", getInfoRefs}, - {regexp.MustCompile("(.*?)/HEAD$"), "GET", getTextFile}, - {regexp.MustCompile("(.*?)/objects/info/alternates$"), "GET", getTextFile}, - {regexp.MustCompile("(.*?)/objects/info/http-alternates$"), "GET", getTextFile}, - {regexp.MustCompile("(.*?)/objects/info/packs$"), "GET", getInfoPacks}, - {regexp.MustCompile("(.*?)/objects/info/[^/]*$"), "GET", getTextFile}, - {regexp.MustCompile("(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$"), "GET", getLooseObject}, - {regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$"), "GET", getPackFile}, - {regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$"), "GET", getIdxFile}, -} - -func getGitRepoPath(dir string) (string, error) { - if !strings.HasSuffix(dir, ".git") { - dir += ".git" - } - - filename := path.Join(setting.RepoRootPath, dir) - if _, err := os.Stat(filename); os.IsNotExist(err) { - return "", err - } - - return filename, nil -} - -func HTTP(c *HTTPContext) { - for _, route := range routes { - reqPath := strings.ToLower(c.Req.URL.Path) - m := route.reg.FindStringSubmatch(reqPath) - if m == nil { - continue - } - - // We perform check here because routes matched in cmd/web.go is wider than needed, - // but we only want to output this message only if user is really trying to access - // Git HTTP endpoints. - if setting.Repository.DisableHTTPGit { - c.HandleText(http.StatusForbidden, "Interacting with repositories by HTTP protocol is not disabled") - return - } - - if route.method != c.Req.Method { - c.NotFound() - return - } - - file := strings.TrimPrefix(reqPath, m[1]+"/") - dir, err := getGitRepoPath(m[1]) - if err != nil { - log.Warn("HTTP.getGitRepoPath: %v", err) - c.NotFound() - return - } - - route.handler(serviceHandler{ - w: c.Resp, - r: c.Req.Request, - dir: dir, - file: file, - - authUser: c.AuthUser, - ownerName: c.OwnerName, - ownerSalt: c.OwnerSalt, - repoID: c.RepoID, - repoName: c.RepoName, - }) - return - } - - c.NotFound() -} diff --git a/routers/repo/issue.go b/routers/repo/issue.go deleted file mode 100644 index 8920bc32..00000000 --- a/routers/repo/issue.go +++ /dev/null @@ -1,1263 +0,0 @@ -// 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 repo - -import ( - "fmt" - "io" - "io/ioutil" - "net/http" - "net/url" - "strings" - "time" - - "github.com/Unknwon/com" - "github.com/Unknwon/paginater" - log "gopkg.in/clog.v1" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/markup" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/pkg/tool" -) - -const ( - ISSUES = "repo/issue/list" - ISSUE_NEW = "repo/issue/new" - ISSUE_VIEW = "repo/issue/view" - - LABELS = "repo/issue/labels" - - MILESTONE = "repo/issue/milestones" - MILESTONE_NEW = "repo/issue/milestone_new" - MILESTONE_EDIT = "repo/issue/milestone_edit" - - ISSUE_TEMPLATE_KEY = "IssueTemplate" -) - -var ( - ErrFileTypeForbidden = errors.New("File type is not allowed") - ErrTooManyFiles = errors.New("Maximum number of files to upload exceeded") - - IssueTemplateCandidates = []string{ - "ISSUE_TEMPLATE.md", - ".gogs/ISSUE_TEMPLATE.md", - ".github/ISSUE_TEMPLATE.md", - } -) - -func MustEnableIssues(c *context.Context) { - if !c.Repo.Repository.EnableIssues { - c.Handle(404, "MustEnableIssues", nil) - return - } - - if c.Repo.Repository.EnableExternalTracker { - c.Redirect(c.Repo.Repository.ExternalTrackerURL) - return - } -} - -func MustAllowPulls(c *context.Context) { - if !c.Repo.Repository.AllowsPulls() { - c.Handle(404, "MustAllowPulls", nil) - return - } - - // User can send pull request if owns a forked repository. - if c.IsLogged && c.User.HasForkedRepo(c.Repo.Repository.ID) { - c.Repo.PullRequest.Allowed = true - c.Repo.PullRequest.HeadInfo = c.User.Name + ":" + c.Repo.BranchName - } -} - -func RetrieveLabels(c *context.Context) { - labels, err := models.GetLabelsByRepoID(c.Repo.Repository.ID) - if err != nil { - c.Handle(500, "RetrieveLabels.GetLabels", err) - return - } - for _, l := range labels { - l.CalOpenIssues() - } - c.Data["Labels"] = labels - c.Data["NumLabels"] = len(labels) -} - -func issues(c *context.Context, isPullList bool) { - if isPullList { - MustAllowPulls(c) - if c.Written() { - return - } - c.Data["Title"] = c.Tr("repo.pulls") - c.Data["PageIsPullList"] = true - - } else { - MustEnableIssues(c) - if c.Written() { - return - } - c.Data["Title"] = c.Tr("repo.issues") - c.Data["PageIsIssueList"] = true - } - - viewType := c.Query("type") - sortType := c.Query("sort") - types := []string{"assigned", "created_by", "mentioned"} - if !com.IsSliceContainsStr(types, viewType) { - viewType = "all" - } - - // Must sign in to see issues about you. - if viewType != "all" && !c.IsLogged { - c.SetCookie("redirect_to", "/"+url.QueryEscape(setting.AppSubURL+c.Req.RequestURI), 0, setting.AppSubURL) - c.Redirect(setting.AppSubURL + "/user/login") - return - } - - var ( - assigneeID = c.QueryInt64("assignee") - posterID int64 - ) - filterMode := models.FILTER_MODE_YOUR_REPOS - switch viewType { - case "assigned": - filterMode = models.FILTER_MODE_ASSIGN - assigneeID = c.User.ID - case "created_by": - filterMode = models.FILTER_MODE_CREATE - posterID = c.User.ID - case "mentioned": - filterMode = models.FILTER_MODE_MENTION - } - - var uid int64 = -1 - if c.IsLogged { - uid = c.User.ID - } - - repo := c.Repo.Repository - selectLabels := c.Query("labels") - milestoneID := c.QueryInt64("milestone") - isShowClosed := c.Query("state") == "closed" - issueStats := models.GetIssueStats(&models.IssueStatsOptions{ - RepoID: repo.ID, - UserID: uid, - Labels: selectLabels, - MilestoneID: milestoneID, - AssigneeID: assigneeID, - FilterMode: filterMode, - IsPull: isPullList, - }) - - page := c.QueryInt("page") - if page <= 1 { - page = 1 - } - - var total int - if !isShowClosed { - total = int(issueStats.OpenCount) - } else { - total = int(issueStats.ClosedCount) - } - pager := paginater.New(total, setting.UI.IssuePagingNum, page, 5) - c.Data["Page"] = pager - - issues, err := models.Issues(&models.IssuesOptions{ - UserID: uid, - AssigneeID: assigneeID, - RepoID: repo.ID, - PosterID: posterID, - MilestoneID: milestoneID, - Page: pager.Current(), - IsClosed: isShowClosed, - IsMention: filterMode == models.FILTER_MODE_MENTION, - IsPull: isPullList, - Labels: selectLabels, - SortType: sortType, - }) - if err != nil { - c.Handle(500, "Issues", err) - return - } - - // Get issue-user relations. - pairs, err := models.GetIssueUsers(repo.ID, posterID, isShowClosed) - if err != nil { - c.Handle(500, "GetIssueUsers", err) - return - } - - // Get posters. - for i := range issues { - if !c.IsLogged { - issues[i].IsRead = true - continue - } - - // Check read status. - idx := models.PairsContains(pairs, issues[i].ID, c.User.ID) - if idx > -1 { - issues[i].IsRead = pairs[idx].IsRead - } else { - issues[i].IsRead = true - } - } - c.Data["Issues"] = issues - - // Get milestones. - c.Data["Milestones"], err = models.GetMilestonesByRepoID(repo.ID) - if err != nil { - c.Handle(500, "GetAllRepoMilestones", err) - return - } - - // Get assignees. - c.Data["Assignees"], err = repo.GetAssignees() - if err != nil { - c.Handle(500, "GetAssignees", err) - return - } - - if viewType == "assigned" { - assigneeID = 0 // Reset ID to prevent unexpected selection of assignee. - } - - c.Data["IssueStats"] = issueStats - c.Data["SelectLabels"] = com.StrTo(selectLabels).MustInt64() - c.Data["ViewType"] = viewType - c.Data["SortType"] = sortType - c.Data["MilestoneID"] = milestoneID - c.Data["AssigneeID"] = assigneeID - c.Data["IsShowClosed"] = isShowClosed - if isShowClosed { - c.Data["State"] = "closed" - } else { - c.Data["State"] = "open" - } - - c.HTML(200, ISSUES) -} - -func Issues(c *context.Context) { - issues(c, false) -} - -func Pulls(c *context.Context) { - issues(c, true) -} - -func renderAttachmentSettings(c *context.Context) { - c.Data["RequireDropzone"] = true - c.Data["IsAttachmentEnabled"] = setting.AttachmentEnabled - c.Data["AttachmentAllowedTypes"] = setting.AttachmentAllowedTypes - c.Data["AttachmentMaxSize"] = setting.AttachmentMaxSize - c.Data["AttachmentMaxFiles"] = setting.AttachmentMaxFiles -} - -func RetrieveRepoMilestonesAndAssignees(c *context.Context, repo *models.Repository) { - var err error - c.Data["OpenMilestones"], err = models.GetMilestones(repo.ID, -1, false) - if err != nil { - c.Handle(500, "GetMilestones", err) - return - } - c.Data["ClosedMilestones"], err = models.GetMilestones(repo.ID, -1, true) - if err != nil { - c.Handle(500, "GetMilestones", err) - return - } - - c.Data["Assignees"], err = repo.GetAssignees() - if err != nil { - c.Handle(500, "GetAssignees", err) - return - } -} - -func RetrieveRepoMetas(c *context.Context, repo *models.Repository) []*models.Label { - if !c.Repo.IsWriter() { - return nil - } - - labels, err := models.GetLabelsByRepoID(repo.ID) - if err != nil { - c.Handle(500, "GetLabelsByRepoID", err) - return nil - } - c.Data["Labels"] = labels - - RetrieveRepoMilestonesAndAssignees(c, repo) - if c.Written() { - return nil - } - - return labels -} - -func getFileContentFromDefaultBranch(c *context.Context, filename string) (string, bool) { - var r io.Reader - var bytes []byte - - if c.Repo.Commit == nil { - var err error - c.Repo.Commit, err = c.Repo.GitRepo.GetBranchCommit(c.Repo.Repository.DefaultBranch) - if err != nil { - return "", false - } - } - - entry, err := c.Repo.Commit.GetTreeEntryByPath(filename) - if err != nil { - return "", false - } - r, err = entry.Blob().Data() - if err != nil { - return "", false - } - bytes, err = ioutil.ReadAll(r) - if err != nil { - return "", false - } - return string(bytes), true -} - -func setTemplateIfExists(c *context.Context, ctxDataKey string, possibleFiles []string) { - for _, filename := range possibleFiles { - content, found := getFileContentFromDefaultBranch(c, filename) - if found { - c.Data[ctxDataKey] = content - return - } - } -} - -func NewIssue(c *context.Context) { - c.Data["Title"] = c.Tr("repo.issues.new") - c.Data["PageIsIssueList"] = true - c.Data["RequireHighlightJS"] = true - c.Data["RequireSimpleMDE"] = true - setTemplateIfExists(c, ISSUE_TEMPLATE_KEY, IssueTemplateCandidates) - renderAttachmentSettings(c) - - RetrieveRepoMetas(c, c.Repo.Repository) - if c.Written() { - return - } - - c.HTML(200, ISSUE_NEW) -} - -func ValidateRepoMetas(c *context.Context, f form.NewIssue) ([]int64, int64, int64) { - var ( - repo = c.Repo.Repository - err error - ) - - labels := RetrieveRepoMetas(c, c.Repo.Repository) - if c.Written() { - return nil, 0, 0 - } - - if !c.Repo.IsWriter() { - return nil, 0, 0 - } - - // Check labels. - labelIDs := tool.StringsToInt64s(strings.Split(f.LabelIDs, ",")) - labelIDMark := tool.Int64sToMap(labelIDs) - hasSelected := false - for i := range labels { - if labelIDMark[labels[i].ID] { - labels[i].IsChecked = true - hasSelected = true - } - } - c.Data["HasSelectedLabel"] = hasSelected - c.Data["label_ids"] = f.LabelIDs - c.Data["Labels"] = labels - - // Check milestone. - milestoneID := f.MilestoneID - if milestoneID > 0 { - c.Data["Milestone"], err = repo.GetMilestoneByID(milestoneID) - if err != nil { - c.Handle(500, "GetMilestoneByID", err) - return nil, 0, 0 - } - c.Data["milestone_id"] = milestoneID - } - - // Check assignee. - assigneeID := f.AssigneeID - if assigneeID > 0 { - c.Data["Assignee"], err = repo.GetAssigneeByID(assigneeID) - if err != nil { - c.Handle(500, "GetAssigneeByID", err) - return nil, 0, 0 - } - c.Data["assignee_id"] = assigneeID - } - - return labelIDs, milestoneID, assigneeID -} - -func NewIssuePost(c *context.Context, f form.NewIssue) { - c.Data["Title"] = c.Tr("repo.issues.new") - c.Data["PageIsIssueList"] = true - c.Data["RequireHighlightJS"] = true - c.Data["RequireSimpleMDE"] = true - renderAttachmentSettings(c) - - labelIDs, milestoneID, assigneeID := ValidateRepoMetas(c, f) - if c.Written() { - return - } - - if c.HasError() { - c.HTML(200, ISSUE_NEW) - return - } - - var attachments []string - if setting.AttachmentEnabled { - attachments = f.Files - } - - issue := &models.Issue{ - RepoID: c.Repo.Repository.ID, - Title: f.Title, - PosterID: c.User.ID, - Poster: c.User, - MilestoneID: milestoneID, - AssigneeID: assigneeID, - Content: f.Content, - } - if err := models.NewIssue(c.Repo.Repository, issue, labelIDs, attachments); err != nil { - c.Handle(500, "NewIssue", err) - return - } - - log.Trace("Issue created: %d/%d", c.Repo.Repository.ID, issue.ID) - c.Redirect(c.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index)) -} - -func uploadAttachment(c *context.Context, allowedTypes []string) { - file, header, err := c.Req.FormFile("file") - if err != nil { - c.Error(500, fmt.Sprintf("FormFile: %v", err)) - return - } - defer file.Close() - - buf := make([]byte, 1024) - n, _ := file.Read(buf) - if n > 0 { - buf = buf[:n] - } - fileType := http.DetectContentType(buf) - - allowed := false - for _, t := range allowedTypes { - t := strings.Trim(t, " ") - if t == "*/*" || t == fileType { - allowed = true - break - } - } - - if !allowed { - c.Error(400, ErrFileTypeForbidden.Error()) - return - } - - attach, err := models.NewAttachment(header.Filename, buf, file) - if err != nil { - c.Error(500, fmt.Sprintf("NewAttachment: %v", err)) - return - } - - log.Trace("New attachment uploaded: %s", attach.UUID) - c.JSON(200, map[string]string{ - "uuid": attach.UUID, - }) -} - -func UploadIssueAttachment(c *context.Context) { - if !setting.AttachmentEnabled { - c.NotFound() - return - } - - uploadAttachment(c, strings.Split(setting.AttachmentAllowedTypes, ",")) -} - -func viewIssue(c *context.Context, isPullList bool) { - c.Data["RequireHighlightJS"] = true - c.Data["RequireDropzone"] = true - renderAttachmentSettings(c) - - index := c.ParamsInt64(":index") - if index <= 0 { - c.NotFound() - return - } - - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, index) - if err != nil { - c.NotFoundOrServerError("GetIssueByIndex", errors.IsIssueNotExist, err) - return - } - c.Data["Title"] = issue.Title - - // Make sure type and URL matches. - if !isPullList && issue.IsPull { - c.Redirect(c.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index)) - return - } else if isPullList && !issue.IsPull { - c.Redirect(c.Repo.RepoLink + "/issues/" + com.ToStr(issue.Index)) - return - } - - if issue.IsPull { - MustAllowPulls(c) - if c.Written() { - return - } - c.Data["PageIsPullList"] = true - c.Data["PageIsPullConversation"] = true - } else { - MustEnableIssues(c) - if c.Written() { - return - } - c.Data["PageIsIssueList"] = true - } - - issue.RenderedContent = string(markup.Markdown(issue.Content, c.Repo.RepoLink, c.Repo.Repository.ComposeMetas())) - - repo := c.Repo.Repository - - // Get more information if it's a pull request. - if issue.IsPull { - if issue.PullRequest.HasMerged { - c.Data["DisableStatusChange"] = issue.PullRequest.HasMerged - PrepareMergedViewPullInfo(c, issue) - } else { - PrepareViewPullInfo(c, issue) - } - if c.Written() { - return - } - } - - // Metas. - // Check labels. - labelIDMark := make(map[int64]bool) - for i := range issue.Labels { - labelIDMark[issue.Labels[i].ID] = true - } - labels, err := models.GetLabelsByRepoID(repo.ID) - if err != nil { - c.Handle(500, "GetLabelsByRepoID", err) - return - } - hasSelected := false - for i := range labels { - if labelIDMark[labels[i].ID] { - labels[i].IsChecked = true - hasSelected = true - } - } - c.Data["HasSelectedLabel"] = hasSelected - c.Data["Labels"] = labels - - // Check milestone and assignee. - if c.Repo.IsWriter() { - RetrieveRepoMilestonesAndAssignees(c, repo) - if c.Written() { - return - } - } - - if c.IsLogged { - // Update issue-user. - if err = issue.ReadBy(c.User.ID); err != nil { - c.Handle(500, "ReadBy", err) - return - } - } - - var ( - tag models.CommentTag - ok bool - marked = make(map[int64]models.CommentTag) - comment *models.Comment - participants = make([]*models.User, 1, 10) - ) - - // Render comments and and fetch participants. - participants[0] = issue.Poster - for _, comment = range issue.Comments { - if comment.Type == models.COMMENT_TYPE_COMMENT { - comment.RenderedContent = string(markup.Markdown(comment.Content, c.Repo.RepoLink, c.Repo.Repository.ComposeMetas())) - - // Check tag. - tag, ok = marked[comment.PosterID] - if ok { - comment.ShowTag = tag - continue - } - - if repo.IsOwnedBy(comment.PosterID) || - (repo.Owner.IsOrganization() && repo.Owner.IsOwnedBy(comment.PosterID)) { - comment.ShowTag = models.COMMENT_TAG_OWNER - } else if comment.Poster.IsWriterOfRepo(repo) { - comment.ShowTag = models.COMMENT_TAG_WRITER - } else if comment.PosterID == issue.PosterID { - comment.ShowTag = models.COMMENT_TAG_POSTER - } - - marked[comment.PosterID] = comment.ShowTag - - isAdded := false - for j := range participants { - if comment.Poster == participants[j] { - isAdded = true - break - } - } - if !isAdded && !issue.IsPoster(comment.Poster.ID) { - participants = append(participants, comment.Poster) - } - } - } - - if issue.IsPull && issue.PullRequest.HasMerged { - pull := issue.PullRequest - c.Data["IsPullBranchDeletable"] = pull.BaseRepoID == pull.HeadRepoID && - c.Repo.IsWriter() && c.Repo.GitRepo.IsBranchExist(pull.HeadBranch) - - deleteBranchUrl := c.Repo.RepoLink + "/branches/delete/" + pull.HeadBranch - c.Data["DeleteBranchLink"] = fmt.Sprintf("%s?commit=%s&redirect_to=%s", deleteBranchUrl, pull.MergedCommitID, c.Data["Link"]) - } - - c.Data["Participants"] = participants - c.Data["NumParticipants"] = len(participants) - c.Data["Issue"] = issue - c.Data["IsIssueOwner"] = c.Repo.IsWriter() || (c.IsLogged && issue.IsPoster(c.User.ID)) - c.Data["SignInLink"] = setting.AppSubURL + "/user/login?redirect_to=" + c.Data["Link"].(string) - c.HTML(200, ISSUE_VIEW) -} - -func ViewIssue(c *context.Context) { - viewIssue(c, false) -} - -func ViewPull(c *context.Context) { - viewIssue(c, true) -} - -func getActionIssue(c *context.Context) *models.Issue { - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - c.NotFoundOrServerError("GetIssueByIndex", errors.IsIssueNotExist, err) - return nil - } - - // Prevent guests accessing pull requests - if !c.Repo.HasAccess() && issue.IsPull { - c.NotFound() - return nil - } - - return issue -} - -func UpdateIssueTitle(c *context.Context) { - issue := getActionIssue(c) - if c.Written() { - return - } - - if !c.IsLogged || (!issue.IsPoster(c.User.ID) && !c.Repo.IsWriter()) { - c.Error(403) - return - } - - title := c.QueryTrim("title") - if len(title) == 0 { - c.Error(204) - return - } - - if err := issue.ChangeTitle(c.User, title); err != nil { - c.Handle(500, "ChangeTitle", err) - return - } - - c.JSON(200, map[string]interface{}{ - "title": issue.Title, - }) -} - -func UpdateIssueContent(c *context.Context) { - issue := getActionIssue(c) - if c.Written() { - return - } - - if !c.IsLogged || (c.User.ID != issue.PosterID && !c.Repo.IsWriter()) { - c.Error(403) - return - } - - content := c.Query("content") - if err := issue.ChangeContent(c.User, content); err != nil { - c.Handle(500, "ChangeContent", err) - return - } - - c.JSON(200, map[string]string{ - "content": string(markup.Markdown(issue.Content, c.Query("context"), c.Repo.Repository.ComposeMetas())), - }) -} - -func UpdateIssueLabel(c *context.Context) { - issue := getActionIssue(c) - if c.Written() { - return - } - - if c.Query("action") == "clear" { - if err := issue.ClearLabels(c.User); err != nil { - c.Handle(500, "ClearLabels", err) - return - } - } else { - isAttach := c.Query("action") == "attach" - label, err := models.GetLabelOfRepoByID(c.Repo.Repository.ID, c.QueryInt64("id")) - if err != nil { - if models.IsErrLabelNotExist(err) { - c.Error(404, "GetLabelByID") - } else { - c.Handle(500, "GetLabelByID", err) - } - return - } - - if isAttach && !issue.HasLabel(label.ID) { - if err = issue.AddLabel(c.User, label); err != nil { - c.Handle(500, "AddLabel", err) - return - } - } else if !isAttach && issue.HasLabel(label.ID) { - if err = issue.RemoveLabel(c.User, label); err != nil { - c.Handle(500, "RemoveLabel", err) - return - } - } - } - - c.JSON(200, map[string]interface{}{ - "ok": true, - }) -} - -func UpdateIssueMilestone(c *context.Context) { - issue := getActionIssue(c) - if c.Written() { - return - } - - oldMilestoneID := issue.MilestoneID - milestoneID := c.QueryInt64("id") - if oldMilestoneID == milestoneID { - c.JSON(200, map[string]interface{}{ - "ok": true, - }) - return - } - - // Not check for invalid milestone id and give responsibility to owners. - issue.MilestoneID = milestoneID - if err := models.ChangeMilestoneAssign(c.User, issue, oldMilestoneID); err != nil { - c.Handle(500, "ChangeMilestoneAssign", err) - return - } - - c.JSON(200, map[string]interface{}{ - "ok": true, - }) -} - -func UpdateIssueAssignee(c *context.Context) { - issue := getActionIssue(c) - if c.Written() { - return - } - - assigneeID := c.QueryInt64("id") - if issue.AssigneeID == assigneeID { - c.JSON(200, map[string]interface{}{ - "ok": true, - }) - return - } - - if err := issue.ChangeAssignee(c.User, assigneeID); err != nil { - c.Handle(500, "ChangeAssignee", err) - return - } - - c.JSON(200, map[string]interface{}{ - "ok": true, - }) -} - -func NewComment(c *context.Context, f form.CreateComment) { - issue := getActionIssue(c) - if c.Written() { - return - } - - var attachments []string - if setting.AttachmentEnabled { - attachments = f.Files - } - - if c.HasError() { - c.Flash.Error(c.Data["ErrorMsg"].(string)) - c.Redirect(fmt.Sprintf("%s/issues/%d", c.Repo.RepoLink, issue.Index)) - return - } - - var err error - var comment *models.Comment - defer func() { - // Check if issue admin/poster changes the status of issue. - if (c.Repo.IsWriter() || (c.IsLogged && issue.IsPoster(c.User.ID))) && - (f.Status == "reopen" || f.Status == "close") && - !(issue.IsPull && issue.PullRequest.HasMerged) { - - // Duplication and conflict check should apply to reopen pull request. - var pr *models.PullRequest - - if f.Status == "reopen" && issue.IsPull { - pull := issue.PullRequest - pr, err = models.GetUnmergedPullRequest(pull.HeadRepoID, pull.BaseRepoID, pull.HeadBranch, pull.BaseBranch) - if err != nil { - if !models.IsErrPullRequestNotExist(err) { - c.ServerError("GetUnmergedPullRequest", err) - return - } - } - - // Regenerate patch and test conflict. - if pr == nil { - if err = issue.PullRequest.UpdatePatch(); err != nil { - c.ServerError("UpdatePatch", err) - return - } - - issue.PullRequest.AddToTaskQueue() - } - } - - if pr != nil { - c.Flash.Info(c.Tr("repo.pulls.open_unmerged_pull_exists", pr.Index)) - } else { - if err = issue.ChangeStatus(c.User, c.Repo.Repository, f.Status == "close"); err != nil { - log.Error(2, "ChangeStatus: %v", err) - } else { - log.Trace("Issue [%d] status changed to closed: %v", issue.ID, issue.IsClosed) - } - } - } - - // Redirect to comment hashtag if there is any actual content. - typeName := "issues" - if issue.IsPull { - typeName = "pulls" - } - if comment != nil { - c.Redirect(fmt.Sprintf("%s/%s/%d#%s", c.Repo.RepoLink, typeName, issue.Index, comment.HashTag())) - } else { - c.Redirect(fmt.Sprintf("%s/%s/%d", c.Repo.RepoLink, typeName, issue.Index)) - } - }() - - // Fix #321: Allow empty comments, as long as we have attachments. - if len(f.Content) == 0 && len(attachments) == 0 { - return - } - - comment, err = models.CreateIssueComment(c.User, c.Repo.Repository, issue, f.Content, attachments) - if err != nil { - c.ServerError("CreateIssueComment", err) - return - } - - log.Trace("Comment created: %d/%d/%d", c.Repo.Repository.ID, issue.ID, comment.ID) -} - -func UpdateCommentContent(c *context.Context) { - comment, err := models.GetCommentByID(c.ParamsInt64(":id")) - if err != nil { - c.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err) - return - } - - if c.UserID() != comment.PosterID && !c.Repo.IsAdmin() { - c.Error(404) - return - } else if comment.Type != models.COMMENT_TYPE_COMMENT { - c.Error(204) - return - } - - oldContent := comment.Content - comment.Content = c.Query("content") - if len(comment.Content) == 0 { - c.JSON(200, map[string]interface{}{ - "content": "", - }) - return - } - if err = models.UpdateComment(c.User, comment, oldContent); err != nil { - c.Handle(500, "UpdateComment", err) - return - } - - c.JSON(200, map[string]string{ - "content": string(markup.Markdown(comment.Content, c.Query("context"), c.Repo.Repository.ComposeMetas())), - }) -} - -func DeleteComment(c *context.Context) { - comment, err := models.GetCommentByID(c.ParamsInt64(":id")) - if err != nil { - c.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err) - return - } - - if c.UserID() != comment.PosterID && !c.Repo.IsAdmin() { - c.Error(404) - return - } else if comment.Type != models.COMMENT_TYPE_COMMENT { - c.Error(204) - return - } - - if err = models.DeleteCommentByID(c.User, comment.ID); err != nil { - c.Handle(500, "DeleteCommentByID", err) - return - } - - c.Status(200) -} - -func Labels(c *context.Context) { - c.Data["Title"] = c.Tr("repo.labels") - c.Data["PageIsIssueList"] = true - c.Data["PageIsLabels"] = true - c.Data["RequireMinicolors"] = true - c.Data["LabelTemplates"] = models.LabelTemplates - c.HTML(200, LABELS) -} - -func InitializeLabels(c *context.Context, f form.InitializeLabels) { - if c.HasError() { - c.Redirect(c.Repo.RepoLink + "/labels") - return - } - list, err := models.GetLabelTemplateFile(f.TemplateName) - if err != nil { - c.Flash.Error(c.Tr("repo.issues.label_templates.fail_to_load_file", f.TemplateName, err)) - c.Redirect(c.Repo.RepoLink + "/labels") - return - } - - labels := make([]*models.Label, len(list)) - for i := 0; i < len(list); i++ { - labels[i] = &models.Label{ - RepoID: c.Repo.Repository.ID, - Name: list[i][0], - Color: list[i][1], - } - } - if err := models.NewLabels(labels...); err != nil { - c.Handle(500, "NewLabels", err) - return - } - c.Redirect(c.Repo.RepoLink + "/labels") -} - -func NewLabel(c *context.Context, f form.CreateLabel) { - c.Data["Title"] = c.Tr("repo.labels") - c.Data["PageIsLabels"] = true - - if c.HasError() { - c.Flash.Error(c.Data["ErrorMsg"].(string)) - c.Redirect(c.Repo.RepoLink + "/labels") - return - } - - l := &models.Label{ - RepoID: c.Repo.Repository.ID, - Name: f.Title, - Color: f.Color, - } - if err := models.NewLabels(l); err != nil { - c.Handle(500, "NewLabel", err) - return - } - c.Redirect(c.Repo.RepoLink + "/labels") -} - -func UpdateLabel(c *context.Context, f form.CreateLabel) { - l, err := models.GetLabelByID(f.ID) - if err != nil { - switch { - case models.IsErrLabelNotExist(err): - c.Error(404) - default: - c.Handle(500, "UpdateLabel", err) - } - return - } - - l.Name = f.Title - l.Color = f.Color - if err := models.UpdateLabel(l); err != nil { - c.Handle(500, "UpdateLabel", err) - return - } - c.Redirect(c.Repo.RepoLink + "/labels") -} - -func DeleteLabel(c *context.Context) { - if err := models.DeleteLabel(c.Repo.Repository.ID, c.QueryInt64("id")); err != nil { - c.Flash.Error("DeleteLabel: " + err.Error()) - } else { - c.Flash.Success(c.Tr("repo.issues.label_deletion_success")) - } - - c.JSON(200, map[string]interface{}{ - "redirect": c.Repo.RepoLink + "/labels", - }) - return -} - -func Milestones(c *context.Context) { - c.Data["Title"] = c.Tr("repo.milestones") - c.Data["PageIsIssueList"] = true - c.Data["PageIsMilestones"] = true - - isShowClosed := c.Query("state") == "closed" - openCount, closedCount := models.MilestoneStats(c.Repo.Repository.ID) - c.Data["OpenCount"] = openCount - c.Data["ClosedCount"] = closedCount - - page := c.QueryInt("page") - if page <= 1 { - page = 1 - } - - var total int - if !isShowClosed { - total = int(openCount) - } else { - total = int(closedCount) - } - c.Data["Page"] = paginater.New(total, setting.UI.IssuePagingNum, page, 5) - - miles, err := models.GetMilestones(c.Repo.Repository.ID, page, isShowClosed) - if err != nil { - c.Handle(500, "GetMilestones", err) - return - } - for _, m := range miles { - m.NumOpenIssues = int(m.CountIssues(false, false)) - m.NumClosedIssues = int(m.CountIssues(true, false)) - if m.NumOpenIssues+m.NumClosedIssues > 0 { - m.Completeness = m.NumClosedIssues * 100 / (m.NumOpenIssues + m.NumClosedIssues) - } - m.RenderedContent = string(markup.Markdown(m.Content, c.Repo.RepoLink, c.Repo.Repository.ComposeMetas())) - } - c.Data["Milestones"] = miles - - if isShowClosed { - c.Data["State"] = "closed" - } else { - c.Data["State"] = "open" - } - - c.Data["IsShowClosed"] = isShowClosed - c.HTML(200, MILESTONE) -} - -func NewMilestone(c *context.Context) { - c.Data["Title"] = c.Tr("repo.milestones.new") - c.Data["PageIsIssueList"] = true - c.Data["PageIsMilestones"] = true - c.Data["RequireDatetimepicker"] = true - c.Data["DateLang"] = setting.DateLang(c.Locale.Language()) - c.HTML(200, MILESTONE_NEW) -} - -func NewMilestonePost(c *context.Context, f form.CreateMilestone) { - c.Data["Title"] = c.Tr("repo.milestones.new") - c.Data["PageIsIssueList"] = true - c.Data["PageIsMilestones"] = true - c.Data["RequireDatetimepicker"] = true - c.Data["DateLang"] = setting.DateLang(c.Locale.Language()) - - if c.HasError() { - c.HTML(200, MILESTONE_NEW) - return - } - - if len(f.Deadline) == 0 { - f.Deadline = "9999-12-31" - } - deadline, err := time.ParseInLocation("2006-01-02", f.Deadline, time.Local) - if err != nil { - c.Data["Err_Deadline"] = true - c.RenderWithErr(c.Tr("repo.milestones.invalid_due_date_format"), MILESTONE_NEW, &f) - return - } - - if err = models.NewMilestone(&models.Milestone{ - RepoID: c.Repo.Repository.ID, - Name: f.Title, - Content: f.Content, - Deadline: deadline, - }); err != nil { - c.Handle(500, "NewMilestone", err) - return - } - - c.Flash.Success(c.Tr("repo.milestones.create_success", f.Title)) - c.Redirect(c.Repo.RepoLink + "/milestones") -} - -func EditMilestone(c *context.Context) { - c.Data["Title"] = c.Tr("repo.milestones.edit") - c.Data["PageIsMilestones"] = true - c.Data["PageIsEditMilestone"] = true - c.Data["RequireDatetimepicker"] = true - c.Data["DateLang"] = setting.DateLang(c.Locale.Language()) - - m, err := models.GetMilestoneByRepoID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - if err != nil { - if models.IsErrMilestoneNotExist(err) { - c.Handle(404, "", nil) - } else { - c.Handle(500, "GetMilestoneByRepoID", err) - } - return - } - c.Data["title"] = m.Name - c.Data["content"] = m.Content - if len(m.DeadlineString) > 0 { - c.Data["deadline"] = m.DeadlineString - } - c.HTML(200, MILESTONE_NEW) -} - -func EditMilestonePost(c *context.Context, f form.CreateMilestone) { - c.Data["Title"] = c.Tr("repo.milestones.edit") - c.Data["PageIsMilestones"] = true - c.Data["PageIsEditMilestone"] = true - c.Data["RequireDatetimepicker"] = true - c.Data["DateLang"] = setting.DateLang(c.Locale.Language()) - - if c.HasError() { - c.HTML(200, MILESTONE_NEW) - return - } - - if len(f.Deadline) == 0 { - f.Deadline = "9999-12-31" - } - deadline, err := time.ParseInLocation("2006-01-02", f.Deadline, time.Local) - if err != nil { - c.Data["Err_Deadline"] = true - c.RenderWithErr(c.Tr("repo.milestones.invalid_due_date_format"), MILESTONE_NEW, &f) - return - } - - m, err := models.GetMilestoneByRepoID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - if err != nil { - if models.IsErrMilestoneNotExist(err) { - c.Handle(404, "", nil) - } else { - c.Handle(500, "GetMilestoneByRepoID", err) - } - return - } - m.Name = f.Title - m.Content = f.Content - m.Deadline = deadline - if err = models.UpdateMilestone(m); err != nil { - c.Handle(500, "UpdateMilestone", err) - return - } - - c.Flash.Success(c.Tr("repo.milestones.edit_success", m.Name)) - c.Redirect(c.Repo.RepoLink + "/milestones") -} - -func ChangeMilestonStatus(c *context.Context) { - m, err := models.GetMilestoneByRepoID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - if err != nil { - if models.IsErrMilestoneNotExist(err) { - c.Handle(404, "", err) - } else { - c.Handle(500, "GetMilestoneByRepoID", err) - } - return - } - - switch c.Params(":action") { - case "open": - if m.IsClosed { - if err = models.ChangeMilestoneStatus(m, false); err != nil { - c.Handle(500, "ChangeMilestoneStatus", err) - return - } - } - c.Redirect(c.Repo.RepoLink + "/milestones?state=open") - case "close": - if !m.IsClosed { - m.ClosedDate = time.Now() - if err = models.ChangeMilestoneStatus(m, true); err != nil { - c.Handle(500, "ChangeMilestoneStatus", err) - return - } - } - c.Redirect(c.Repo.RepoLink + "/milestones?state=closed") - default: - c.Redirect(c.Repo.RepoLink + "/milestones") - } -} - -func DeleteMilestone(c *context.Context) { - if err := models.DeleteMilestoneOfRepoByID(c.Repo.Repository.ID, c.QueryInt64("id")); err != nil { - c.Flash.Error("DeleteMilestoneByRepoID: " + err.Error()) - } else { - c.Flash.Success(c.Tr("repo.milestones.deletion_success")) - } - - c.JSON(200, map[string]interface{}{ - "redirect": c.Repo.RepoLink + "/milestones", - }) -} diff --git a/routers/repo/pull.go b/routers/repo/pull.go deleted file mode 100644 index 73757280..00000000 --- a/routers/repo/pull.go +++ /dev/null @@ -1,763 +0,0 @@ -// 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 repo - -import ( - "container/list" - "path" - "strings" - - "github.com/Unknwon/com" - log "gopkg.in/clog.v1" - - "github.com/gogits/git-module" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/pkg/tool" -) - -const ( - FORK = "repo/pulls/fork" - COMPARE_PULL = "repo/pulls/compare" - PULL_COMMITS = "repo/pulls/commits" - PULL_FILES = "repo/pulls/files" - - PULL_REQUEST_TEMPLATE_KEY = "PullRequestTemplate" -) - -var ( - PullRequestTemplateCandidates = []string{ - "PULL_REQUEST.md", - ".gogs/PULL_REQUEST.md", - ".github/PULL_REQUEST.md", - } -) - -func parseBaseRepository(c *context.Context) *models.Repository { - baseRepo, err := models.GetRepositoryByID(c.ParamsInt64(":repoid")) - if err != nil { - c.NotFoundOrServerError("GetRepositoryByID", errors.IsRepoNotExist, err) - return nil - } - - if !baseRepo.CanBeForked() || !baseRepo.HasAccess(c.User.ID) { - c.NotFound() - return nil - } - - c.Data["repo_name"] = baseRepo.Name - c.Data["description"] = baseRepo.Description - c.Data["IsPrivate"] = baseRepo.IsPrivate - - if err = baseRepo.GetOwner(); err != nil { - c.ServerError("GetOwner", err) - return nil - } - c.Data["ForkFrom"] = baseRepo.Owner.Name + "/" + baseRepo.Name - - if err := c.User.GetOrganizations(true); err != nil { - c.ServerError("GetOrganizations", err) - return nil - } - c.Data["Orgs"] = c.User.Orgs - - return baseRepo -} - -func Fork(c *context.Context) { - c.Data["Title"] = c.Tr("new_fork") - - parseBaseRepository(c) - if c.Written() { - return - } - - c.Data["ContextUser"] = c.User - c.Success(FORK) -} - -func ForkPost(c *context.Context, f form.CreateRepo) { - c.Data["Title"] = c.Tr("new_fork") - - baseRepo := parseBaseRepository(c) - if c.Written() { - return - } - - ctxUser := checkContextUser(c, f.UserID) - if c.Written() { - return - } - c.Data["ContextUser"] = ctxUser - - if c.HasError() { - c.Success(FORK) - return - } - - repo, has := models.HasForkedRepo(ctxUser.ID, baseRepo.ID) - if has { - c.Redirect(repo.Link()) - return - } - - // Check ownership of organization. - if ctxUser.IsOrganization() && !ctxUser.IsOwnedBy(c.User.ID) { - c.Error(403) - return - } - - // Cannot fork to same owner - if ctxUser.ID == baseRepo.OwnerID { - c.RenderWithErr(c.Tr("repo.settings.cannot_fork_to_same_owner"), FORK, &f) - return - } - - repo, err := models.ForkRepository(c.User, ctxUser, baseRepo, f.RepoName, f.Description) - if err != nil { - c.Data["Err_RepoName"] = true - switch { - case models.IsErrRepoAlreadyExist(err): - c.RenderWithErr(c.Tr("repo.settings.new_owner_has_same_repo"), FORK, &f) - case models.IsErrNameReserved(err): - c.RenderWithErr(c.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), FORK, &f) - case models.IsErrNamePatternNotAllowed(err): - c.RenderWithErr(c.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), FORK, &f) - default: - c.ServerError("ForkPost", err) - } - return - } - - log.Trace("Repository forked from '%s' -> '%s'", baseRepo.FullName(), repo.FullName()) - c.Redirect(repo.Link()) -} - -func checkPullInfo(c *context.Context) *models.Issue { - issue, err := models.GetIssueByIndex(c.Repo.Repository.ID, c.ParamsInt64(":index")) - if err != nil { - c.NotFoundOrServerError("GetIssueByIndex", errors.IsIssueNotExist, err) - return nil - } - c.Data["Title"] = issue.Title - c.Data["Issue"] = issue - - if !issue.IsPull { - c.Handle(404, "ViewPullCommits", nil) - return nil - } - - if c.IsLogged { - // Update issue-user. - if err = issue.ReadBy(c.User.ID); err != nil { - c.ServerError("ReadBy", err) - return nil - } - } - - return issue -} - -func PrepareMergedViewPullInfo(c *context.Context, issue *models.Issue) { - pull := issue.PullRequest - c.Data["HasMerged"] = true - c.Data["HeadTarget"] = issue.PullRequest.HeadUserName + "/" + pull.HeadBranch - c.Data["BaseTarget"] = c.Repo.Owner.Name + "/" + pull.BaseBranch - - var err error - c.Data["NumCommits"], err = c.Repo.GitRepo.CommitsCountBetween(pull.MergeBase, pull.MergedCommitID) - if err != nil { - c.ServerError("Repo.GitRepo.CommitsCountBetween", err) - return - } - c.Data["NumFiles"], err = c.Repo.GitRepo.FilesCountBetween(pull.MergeBase, pull.MergedCommitID) - if err != nil { - c.ServerError("Repo.GitRepo.FilesCountBetween", err) - return - } -} - -func PrepareViewPullInfo(c *context.Context, issue *models.Issue) *git.PullRequestInfo { - repo := c.Repo.Repository - pull := issue.PullRequest - - c.Data["HeadTarget"] = pull.HeadUserName + "/" + pull.HeadBranch - c.Data["BaseTarget"] = c.Repo.Owner.Name + "/" + pull.BaseBranch - - var ( - headGitRepo *git.Repository - err error - ) - - if pull.HeadRepo != nil { - headGitRepo, err = git.OpenRepository(pull.HeadRepo.RepoPath()) - if err != nil { - c.ServerError("OpenRepository", err) - return nil - } - } - - if pull.HeadRepo == nil || !headGitRepo.IsBranchExist(pull.HeadBranch) { - c.Data["IsPullReuqestBroken"] = true - c.Data["HeadTarget"] = "deleted" - c.Data["NumCommits"] = 0 - c.Data["NumFiles"] = 0 - return nil - } - - prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(repo.Owner.Name, repo.Name), - pull.BaseBranch, pull.HeadBranch) - if err != nil { - if strings.Contains(err.Error(), "fatal: Not a valid object name") { - c.Data["IsPullReuqestBroken"] = true - c.Data["BaseTarget"] = "deleted" - c.Data["NumCommits"] = 0 - c.Data["NumFiles"] = 0 - return nil - } - - c.ServerError("GetPullRequestInfo", err) - return nil - } - c.Data["NumCommits"] = prInfo.Commits.Len() - c.Data["NumFiles"] = prInfo.NumFiles - return prInfo -} - -func ViewPullCommits(c *context.Context) { - c.Data["PageIsPullList"] = true - c.Data["PageIsPullCommits"] = true - - issue := checkPullInfo(c) - if c.Written() { - return - } - pull := issue.PullRequest - - if pull.HeadRepo != nil { - c.Data["Username"] = pull.HeadUserName - c.Data["Reponame"] = pull.HeadRepo.Name - } - - var commits *list.List - if pull.HasMerged { - PrepareMergedViewPullInfo(c, issue) - if c.Written() { - return - } - startCommit, err := c.Repo.GitRepo.GetCommit(pull.MergeBase) - if err != nil { - c.ServerError("Repo.GitRepo.GetCommit", err) - return - } - endCommit, err := c.Repo.GitRepo.GetCommit(pull.MergedCommitID) - if err != nil { - c.ServerError("Repo.GitRepo.GetCommit", err) - return - } - commits, err = c.Repo.GitRepo.CommitsBetween(endCommit, startCommit) - if err != nil { - c.ServerError("Repo.GitRepo.CommitsBetween", err) - return - } - - } else { - prInfo := PrepareViewPullInfo(c, issue) - if c.Written() { - return - } else if prInfo == nil { - c.Handle(404, "ViewPullCommits", nil) - return - } - commits = prInfo.Commits - } - - commits = models.ValidateCommitsWithEmails(commits) - c.Data["Commits"] = commits - c.Data["CommitsCount"] = commits.Len() - - c.Success(PULL_COMMITS) -} - -func ViewPullFiles(c *context.Context) { - c.Data["PageIsPullList"] = true - c.Data["PageIsPullFiles"] = true - - issue := checkPullInfo(c) - if c.Written() { - return - } - pull := issue.PullRequest - - var ( - diffRepoPath string - startCommitID string - endCommitID string - gitRepo *git.Repository - ) - - if pull.HasMerged { - PrepareMergedViewPullInfo(c, issue) - if c.Written() { - return - } - - diffRepoPath = c.Repo.GitRepo.Path - startCommitID = pull.MergeBase - endCommitID = pull.MergedCommitID - gitRepo = c.Repo.GitRepo - } else { - prInfo := PrepareViewPullInfo(c, issue) - if c.Written() { - return - } else if prInfo == nil { - c.Handle(404, "ViewPullFiles", nil) - return - } - - headRepoPath := models.RepoPath(pull.HeadUserName, pull.HeadRepo.Name) - - headGitRepo, err := git.OpenRepository(headRepoPath) - if err != nil { - c.ServerError("OpenRepository", err) - return - } - - headCommitID, err := headGitRepo.GetBranchCommitID(pull.HeadBranch) - if err != nil { - c.ServerError("GetBranchCommitID", err) - return - } - - diffRepoPath = headRepoPath - startCommitID = prInfo.MergeBase - endCommitID = headCommitID - gitRepo = headGitRepo - } - - diff, err := models.GetDiffRange(diffRepoPath, - startCommitID, endCommitID, setting.Git.MaxGitDiffLines, - setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles) - if err != nil { - c.ServerError("GetDiffRange", err) - return - } - c.Data["Diff"] = diff - c.Data["DiffNotAvailable"] = diff.NumFiles() == 0 - - commit, err := gitRepo.GetCommit(endCommitID) - if err != nil { - c.ServerError("GetCommit", err) - return - } - - setEditorconfigIfExists(c) - if c.Written() { - return - } - - c.Data["IsSplitStyle"] = c.Query("style") == "split" - c.Data["IsImageFile"] = commit.IsImageFile - - // It is possible head repo has been deleted for merged pull requests - if pull.HeadRepo != nil { - c.Data["Username"] = pull.HeadUserName - c.Data["Reponame"] = pull.HeadRepo.Name - - headTarget := path.Join(pull.HeadUserName, pull.HeadRepo.Name) - c.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", endCommitID) - c.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", startCommitID) - c.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", endCommitID) - } - - c.Data["RequireHighlightJS"] = true - c.Success(PULL_FILES) -} - -func MergePullRequest(c *context.Context) { - issue := checkPullInfo(c) - if c.Written() { - return - } - if issue.IsClosed { - c.Handle(404, "MergePullRequest", nil) - return - } - - pr, err := models.GetPullRequestByIssueID(issue.ID) - if err != nil { - c.NotFoundOrServerError("GetPullRequestByIssueID", models.IsErrPullRequestNotExist, err) - return - } - - if !pr.CanAutoMerge() || pr.HasMerged { - c.Handle(404, "MergePullRequest", nil) - return - } - - pr.Issue = issue - pr.Issue.Repo = c.Repo.Repository - if err = pr.Merge(c.User, c.Repo.GitRepo); err != nil { - c.ServerError("Merge", err) - return - } - - log.Trace("Pull request merged: %d", pr.ID) - c.Redirect(c.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index)) -} - -func ParseCompareInfo(c *context.Context) (*models.User, *models.Repository, *git.Repository, *git.PullRequestInfo, string, string) { - baseRepo := c.Repo.Repository - - // Get compared branches information - // format: <base branch>...[<head repo>:]<head branch> - // base<-head: master...head:feature - // same repo: master...feature - infos := strings.Split(c.Params("*"), "...") - if len(infos) != 2 { - log.Trace("ParseCompareInfo[%d]: not enough compared branches information %s", baseRepo.ID, infos) - c.NotFound() - return nil, nil, nil, nil, "", "" - } - - baseBranch := infos[0] - c.Data["BaseBranch"] = baseBranch - - var ( - headUser *models.User - headBranch string - isSameRepo bool - err error - ) - - // If there is no head repository, it means pull request between same repository. - headInfos := strings.Split(infos[1], ":") - if len(headInfos) == 1 { - isSameRepo = true - headUser = c.Repo.Owner - headBranch = headInfos[0] - - } else if len(headInfos) == 2 { - headUser, err = models.GetUserByName(headInfos[0]) - if err != nil { - c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err) - return nil, nil, nil, nil, "", "" - } - headBranch = headInfos[1] - isSameRepo = headUser.ID == baseRepo.OwnerID - - } else { - c.NotFound() - return nil, nil, nil, nil, "", "" - } - c.Data["HeadUser"] = headUser - c.Data["HeadBranch"] = headBranch - c.Repo.PullRequest.SameRepo = isSameRepo - - // Check if base branch is valid. - if !c.Repo.GitRepo.IsBranchExist(baseBranch) { - c.NotFound() - return nil, nil, nil, nil, "", "" - } - - var ( - headRepo *models.Repository - headGitRepo *git.Repository - ) - - // In case user included redundant head user name for comparison in same repository, - // no need to check the fork relation. - if !isSameRepo { - var has bool - headRepo, has = models.HasForkedRepo(headUser.ID, baseRepo.ID) - if !has { - log.Trace("ParseCompareInfo [base_repo_id: %d]: does not have fork or in same repository", baseRepo.ID) - c.NotFound() - return nil, nil, nil, nil, "", "" - } - - headGitRepo, err = git.OpenRepository(models.RepoPath(headUser.Name, headRepo.Name)) - if err != nil { - c.ServerError("OpenRepository", err) - return nil, nil, nil, nil, "", "" - } - } else { - headRepo = c.Repo.Repository - headGitRepo = c.Repo.GitRepo - } - - if !c.User.IsWriterOfRepo(headRepo) && !c.User.IsAdmin { - log.Trace("ParseCompareInfo [base_repo_id: %d]: does not have write access or site admin", baseRepo.ID) - c.NotFound() - return nil, nil, nil, nil, "", "" - } - - // Check if head branch is valid. - if !headGitRepo.IsBranchExist(headBranch) { - c.NotFound() - return nil, nil, nil, nil, "", "" - } - - headBranches, err := headGitRepo.GetBranches() - if err != nil { - c.ServerError("GetBranches", err) - return nil, nil, nil, nil, "", "" - } - c.Data["HeadBranches"] = headBranches - - prInfo, err := headGitRepo.GetPullRequestInfo(models.RepoPath(baseRepo.Owner.Name, baseRepo.Name), baseBranch, headBranch) - if err != nil { - if git.IsErrNoMergeBase(err) { - c.Data["IsNoMergeBase"] = true - c.Success(COMPARE_PULL) - } else { - c.ServerError("GetPullRequestInfo", err) - } - return nil, nil, nil, nil, "", "" - } - c.Data["BeforeCommitID"] = prInfo.MergeBase - - return headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch -} - -func PrepareCompareDiff( - c *context.Context, - headUser *models.User, - headRepo *models.Repository, - headGitRepo *git.Repository, - prInfo *git.PullRequestInfo, - baseBranch, headBranch string) bool { - - var ( - repo = c.Repo.Repository - err error - ) - - // Get diff information. - c.Data["CommitRepoLink"] = headRepo.Link() - - headCommitID, err := headGitRepo.GetBranchCommitID(headBranch) - if err != nil { - c.ServerError("GetBranchCommitID", err) - return false - } - c.Data["AfterCommitID"] = headCommitID - - if headCommitID == prInfo.MergeBase { - c.Data["IsNothingToCompare"] = true - return true - } - - diff, err := models.GetDiffRange(models.RepoPath(headUser.Name, headRepo.Name), - prInfo.MergeBase, headCommitID, setting.Git.MaxGitDiffLines, - setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles) - if err != nil { - c.ServerError("GetDiffRange", err) - return false - } - c.Data["Diff"] = diff - c.Data["DiffNotAvailable"] = diff.NumFiles() == 0 - - headCommit, err := headGitRepo.GetCommit(headCommitID) - if err != nil { - c.ServerError("GetCommit", err) - return false - } - - prInfo.Commits = models.ValidateCommitsWithEmails(prInfo.Commits) - c.Data["Commits"] = prInfo.Commits - c.Data["CommitCount"] = prInfo.Commits.Len() - c.Data["Username"] = headUser.Name - c.Data["Reponame"] = headRepo.Name - c.Data["IsImageFile"] = headCommit.IsImageFile - - headTarget := path.Join(headUser.Name, repo.Name) - c.Data["SourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", headCommitID) - c.Data["BeforeSourcePath"] = setting.AppSubURL + "/" + path.Join(headTarget, "src", prInfo.MergeBase) - c.Data["RawPath"] = setting.AppSubURL + "/" + path.Join(headTarget, "raw", headCommitID) - return false -} - -func CompareAndPullRequest(c *context.Context) { - c.Data["Title"] = c.Tr("repo.pulls.compare_changes") - c.Data["PageIsComparePull"] = true - c.Data["IsDiffCompare"] = true - c.Data["RequireHighlightJS"] = true - setTemplateIfExists(c, PULL_REQUEST_TEMPLATE_KEY, PullRequestTemplateCandidates) - renderAttachmentSettings(c) - - headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(c) - if c.Written() { - return - } - - pr, err := models.GetUnmergedPullRequest(headRepo.ID, c.Repo.Repository.ID, headBranch, baseBranch) - if err != nil { - if !models.IsErrPullRequestNotExist(err) { - c.ServerError("GetUnmergedPullRequest", err) - return - } - } else { - c.Data["HasPullRequest"] = true - c.Data["PullRequest"] = pr - c.Success(COMPARE_PULL) - return - } - - nothingToCompare := PrepareCompareDiff(c, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch) - if c.Written() { - return - } - - if !nothingToCompare { - // Setup information for new form. - RetrieveRepoMetas(c, c.Repo.Repository) - if c.Written() { - return - } - } - - setEditorconfigIfExists(c) - if c.Written() { - return - } - - c.Data["IsSplitStyle"] = c.Query("style") == "split" - c.Success(COMPARE_PULL) -} - -func CompareAndPullRequestPost(c *context.Context, f form.NewIssue) { - c.Data["Title"] = c.Tr("repo.pulls.compare_changes") - c.Data["PageIsComparePull"] = true - c.Data["IsDiffCompare"] = true - c.Data["RequireHighlightJS"] = true - renderAttachmentSettings(c) - - var ( - repo = c.Repo.Repository - attachments []string - ) - - headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch := ParseCompareInfo(c) - if c.Written() { - return - } - - labelIDs, milestoneID, assigneeID := ValidateRepoMetas(c, f) - if c.Written() { - return - } - - if setting.AttachmentEnabled { - attachments = f.Files - } - - if c.HasError() { - form.Assign(f, c.Data) - - // This stage is already stop creating new pull request, so it does not matter if it has - // something to compare or not. - PrepareCompareDiff(c, headUser, headRepo, headGitRepo, prInfo, baseBranch, headBranch) - if c.Written() { - return - } - - c.Success(COMPARE_PULL) - return - } - - patch, err := headGitRepo.GetPatch(prInfo.MergeBase, headBranch) - if err != nil { - c.ServerError("GetPatch", err) - return - } - - pullIssue := &models.Issue{ - RepoID: repo.ID, - Index: repo.NextIssueIndex(), - Title: f.Title, - PosterID: c.User.ID, - Poster: c.User, - MilestoneID: milestoneID, - AssigneeID: assigneeID, - IsPull: true, - Content: f.Content, - } - pullRequest := &models.PullRequest{ - HeadRepoID: headRepo.ID, - BaseRepoID: repo.ID, - HeadUserName: headUser.Name, - HeadBranch: headBranch, - BaseBranch: baseBranch, - HeadRepo: headRepo, - BaseRepo: repo, - MergeBase: prInfo.MergeBase, - Type: models.PULL_REQUEST_GOGS, - } - // FIXME: check error in the case two people send pull request at almost same time, give nice error prompt - // instead of 500. - if err := models.NewPullRequest(repo, pullIssue, labelIDs, attachments, pullRequest, patch); err != nil { - c.ServerError("NewPullRequest", err) - return - } else if err := pullRequest.PushToBaseRepo(); err != nil { - c.ServerError("PushToBaseRepo", err) - return - } - - log.Trace("Pull request created: %d/%d", repo.ID, pullIssue.ID) - c.Redirect(c.Repo.RepoLink + "/pulls/" + com.ToStr(pullIssue.Index)) -} - -func parseOwnerAndRepo(c *context.Context) (*models.User, *models.Repository) { - owner, err := models.GetUserByName(c.Params(":username")) - if err != nil { - c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err) - return nil, nil - } - - repo, err := models.GetRepositoryByName(owner.ID, c.Params(":reponame")) - if err != nil { - c.NotFoundOrServerError("GetRepositoryByName", errors.IsRepoNotExist, err) - return nil, nil - } - - return owner, repo -} - -func TriggerTask(c *context.Context) { - pusherID := c.QueryInt64("pusher") - branch := c.Query("branch") - secret := c.Query("secret") - if len(branch) == 0 || len(secret) == 0 || pusherID <= 0 { - c.Error(404) - log.Trace("TriggerTask: branch or secret is empty, or pusher ID is not valid") - return - } - owner, repo := parseOwnerAndRepo(c) - if c.Written() { - return - } - if secret != tool.MD5(owner.Salt) { - c.Error(404) - log.Trace("TriggerTask [%s/%s]: invalid secret", owner.Name, repo.Name) - return - } - - pusher, err := models.GetUserByID(pusherID) - if err != nil { - c.NotFoundOrServerError("GetUserByID", errors.IsUserNotExist, err) - return - } - - log.Trace("TriggerTask '%s/%s' by '%s'", repo.Name, branch, pusher.Name) - - go models.HookQueue.Add(repo.ID) - go models.AddTestPullRequestTask(pusher, repo.ID, branch, true) - c.Status(202) -} diff --git a/routers/repo/release.go b/routers/repo/release.go deleted file mode 100644 index 86dfe6f7..00000000 --- a/routers/repo/release.go +++ /dev/null @@ -1,332 +0,0 @@ -// 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 repo - -import ( - "fmt" - "strings" - - 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/markup" - "github.com/gogits/gogs/pkg/setting" -) - -const ( - RELEASES = "repo/release/list" - RELEASE_NEW = "repo/release/new" -) - -// calReleaseNumCommitsBehind calculates given release has how many commits behind release target. -func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *models.Release, countCache map[string]int64) error { - // Get count if not exists - if _, ok := countCache[release.Target]; !ok { - if repoCtx.GitRepo.IsBranchExist(release.Target) { - commit, err := repoCtx.GitRepo.GetBranchCommit(release.Target) - if err != nil { - return fmt.Errorf("GetBranchCommit: %v", err) - } - countCache[release.Target], err = commit.CommitsCount() - if err != nil { - return fmt.Errorf("CommitsCount: %v", err) - } - } else { - // Use NumCommits of the newest release on that target - countCache[release.Target] = release.NumCommits - } - } - release.NumCommitsBehind = countCache[release.Target] - release.NumCommits - return nil -} - -func Releases(c *context.Context) { - c.Data["Title"] = c.Tr("repo.release.releases") - c.Data["PageIsViewFiles"] = true - c.Data["PageIsReleaseList"] = true - - tagsResult, err := c.Repo.GitRepo.GetTagsAfter(c.Query("after"), 10) - if err != nil { - c.Handle(500, fmt.Sprintf("GetTags '%s'", c.Repo.Repository.RepoPath()), err) - return - } - - releases, err := models.GetPublishedReleasesByRepoID(c.Repo.Repository.ID, tagsResult.Tags...) - if err != nil { - c.Handle(500, "GetPublishedReleasesByRepoID", err) - return - } - - // Temproray cache commits count of used branches to speed up. - countCache := make(map[string]int64) - - results := make([]*models.Release, len(tagsResult.Tags)) - for i, rawTag := range tagsResult.Tags { - for j, r := range releases { - if r == nil || r.TagName != rawTag { - continue - } - releases[j] = nil // Mark as used. - - if err = r.LoadAttributes(); err != nil { - c.Handle(500, "LoadAttributes", err) - return - } - - if err := calReleaseNumCommitsBehind(c.Repo, r, countCache); err != nil { - c.Handle(500, "calReleaseNumCommitsBehind", err) - return - } - - r.Note = string(markup.Markdown(r.Note, c.Repo.RepoLink, c.Repo.Repository.ComposeMetas())) - results[i] = r - break - } - - // No published release matches this tag - if results[i] == nil { - commit, err := c.Repo.GitRepo.GetTagCommit(rawTag) - if err != nil { - c.Handle(500, "GetTagCommit", err) - return - } - - results[i] = &models.Release{ - Title: rawTag, - TagName: rawTag, - Sha1: commit.ID.String(), - } - - results[i].NumCommits, err = commit.CommitsCount() - if err != nil { - c.Handle(500, "CommitsCount", err) - return - } - results[i].NumCommitsBehind = c.Repo.CommitsCount - results[i].NumCommits - } - } - models.SortReleases(results) - - // Only show drafts if user is viewing the latest page - var drafts []*models.Release - if tagsResult.HasLatest { - drafts, err = models.GetDraftReleasesByRepoID(c.Repo.Repository.ID) - if err != nil { - c.Handle(500, "GetDraftReleasesByRepoID", err) - return - } - - for _, r := range drafts { - if err = r.LoadAttributes(); err != nil { - c.Handle(500, "LoadAttributes", err) - return - } - - if err := calReleaseNumCommitsBehind(c.Repo, r, countCache); err != nil { - c.Handle(500, "calReleaseNumCommitsBehind", err) - return - } - - r.Note = string(markup.Markdown(r.Note, c.Repo.RepoLink, c.Repo.Repository.ComposeMetas())) - } - - if len(drafts) > 0 { - results = append(drafts, results...) - } - } - - c.Data["Releases"] = results - c.Data["HasPrevious"] = !tagsResult.HasLatest - c.Data["ReachEnd"] = tagsResult.ReachEnd - c.Data["PreviousAfter"] = tagsResult.PreviousAfter - if len(results) > 0 { - c.Data["NextAfter"] = results[len(results)-1].TagName - } - c.HTML(200, RELEASES) -} - -func renderReleaseAttachmentSettings(c *context.Context) { - c.Data["RequireDropzone"] = true - c.Data["IsAttachmentEnabled"] = setting.Release.Attachment.Enabled - c.Data["AttachmentAllowedTypes"] = strings.Join(setting.Release.Attachment.AllowedTypes, ",") - c.Data["AttachmentMaxSize"] = setting.Release.Attachment.MaxSize - c.Data["AttachmentMaxFiles"] = setting.Release.Attachment.MaxFiles -} - -func NewRelease(c *context.Context) { - c.Data["Title"] = c.Tr("repo.release.new_release") - c.Data["PageIsReleaseList"] = true - c.Data["tag_target"] = c.Repo.Repository.DefaultBranch - renderReleaseAttachmentSettings(c) - c.HTML(200, RELEASE_NEW) -} - -func NewReleasePost(c *context.Context, f form.NewRelease) { - c.Data["Title"] = c.Tr("repo.release.new_release") - c.Data["PageIsReleaseList"] = true - renderReleaseAttachmentSettings(c) - - if c.HasError() { - c.HTML(200, RELEASE_NEW) - return - } - - if !c.Repo.GitRepo.IsBranchExist(f.Target) { - c.RenderWithErr(c.Tr("form.target_branch_not_exist"), RELEASE_NEW, &f) - return - } - - // Use current time if tag not yet exist, otherwise get time from Git - var tagCreatedUnix int64 - tag, err := c.Repo.GitRepo.GetTag(f.TagName) - if err == nil { - commit, err := tag.Commit() - if err == nil { - tagCreatedUnix = commit.Author.When.Unix() - } - } - - commit, err := c.Repo.GitRepo.GetBranchCommit(f.Target) - if err != nil { - c.Handle(500, "GetBranchCommit", err) - return - } - - commitsCount, err := commit.CommitsCount() - if err != nil { - c.Handle(500, "CommitsCount", err) - return - } - - var attachments []string - if setting.Release.Attachment.Enabled { - attachments = f.Files - } - - rel := &models.Release{ - RepoID: c.Repo.Repository.ID, - PublisherID: c.User.ID, - Title: f.Title, - TagName: f.TagName, - Target: f.Target, - Sha1: commit.ID.String(), - NumCommits: commitsCount, - Note: f.Content, - IsDraft: len(f.Draft) > 0, - IsPrerelease: f.Prerelease, - CreatedUnix: tagCreatedUnix, - } - if err = models.NewRelease(c.Repo.GitRepo, rel, attachments); err != nil { - c.Data["Err_TagName"] = true - switch { - case models.IsErrReleaseAlreadyExist(err): - c.RenderWithErr(c.Tr("repo.release.tag_name_already_exist"), RELEASE_NEW, &f) - case models.IsErrInvalidTagName(err): - c.RenderWithErr(c.Tr("repo.release.tag_name_invalid"), RELEASE_NEW, &f) - default: - c.Handle(500, "NewRelease", err) - } - return - } - log.Trace("Release created: %s/%s:%s", c.User.LowerName, c.Repo.Repository.Name, f.TagName) - - c.Redirect(c.Repo.RepoLink + "/releases") -} - -func EditRelease(c *context.Context) { - c.Data["Title"] = c.Tr("repo.release.edit_release") - c.Data["PageIsReleaseList"] = true - c.Data["PageIsEditRelease"] = true - renderReleaseAttachmentSettings(c) - - tagName := c.Params("*") - rel, err := models.GetRelease(c.Repo.Repository.ID, tagName) - if err != nil { - if models.IsErrReleaseNotExist(err) { - c.Handle(404, "GetRelease", err) - } else { - c.Handle(500, "GetRelease", err) - } - return - } - c.Data["ID"] = rel.ID - c.Data["tag_name"] = rel.TagName - c.Data["tag_target"] = rel.Target - c.Data["title"] = rel.Title - c.Data["content"] = rel.Note - c.Data["attachments"] = rel.Attachments - c.Data["prerelease"] = rel.IsPrerelease - c.Data["IsDraft"] = rel.IsDraft - - c.HTML(200, RELEASE_NEW) -} - -func EditReleasePost(c *context.Context, f form.EditRelease) { - c.Data["Title"] = c.Tr("repo.release.edit_release") - c.Data["PageIsReleaseList"] = true - c.Data["PageIsEditRelease"] = true - renderReleaseAttachmentSettings(c) - - tagName := c.Params("*") - rel, err := models.GetRelease(c.Repo.Repository.ID, tagName) - if err != nil { - if models.IsErrReleaseNotExist(err) { - c.Handle(404, "GetRelease", err) - } else { - c.Handle(500, "GetRelease", err) - } - return - } - c.Data["tag_name"] = rel.TagName - c.Data["tag_target"] = rel.Target - c.Data["title"] = rel.Title - c.Data["content"] = rel.Note - c.Data["attachments"] = rel.Attachments - c.Data["prerelease"] = rel.IsPrerelease - c.Data["IsDraft"] = rel.IsDraft - - if c.HasError() { - c.HTML(200, RELEASE_NEW) - return - } - - var attachments []string - if setting.Release.Attachment.Enabled { - attachments = f.Files - } - - isPublish := rel.IsDraft && len(f.Draft) == 0 - rel.Title = f.Title - rel.Note = f.Content - rel.IsDraft = len(f.Draft) > 0 - rel.IsPrerelease = f.Prerelease - if err = models.UpdateRelease(c.User, c.Repo.GitRepo, rel, isPublish, attachments); err != nil { - c.Handle(500, "UpdateRelease", err) - return - } - c.Redirect(c.Repo.RepoLink + "/releases") -} - -func UploadReleaseAttachment(c *context.Context) { - if !setting.Release.Attachment.Enabled { - c.NotFound() - return - } - uploadAttachment(c, setting.Release.Attachment.AllowedTypes) -} - -func DeleteRelease(c *context.Context) { - if err := models.DeleteReleaseOfRepoByID(c.Repo.Repository.ID, c.QueryInt64("id")); err != nil { - c.Flash.Error("DeleteReleaseByID: " + err.Error()) - } else { - c.Flash.Success(c.Tr("repo.release.deletion_success")) - } - - c.JSON(200, map[string]interface{}{ - "redirect": c.Repo.RepoLink + "/releases", - }) -} diff --git a/routers/repo/repo.go b/routers/repo/repo.go deleted file mode 100644 index ea3c1a60..00000000 --- a/routers/repo/repo.go +++ /dev/null @@ -1,335 +0,0 @@ -// 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 repo - -import ( - "fmt" - "os" - "path" - "strings" - - "github.com/Unknwon/com" - log "gopkg.in/clog.v1" - - "github.com/gogits/git-module" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/pkg/tool" -) - -const ( - CREATE = "repo/create" - MIGRATE = "repo/migrate" -) - -func MustBeNotBare(c *context.Context) { - if c.Repo.Repository.IsBare { - c.Handle(404, "MustBeNotBare", nil) - } -} - -func checkContextUser(c *context.Context, uid int64) *models.User { - orgs, err := models.GetOwnedOrgsByUserIDDesc(c.User.ID, "updated_unix") - if err != nil { - c.Handle(500, "GetOwnedOrgsByUserIDDesc", err) - return nil - } - c.Data["Orgs"] = orgs - - // Not equal means current user is an organization. - if uid == c.User.ID || uid == 0 { - return c.User - } - - org, err := models.GetUserByID(uid) - if errors.IsUserNotExist(err) { - return c.User - } - - if err != nil { - c.Handle(500, "GetUserByID", fmt.Errorf("[%d]: %v", uid, err)) - return nil - } - - // Check ownership of organization. - if !org.IsOrganization() || !(c.User.IsAdmin || org.IsOwnedBy(c.User.ID)) { - c.Error(403) - return nil - } - return org -} - -func Create(c *context.Context) { - c.Data["Title"] = c.Tr("new_repo") - - // Give default value for template to render. - c.Data["Gitignores"] = models.Gitignores - c.Data["Licenses"] = models.Licenses - c.Data["Readmes"] = models.Readmes - c.Data["readme"] = "Default" - c.Data["private"] = c.User.LastRepoVisibility - c.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate - - ctxUser := checkContextUser(c, c.QueryInt64("org")) - if c.Written() { - return - } - c.Data["ContextUser"] = ctxUser - - c.HTML(200, CREATE) -} - -func handleCreateError(c *context.Context, owner *models.User, err error, name, tpl string, form interface{}) { - switch { - case errors.IsReachLimitOfRepo(err): - c.RenderWithErr(c.Tr("repo.form.reach_limit_of_creation", owner.RepoCreationNum()), tpl, form) - case models.IsErrRepoAlreadyExist(err): - c.Data["Err_RepoName"] = true - c.RenderWithErr(c.Tr("form.repo_name_been_taken"), tpl, form) - case models.IsErrNameReserved(err): - c.Data["Err_RepoName"] = true - c.RenderWithErr(c.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), tpl, form) - case models.IsErrNamePatternNotAllowed(err): - c.Data["Err_RepoName"] = true - c.RenderWithErr(c.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), tpl, form) - default: - c.Handle(500, name, err) - } -} - -func CreatePost(c *context.Context, f form.CreateRepo) { - c.Data["Title"] = c.Tr("new_repo") - - c.Data["Gitignores"] = models.Gitignores - c.Data["Licenses"] = models.Licenses - c.Data["Readmes"] = models.Readmes - - ctxUser := checkContextUser(c, f.UserID) - if c.Written() { - return - } - c.Data["ContextUser"] = ctxUser - - if c.HasError() { - c.HTML(200, CREATE) - return - } - - repo, err := models.CreateRepository(c.User, ctxUser, models.CreateRepoOptions{ - Name: f.RepoName, - Description: f.Description, - Gitignores: f.Gitignores, - License: f.License, - Readme: f.Readme, - IsPrivate: f.Private || setting.Repository.ForcePrivate, - AutoInit: f.AutoInit, - }) - if err == nil { - log.Trace("Repository created [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name) - c.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + repo.Name) - return - } - - if repo != nil { - if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil { - log.Error(4, "DeleteRepository: %v", errDelete) - } - } - - handleCreateError(c, ctxUser, err, "CreatePost", CREATE, &f) -} - -func Migrate(c *context.Context) { - c.Data["Title"] = c.Tr("new_migrate") - c.Data["private"] = c.User.LastRepoVisibility - c.Data["IsForcedPrivate"] = setting.Repository.ForcePrivate - c.Data["mirror"] = c.Query("mirror") == "1" - - ctxUser := checkContextUser(c, c.QueryInt64("org")) - if c.Written() { - return - } - c.Data["ContextUser"] = ctxUser - - c.HTML(200, MIGRATE) -} - -func MigratePost(c *context.Context, f form.MigrateRepo) { - c.Data["Title"] = c.Tr("new_migrate") - - ctxUser := checkContextUser(c, f.Uid) - if c.Written() { - return - } - c.Data["ContextUser"] = ctxUser - - if c.HasError() { - c.HTML(200, MIGRATE) - return - } - - remoteAddr, err := f.ParseRemoteAddr(c.User) - if err != nil { - if models.IsErrInvalidCloneAddr(err) { - c.Data["Err_CloneAddr"] = true - addrErr := err.(models.ErrInvalidCloneAddr) - switch { - case addrErr.IsURLError: - c.RenderWithErr(c.Tr("form.url_error"), MIGRATE, &f) - case addrErr.IsPermissionDenied: - c.RenderWithErr(c.Tr("repo.migrate.permission_denied"), MIGRATE, &f) - case addrErr.IsInvalidPath: - c.RenderWithErr(c.Tr("repo.migrate.invalid_local_path"), MIGRATE, &f) - default: - c.Handle(500, "Unknown error", err) - } - } else { - c.Handle(500, "ParseRemoteAddr", err) - } - return - } - - repo, err := models.MigrateRepository(c.User, ctxUser, models.MigrateRepoOptions{ - Name: f.RepoName, - Description: f.Description, - IsPrivate: f.Private || setting.Repository.ForcePrivate, - IsMirror: f.Mirror, - RemoteAddr: remoteAddr, - }) - if err == nil { - log.Trace("Repository migrated [%d]: %s/%s", repo.ID, ctxUser.Name, f.RepoName) - c.Redirect(setting.AppSubURL + "/" + ctxUser.Name + "/" + f.RepoName) - return - } - - if repo != nil { - if errDelete := models.DeleteRepository(ctxUser.ID, repo.ID); errDelete != nil { - log.Error(4, "DeleteRepository: %v", errDelete) - } - } - - if strings.Contains(err.Error(), "Authentication failed") || - strings.Contains(err.Error(), "could not read Username") { - c.Data["Err_Auth"] = true - c.RenderWithErr(c.Tr("form.auth_failed", models.HandleMirrorCredentials(err.Error(), true)), MIGRATE, &f) - return - } else if strings.Contains(err.Error(), "fatal:") { - c.Data["Err_CloneAddr"] = true - c.RenderWithErr(c.Tr("repo.migrate.failed", models.HandleMirrorCredentials(err.Error(), true)), MIGRATE, &f) - return - } - - handleCreateError(c, ctxUser, err, "MigratePost", MIGRATE, &f) -} - -func Action(c *context.Context) { - var err error - switch c.Params(":action") { - case "watch": - err = models.WatchRepo(c.User.ID, c.Repo.Repository.ID, true) - case "unwatch": - err = models.WatchRepo(c.User.ID, c.Repo.Repository.ID, false) - case "star": - err = models.StarRepo(c.User.ID, c.Repo.Repository.ID, true) - case "unstar": - err = models.StarRepo(c.User.ID, c.Repo.Repository.ID, false) - case "desc": // FIXME: this is not used - if !c.Repo.IsOwner() { - c.Error(404) - return - } - - c.Repo.Repository.Description = c.Query("desc") - c.Repo.Repository.Website = c.Query("site") - err = models.UpdateRepository(c.Repo.Repository, false) - } - - if err != nil { - c.Handle(500, fmt.Sprintf("Action (%s)", c.Params(":action")), err) - return - } - - redirectTo := c.Query("redirect_to") - if len(redirectTo) == 0 { - redirectTo = c.Repo.RepoLink - } - c.Redirect(redirectTo) -} - -func Download(c *context.Context) { - var ( - uri = c.Params("*") - refName string - ext string - archivePath string - archiveType git.ArchiveType - ) - - switch { - case strings.HasSuffix(uri, ".zip"): - ext = ".zip" - archivePath = path.Join(c.Repo.GitRepo.Path, "archives/zip") - archiveType = git.ZIP - case strings.HasSuffix(uri, ".tar.gz"): - ext = ".tar.gz" - archivePath = path.Join(c.Repo.GitRepo.Path, "archives/targz") - archiveType = git.TARGZ - default: - log.Trace("Unknown format: %s", uri) - c.Error(404) - return - } - refName = strings.TrimSuffix(uri, ext) - - if !com.IsDir(archivePath) { - if err := os.MkdirAll(archivePath, os.ModePerm); err != nil { - c.Handle(500, "Download -> os.MkdirAll(archivePath)", err) - return - } - } - - // Get corresponding commit. - var ( - commit *git.Commit - err error - ) - gitRepo := c.Repo.GitRepo - if gitRepo.IsBranchExist(refName) { - commit, err = gitRepo.GetBranchCommit(refName) - if err != nil { - c.Handle(500, "GetBranchCommit", err) - return - } - } else if gitRepo.IsTagExist(refName) { - commit, err = gitRepo.GetTagCommit(refName) - if err != nil { - c.Handle(500, "GetTagCommit", err) - return - } - } else if len(refName) >= 7 && len(refName) <= 40 { - commit, err = gitRepo.GetCommit(refName) - if err != nil { - c.NotFound() - return - } - } else { - c.NotFound() - return - } - - archivePath = path.Join(archivePath, tool.ShortSHA1(commit.ID.String())+ext) - if !com.IsFile(archivePath) { - if err := commit.CreateArchive(archivePath, archiveType); err != nil { - c.Handle(500, "Download -> CreateArchive "+archivePath, err) - return - } - } - - c.ServeFile(archivePath, c.Repo.Repository.Name+"-"+refName+ext) -} diff --git a/routers/repo/setting.go b/routers/repo/setting.go deleted file mode 100644 index 9168b04a..00000000 --- a/routers/repo/setting.go +++ /dev/null @@ -1,631 +0,0 @@ -// 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 repo - -import ( - "fmt" - "strings" - "time" - - log "gopkg.in/clog.v1" - - "github.com/gogits/git-module" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/mailer" - "github.com/gogits/gogs/pkg/setting" -) - -const ( - SETTINGS_OPTIONS = "repo/settings/options" - SETTINGS_COLLABORATION = "repo/settings/collaboration" - SETTINGS_BRANCHES = "repo/settings/branches" - SETTINGS_PROTECTED_BRANCH = "repo/settings/protected_branch" - SETTINGS_GITHOOKS = "repo/settings/githooks" - SETTINGS_GITHOOK_EDIT = "repo/settings/githook_edit" - SETTINGS_DEPLOY_KEYS = "repo/settings/deploy_keys" -) - -func Settings(c *context.Context) { - c.Data["Title"] = c.Tr("repo.settings") - c.Data["PageIsSettingsOptions"] = true - c.HTML(200, SETTINGS_OPTIONS) -} - -func SettingsPost(c *context.Context, f form.RepoSetting) { - c.Data["Title"] = c.Tr("repo.settings") - c.Data["PageIsSettingsOptions"] = true - - repo := c.Repo.Repository - - switch c.Query("action") { - case "update": - if c.HasError() { - c.HTML(200, SETTINGS_OPTIONS) - return - } - - isNameChanged := false - oldRepoName := repo.Name - newRepoName := f.RepoName - // Check if repository name has been changed. - if repo.LowerName != strings.ToLower(newRepoName) { - isNameChanged = true - if err := models.ChangeRepositoryName(c.Repo.Owner, repo.Name, newRepoName); err != nil { - c.Data["Err_RepoName"] = true - switch { - case models.IsErrRepoAlreadyExist(err): - c.RenderWithErr(c.Tr("form.repo_name_been_taken"), SETTINGS_OPTIONS, &f) - case models.IsErrNameReserved(err): - c.RenderWithErr(c.Tr("repo.form.name_reserved", err.(models.ErrNameReserved).Name), SETTINGS_OPTIONS, &f) - case models.IsErrNamePatternNotAllowed(err): - c.RenderWithErr(c.Tr("repo.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), SETTINGS_OPTIONS, &f) - default: - c.Handle(500, "ChangeRepositoryName", err) - } - return - } - - log.Trace("Repository name changed: %s/%s -> %s", c.Repo.Owner.Name, repo.Name, newRepoName) - } - // In case it's just a case change. - repo.Name = newRepoName - repo.LowerName = strings.ToLower(newRepoName) - - repo.Description = f.Description - repo.Website = f.Website - - // Visibility of forked repository is forced sync with base repository. - if repo.IsFork { - f.Private = repo.BaseRepo.IsPrivate - } - - visibilityChanged := repo.IsPrivate != f.Private - repo.IsPrivate = f.Private - if err := models.UpdateRepository(repo, visibilityChanged); err != nil { - c.Handle(500, "UpdateRepository", err) - return - } - log.Trace("Repository basic settings updated: %s/%s", c.Repo.Owner.Name, repo.Name) - - if isNameChanged { - if err := models.RenameRepoAction(c.User, oldRepoName, repo); err != nil { - log.Error(4, "RenameRepoAction: %v", err) - } - } - - c.Flash.Success(c.Tr("repo.settings.update_settings_success")) - c.Redirect(repo.Link() + "/settings") - - case "mirror": - if !repo.IsMirror { - c.Handle(404, "", nil) - return - } - - if f.Interval > 0 { - c.Repo.Mirror.EnablePrune = f.EnablePrune - c.Repo.Mirror.Interval = f.Interval - c.Repo.Mirror.NextUpdate = time.Now().Add(time.Duration(f.Interval) * time.Hour) - if err := models.UpdateMirror(c.Repo.Mirror); err != nil { - c.Handle(500, "UpdateMirror", err) - return - } - } - if err := c.Repo.Mirror.SaveAddress(f.MirrorAddress); err != nil { - c.Handle(500, "SaveAddress", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.update_settings_success")) - c.Redirect(repo.Link() + "/settings") - - case "mirror-sync": - if !repo.IsMirror { - c.Handle(404, "", nil) - return - } - - go models.MirrorQueue.Add(repo.ID) - c.Flash.Info(c.Tr("repo.settings.mirror_sync_in_progress")) - c.Redirect(repo.Link() + "/settings") - - case "advanced": - repo.EnableWiki = f.EnableWiki - repo.AllowPublicWiki = f.AllowPublicWiki - repo.EnableExternalWiki = f.EnableExternalWiki - repo.ExternalWikiURL = f.ExternalWikiURL - repo.EnableIssues = f.EnableIssues - repo.AllowPublicIssues = f.AllowPublicIssues - repo.EnableExternalTracker = f.EnableExternalTracker - repo.ExternalTrackerURL = f.ExternalTrackerURL - repo.ExternalTrackerFormat = f.TrackerURLFormat - repo.ExternalTrackerStyle = f.TrackerIssueStyle - repo.EnablePulls = f.EnablePulls - - if err := models.UpdateRepository(repo, false); err != nil { - c.Handle(500, "UpdateRepository", err) - return - } - log.Trace("Repository advanced settings updated: %s/%s", c.Repo.Owner.Name, repo.Name) - - c.Flash.Success(c.Tr("repo.settings.update_settings_success")) - c.Redirect(c.Repo.RepoLink + "/settings") - - case "convert": - if !c.Repo.IsOwner() { - c.Error(404) - return - } - if repo.Name != f.RepoName { - c.RenderWithErr(c.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil) - return - } - - if c.Repo.Owner.IsOrganization() { - if !c.Repo.Owner.IsOwnedBy(c.User.ID) { - c.Error(404) - return - } - } - - if !repo.IsMirror { - c.Error(404) - return - } - repo.IsMirror = false - - if _, err := models.CleanUpMigrateInfo(repo); err != nil { - c.Handle(500, "CleanUpMigrateInfo", err) - return - } else if err = models.DeleteMirrorByRepoID(c.Repo.Repository.ID); err != nil { - c.Handle(500, "DeleteMirrorByRepoID", err) - return - } - log.Trace("Repository converted from mirror to regular: %s/%s", c.Repo.Owner.Name, repo.Name) - c.Flash.Success(c.Tr("repo.settings.convert_succeed")) - c.Redirect(setting.AppSubURL + "/" + c.Repo.Owner.Name + "/" + repo.Name) - - case "transfer": - if !c.Repo.IsOwner() { - c.Error(404) - return - } - if repo.Name != f.RepoName { - c.RenderWithErr(c.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil) - return - } - - if c.Repo.Owner.IsOrganization() && !c.User.IsAdmin { - if !c.Repo.Owner.IsOwnedBy(c.User.ID) { - c.Error(404) - return - } - } - - newOwner := c.Query("new_owner_name") - isExist, err := models.IsUserExist(0, newOwner) - if err != nil { - c.Handle(500, "IsUserExist", err) - return - } else if !isExist { - c.RenderWithErr(c.Tr("form.enterred_invalid_owner_name"), SETTINGS_OPTIONS, nil) - return - } - - if err = models.TransferOwnership(c.User, newOwner, repo); err != nil { - if models.IsErrRepoAlreadyExist(err) { - c.RenderWithErr(c.Tr("repo.settings.new_owner_has_same_repo"), SETTINGS_OPTIONS, nil) - } else { - c.Handle(500, "TransferOwnership", err) - } - return - } - log.Trace("Repository transfered: %s/%s -> %s", c.Repo.Owner.Name, repo.Name, newOwner) - c.Flash.Success(c.Tr("repo.settings.transfer_succeed")) - c.Redirect(setting.AppSubURL + "/" + newOwner + "/" + repo.Name) - - case "delete": - if !c.Repo.IsOwner() { - c.Error(404) - return - } - if repo.Name != f.RepoName { - c.RenderWithErr(c.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil) - return - } - - if c.Repo.Owner.IsOrganization() && !c.User.IsAdmin { - if !c.Repo.Owner.IsOwnedBy(c.User.ID) { - c.Error(404) - return - } - } - - if err := models.DeleteRepository(c.Repo.Owner.ID, repo.ID); err != nil { - c.Handle(500, "DeleteRepository", err) - return - } - log.Trace("Repository deleted: %s/%s", c.Repo.Owner.Name, repo.Name) - - c.Flash.Success(c.Tr("repo.settings.deletion_success")) - c.Redirect(c.Repo.Owner.DashboardLink()) - - case "delete-wiki": - if !c.Repo.IsOwner() { - c.Error(404) - return - } - if repo.Name != f.RepoName { - c.RenderWithErr(c.Tr("form.enterred_invalid_repo_name"), SETTINGS_OPTIONS, nil) - return - } - - if c.Repo.Owner.IsOrganization() && !c.User.IsAdmin { - if !c.Repo.Owner.IsOwnedBy(c.User.ID) { - c.Error(404) - return - } - } - - repo.DeleteWiki() - log.Trace("Repository wiki deleted: %s/%s", c.Repo.Owner.Name, repo.Name) - - repo.EnableWiki = false - if err := models.UpdateRepository(repo, false); err != nil { - c.Handle(500, "UpdateRepository", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.wiki_deletion_success")) - c.Redirect(c.Repo.RepoLink + "/settings") - - default: - c.Handle(404, "", nil) - } -} - -func SettingsCollaboration(c *context.Context) { - c.Data["Title"] = c.Tr("repo.settings") - c.Data["PageIsSettingsCollaboration"] = true - - users, err := c.Repo.Repository.GetCollaborators() - if err != nil { - c.Handle(500, "GetCollaborators", err) - return - } - c.Data["Collaborators"] = users - - c.HTML(200, SETTINGS_COLLABORATION) -} - -func SettingsCollaborationPost(c *context.Context) { - name := strings.ToLower(c.Query("collaborator")) - if len(name) == 0 || c.Repo.Owner.LowerName == name { - c.Redirect(setting.AppSubURL + c.Req.URL.Path) - return - } - - u, err := models.GetUserByName(name) - if err != nil { - if errors.IsUserNotExist(err) { - c.Flash.Error(c.Tr("form.user_not_exist")) - c.Redirect(setting.AppSubURL + c.Req.URL.Path) - } else { - c.Handle(500, "GetUserByName", err) - } - return - } - - // Organization is not allowed to be added as a collaborator - if u.IsOrganization() { - c.Flash.Error(c.Tr("repo.settings.org_not_allowed_to_be_collaborator")) - c.Redirect(setting.AppSubURL + c.Req.URL.Path) - return - } - - if err = c.Repo.Repository.AddCollaborator(u); err != nil { - c.Handle(500, "AddCollaborator", err) - return - } - - if setting.Service.EnableNotifyMail { - mailer.SendCollaboratorMail(models.NewMailerUser(u), models.NewMailerUser(c.User), models.NewMailerRepo(c.Repo.Repository)) - } - - c.Flash.Success(c.Tr("repo.settings.add_collaborator_success")) - c.Redirect(setting.AppSubURL + c.Req.URL.Path) -} - -func ChangeCollaborationAccessMode(c *context.Context) { - if err := c.Repo.Repository.ChangeCollaborationAccessMode( - c.QueryInt64("uid"), - models.AccessMode(c.QueryInt("mode"))); err != nil { - log.Error(2, "ChangeCollaborationAccessMode: %v", err) - return - } - - c.Status(204) -} - -func DeleteCollaboration(c *context.Context) { - if err := c.Repo.Repository.DeleteCollaboration(c.QueryInt64("id")); err != nil { - c.Flash.Error("DeleteCollaboration: " + err.Error()) - } else { - c.Flash.Success(c.Tr("repo.settings.remove_collaborator_success")) - } - - c.JSON(200, map[string]interface{}{ - "redirect": c.Repo.RepoLink + "/settings/collaboration", - }) -} - -func SettingsBranches(c *context.Context) { - c.Data["Title"] = c.Tr("repo.settings.branches") - c.Data["PageIsSettingsBranches"] = true - - if c.Repo.Repository.IsBare { - c.Flash.Info(c.Tr("repo.settings.branches_bare"), true) - c.HTML(200, SETTINGS_BRANCHES) - return - } - - protectBranches, err := models.GetProtectBranchesByRepoID(c.Repo.Repository.ID) - if err != nil { - c.Handle(500, "GetProtectBranchesByRepoID", err) - return - } - - // Filter out deleted branches - branches := make([]string, 0, len(protectBranches)) - for i := range protectBranches { - if c.Repo.GitRepo.IsBranchExist(protectBranches[i].Name) { - branches = append(branches, protectBranches[i].Name) - } - } - c.Data["ProtectBranches"] = branches - - c.HTML(200, SETTINGS_BRANCHES) -} - -func UpdateDefaultBranch(c *context.Context) { - branch := c.Query("branch") - if c.Repo.GitRepo.IsBranchExist(branch) && - c.Repo.Repository.DefaultBranch != branch { - c.Repo.Repository.DefaultBranch = branch - if err := c.Repo.GitRepo.SetDefaultBranch(branch); err != nil { - if !git.IsErrUnsupportedVersion(err) { - c.Handle(500, "SetDefaultBranch", err) - return - } - - c.Flash.Warning(c.Tr("repo.settings.update_default_branch_unsupported")) - c.Redirect(c.Repo.RepoLink + "/settings/branches") - return - } - } - - if err := models.UpdateRepository(c.Repo.Repository, false); err != nil { - c.Handle(500, "UpdateRepository", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.update_default_branch_success")) - c.Redirect(c.Repo.RepoLink + "/settings/branches") -} - -func SettingsProtectedBranch(c *context.Context) { - branch := c.Params("*") - if !c.Repo.GitRepo.IsBranchExist(branch) { - c.NotFound() - return - } - - c.Data["Title"] = c.Tr("repo.settings.protected_branches") + " - " + branch - c.Data["PageIsSettingsBranches"] = true - - protectBranch, err := models.GetProtectBranchOfRepoByName(c.Repo.Repository.ID, branch) - if err != nil { - if !models.IsErrBranchNotExist(err) { - c.Handle(500, "GetProtectBranchOfRepoByName", err) - return - } - - // No options found, create defaults. - protectBranch = &models.ProtectBranch{ - Name: branch, - } - } - - if c.Repo.Owner.IsOrganization() { - users, err := c.Repo.Repository.GetWriters() - if err != nil { - c.Handle(500, "Repo.Repository.GetPushers", err) - return - } - c.Data["Users"] = users - c.Data["whitelist_users"] = protectBranch.WhitelistUserIDs - - teams, err := c.Repo.Owner.TeamsHaveAccessToRepo(c.Repo.Repository.ID, models.ACCESS_MODE_WRITE) - if err != nil { - c.Handle(500, "Repo.Owner.TeamsHaveAccessToRepo", err) - return - } - c.Data["Teams"] = teams - c.Data["whitelist_teams"] = protectBranch.WhitelistTeamIDs - } - - c.Data["Branch"] = protectBranch - c.HTML(200, SETTINGS_PROTECTED_BRANCH) -} - -func SettingsProtectedBranchPost(c *context.Context, f form.ProtectBranch) { - branch := c.Params("*") - if !c.Repo.GitRepo.IsBranchExist(branch) { - c.NotFound() - return - } - - protectBranch, err := models.GetProtectBranchOfRepoByName(c.Repo.Repository.ID, branch) - if err != nil { - if !models.IsErrBranchNotExist(err) { - c.Handle(500, "GetProtectBranchOfRepoByName", err) - return - } - - // No options found, create defaults. - protectBranch = &models.ProtectBranch{ - RepoID: c.Repo.Repository.ID, - Name: branch, - } - } - - protectBranch.Protected = f.Protected - protectBranch.RequirePullRequest = f.RequirePullRequest - protectBranch.EnableWhitelist = f.EnableWhitelist - if c.Repo.Owner.IsOrganization() { - err = models.UpdateOrgProtectBranch(c.Repo.Repository, protectBranch, f.WhitelistUsers, f.WhitelistTeams) - } else { - err = models.UpdateProtectBranch(protectBranch) - } - if err != nil { - c.Handle(500, "UpdateOrgProtectBranch/UpdateProtectBranch", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.update_protect_branch_success")) - c.Redirect(fmt.Sprintf("%s/settings/branches/%s", c.Repo.RepoLink, branch)) -} - -func SettingsGitHooks(c *context.Context) { - c.Data["Title"] = c.Tr("repo.settings.githooks") - c.Data["PageIsSettingsGitHooks"] = true - - hooks, err := c.Repo.GitRepo.Hooks() - if err != nil { - c.Handle(500, "Hooks", err) - return - } - c.Data["Hooks"] = hooks - - c.HTML(200, SETTINGS_GITHOOKS) -} - -func SettingsGitHooksEdit(c *context.Context) { - c.Data["Title"] = c.Tr("repo.settings.githooks") - c.Data["PageIsSettingsGitHooks"] = true - c.Data["RequireSimpleMDE"] = true - - name := c.Params(":name") - hook, err := c.Repo.GitRepo.GetHook(name) - if err != nil { - if err == git.ErrNotValidHook { - c.Handle(404, "GetHook", err) - } else { - c.Handle(500, "GetHook", err) - } - return - } - c.Data["Hook"] = hook - c.HTML(200, SETTINGS_GITHOOK_EDIT) -} - -func SettingsGitHooksEditPost(c *context.Context) { - name := c.Params(":name") - hook, err := c.Repo.GitRepo.GetHook(name) - if err != nil { - if err == git.ErrNotValidHook { - c.Handle(404, "GetHook", err) - } else { - c.Handle(500, "GetHook", err) - } - return - } - hook.Content = c.Query("content") - if err = hook.Update(); err != nil { - c.Handle(500, "hook.Update", err) - return - } - c.Redirect(c.Data["Link"].(string)) -} - -func SettingsDeployKeys(c *context.Context) { - c.Data["Title"] = c.Tr("repo.settings.deploy_keys") - c.Data["PageIsSettingsKeys"] = true - - keys, err := models.ListDeployKeys(c.Repo.Repository.ID) - if err != nil { - c.Handle(500, "ListDeployKeys", err) - return - } - c.Data["Deploykeys"] = keys - - c.HTML(200, SETTINGS_DEPLOY_KEYS) -} - -func SettingsDeployKeysPost(c *context.Context, f form.AddSSHKey) { - c.Data["Title"] = c.Tr("repo.settings.deploy_keys") - c.Data["PageIsSettingsKeys"] = true - - keys, err := models.ListDeployKeys(c.Repo.Repository.ID) - if err != nil { - c.Handle(500, "ListDeployKeys", err) - return - } - c.Data["Deploykeys"] = keys - - if c.HasError() { - c.HTML(200, SETTINGS_DEPLOY_KEYS) - return - } - - content, err := models.CheckPublicKeyString(f.Content) - if err != nil { - if models.IsErrKeyUnableVerify(err) { - c.Flash.Info(c.Tr("form.unable_verify_ssh_key")) - } else { - c.Data["HasError"] = true - c.Data["Err_Content"] = true - c.Flash.Error(c.Tr("form.invalid_ssh_key", err.Error())) - c.Redirect(c.Repo.RepoLink + "/settings/keys") - return - } - } - - key, err := models.AddDeployKey(c.Repo.Repository.ID, f.Title, content) - if err != nil { - c.Data["HasError"] = true - switch { - case models.IsErrKeyAlreadyExist(err): - c.Data["Err_Content"] = true - c.RenderWithErr(c.Tr("repo.settings.key_been_used"), SETTINGS_DEPLOY_KEYS, &f) - case models.IsErrKeyNameAlreadyUsed(err): - c.Data["Err_Title"] = true - c.RenderWithErr(c.Tr("repo.settings.key_name_used"), SETTINGS_DEPLOY_KEYS, &f) - default: - c.Handle(500, "AddDeployKey", err) - } - return - } - - log.Trace("Deploy key added: %d", c.Repo.Repository.ID) - c.Flash.Success(c.Tr("repo.settings.add_key_success", key.Name)) - c.Redirect(c.Repo.RepoLink + "/settings/keys") -} - -func DeleteDeployKey(c *context.Context) { - if err := models.DeleteDeployKey(c.User, c.QueryInt64("id")); err != nil { - c.Flash.Error("DeleteDeployKey: " + err.Error()) - } else { - c.Flash.Success(c.Tr("repo.settings.deploy_key_deletion_success")) - } - - c.JSON(200, map[string]interface{}{ - "redirect": c.Repo.RepoLink + "/settings/keys", - }) -} diff --git a/routers/repo/view.go b/routers/repo/view.go deleted file mode 100644 index 1ea25d51..00000000 --- a/routers/repo/view.go +++ /dev/null @@ -1,367 +0,0 @@ -// 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 repo - -import ( - "bytes" - "fmt" - gotemplate "html/template" - "io/ioutil" - "path" - "strings" - - "github.com/Unknwon/paginater" - log "gopkg.in/clog.v1" - - "github.com/gogits/git-module" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/markup" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/pkg/template" - "github.com/gogits/gogs/pkg/template/highlight" - "github.com/gogits/gogs/pkg/tool" -) - -const ( - BARE = "repo/bare" - HOME = "repo/home" - WATCHERS = "repo/watchers" - FORKS = "repo/forks" -) - -func renderDirectory(c *context.Context, treeLink string) { - tree, err := c.Repo.Commit.SubTree(c.Repo.TreePath) - if err != nil { - c.NotFoundOrServerError("Repo.Commit.SubTree", git.IsErrNotExist, err) - return - } - - entries, err := tree.ListEntries() - if err != nil { - c.ServerError("ListEntries", err) - return - } - entries.Sort() - - c.Data["Files"], err = entries.GetCommitsInfoWithCustomConcurrency(c.Repo.Commit, c.Repo.TreePath, setting.Repository.CommitsFetchConcurrency) - if err != nil { - c.ServerError("GetCommitsInfoWithCustomConcurrency", err) - return - } - - var readmeFile *git.Blob - for _, entry := range entries { - if entry.IsDir() || !markup.IsReadmeFile(entry.Name()) { - continue - } - - // TODO: collect all possible README files and show with priority. - readmeFile = entry.Blob() - break - } - - if readmeFile != nil { - c.Data["RawFileLink"] = "" - c.Data["ReadmeInList"] = true - c.Data["ReadmeExist"] = true - - dataRc, err := readmeFile.Data() - if err != nil { - c.ServerError("readmeFile.Data", err) - return - } - - buf := make([]byte, 1024) - n, _ := dataRc.Read(buf) - buf = buf[:n] - - isTextFile := tool.IsTextFile(buf) - c.Data["IsTextFile"] = isTextFile - c.Data["FileName"] = readmeFile.Name() - if isTextFile { - d, _ := ioutil.ReadAll(dataRc) - buf = append(buf, d...) - - switch markup.Detect(readmeFile.Name()) { - case markup.MARKDOWN: - c.Data["IsMarkdown"] = true - buf = markup.Markdown(buf, treeLink, c.Repo.Repository.ComposeMetas()) - case markup.ORG_MODE: - c.Data["IsMarkdown"] = true - buf = markup.OrgMode(buf, treeLink, c.Repo.Repository.ComposeMetas()) - case markup.IPYTHON_NOTEBOOK: - c.Data["IsIPythonNotebook"] = true - c.Data["RawFileLink"] = c.Repo.RepoLink + "/raw/" + path.Join(c.Repo.BranchName, c.Repo.TreePath, readmeFile.Name()) - default: - buf = bytes.Replace(buf, []byte("\n"), []byte(`<br>`), -1) - } - c.Data["FileContent"] = string(buf) - } - } - - // Show latest commit info of repository in table header, - // or of directory if not in root directory. - latestCommit := c.Repo.Commit - if len(c.Repo.TreePath) > 0 { - latestCommit, err = c.Repo.Commit.GetCommitByPath(c.Repo.TreePath) - if err != nil { - c.ServerError("GetCommitByPath", err) - return - } - } - c.Data["LatestCommit"] = latestCommit - c.Data["LatestCommitUser"] = models.ValidateCommitWithEmail(latestCommit) - - if c.Repo.CanEnableEditor() { - c.Data["CanAddFile"] = true - c.Data["CanUploadFile"] = setting.Repository.Upload.Enabled - } -} - -func renderFile(c *context.Context, entry *git.TreeEntry, treeLink, rawLink string) { - c.Data["IsViewFile"] = true - - blob := entry.Blob() - dataRc, err := blob.Data() - if err != nil { - c.Handle(500, "Data", err) - return - } - - c.Data["FileSize"] = blob.Size() - c.Data["FileName"] = blob.Name() - c.Data["HighlightClass"] = highlight.FileNameToHighlightClass(blob.Name()) - c.Data["RawFileLink"] = rawLink + "/" + c.Repo.TreePath - - buf := make([]byte, 1024) - n, _ := dataRc.Read(buf) - buf = buf[:n] - - isTextFile := tool.IsTextFile(buf) - c.Data["IsTextFile"] = isTextFile - - // Assume file is not editable first. - if !isTextFile { - c.Data["EditFileTooltip"] = c.Tr("repo.editor.cannot_edit_non_text_files") - } - - canEnableEditor := c.Repo.CanEnableEditor() - switch { - case isTextFile: - if blob.Size() >= setting.UI.MaxDisplayFileSize { - c.Data["IsFileTooLarge"] = true - break - } - - c.Data["ReadmeExist"] = markup.IsReadmeFile(blob.Name()) - - d, _ := ioutil.ReadAll(dataRc) - buf = append(buf, d...) - - switch markup.Detect(blob.Name()) { - case markup.MARKDOWN: - c.Data["IsMarkdown"] = true - c.Data["FileContent"] = string(markup.Markdown(buf, path.Dir(treeLink), c.Repo.Repository.ComposeMetas())) - case markup.ORG_MODE: - c.Data["IsMarkdown"] = true - c.Data["FileContent"] = string(markup.OrgMode(buf, path.Dir(treeLink), c.Repo.Repository.ComposeMetas())) - case markup.IPYTHON_NOTEBOOK: - c.Data["IsIPythonNotebook"] = true - default: - // Building code view blocks with line number on server side. - var fileContent string - if err, content := template.ToUTF8WithErr(buf); err != nil { - if err != nil { - log.Error(4, "ToUTF8WithErr: %s", err) - } - fileContent = string(buf) - } else { - fileContent = content - } - - var output bytes.Buffer - lines := strings.Split(fileContent, "\n") - for index, line := range lines { - output.WriteString(fmt.Sprintf(`<li class="L%d" rel="L%d">%s</li>`, index+1, index+1, gotemplate.HTMLEscapeString(strings.TrimRight(line, "\r"))) + "\n") - } - c.Data["FileContent"] = gotemplate.HTML(output.String()) - - output.Reset() - for i := 0; i < len(lines); i++ { - output.WriteString(fmt.Sprintf(`<span id="L%d">%d</span>`, i+1, i+1)) - } - c.Data["LineNums"] = gotemplate.HTML(output.String()) - } - - if canEnableEditor { - c.Data["CanEditFile"] = true - c.Data["EditFileTooltip"] = c.Tr("repo.editor.edit_this_file") - } else if !c.Repo.IsViewBranch { - c.Data["EditFileTooltip"] = c.Tr("repo.editor.must_be_on_a_branch") - } else if !c.Repo.IsWriter() { - c.Data["EditFileTooltip"] = c.Tr("repo.editor.fork_before_edit") - } - - case tool.IsPDFFile(buf): - c.Data["IsPDFFile"] = true - case tool.IsVideoFile(buf): - c.Data["IsVideoFile"] = true - case tool.IsImageFile(buf): - c.Data["IsImageFile"] = true - } - - if canEnableEditor { - c.Data["CanDeleteFile"] = true - c.Data["DeleteFileTooltip"] = c.Tr("repo.editor.delete_this_file") - } else if !c.Repo.IsViewBranch { - c.Data["DeleteFileTooltip"] = c.Tr("repo.editor.must_be_on_a_branch") - } else if !c.Repo.IsWriter() { - c.Data["DeleteFileTooltip"] = c.Tr("repo.editor.must_have_write_access") - } -} - -func setEditorconfigIfExists(c *context.Context) { - ec, err := c.Repo.GetEditorconfig() - if err != nil && !git.IsErrNotExist(err) { - log.Trace("setEditorconfigIfExists.GetEditorconfig [%d]: %v", c.Repo.Repository.ID, err) - return - } - c.Data["Editorconfig"] = ec -} - -func Home(c *context.Context) { - c.Data["PageIsViewFiles"] = true - - if c.Repo.Repository.IsBare { - c.HTML(200, BARE) - return - } - - title := c.Repo.Repository.Owner.Name + "/" + c.Repo.Repository.Name - if len(c.Repo.Repository.Description) > 0 { - title += ": " + c.Repo.Repository.Description - } - c.Data["Title"] = title - if c.Repo.BranchName != c.Repo.Repository.DefaultBranch { - c.Data["Title"] = title + " @ " + c.Repo.BranchName - } - c.Data["RequireHighlightJS"] = true - - branchLink := c.Repo.RepoLink + "/src/" + c.Repo.BranchName - treeLink := branchLink - rawLink := c.Repo.RepoLink + "/raw/" + c.Repo.BranchName - - isRootDir := false - if len(c.Repo.TreePath) > 0 { - treeLink += "/" + c.Repo.TreePath - } else { - isRootDir = true - - // Only show Git stats panel when view root directory - var err error - c.Repo.CommitsCount, err = c.Repo.Commit.CommitsCount() - if err != nil { - c.Handle(500, "CommitsCount", err) - return - } - c.Data["CommitsCount"] = c.Repo.CommitsCount - } - c.Data["PageIsRepoHome"] = isRootDir - - // Get current entry user currently looking at. - entry, err := c.Repo.Commit.GetTreeEntryByPath(c.Repo.TreePath) - if err != nil { - c.NotFoundOrServerError("Repo.Commit.GetTreeEntryByPath", git.IsErrNotExist, err) - return - } - - if entry.IsDir() { - renderDirectory(c, treeLink) - } else { - renderFile(c, entry, treeLink, rawLink) - } - if c.Written() { - return - } - - setEditorconfigIfExists(c) - if c.Written() { - return - } - - var treeNames []string - paths := make([]string, 0, 5) - if len(c.Repo.TreePath) > 0 { - treeNames = strings.Split(c.Repo.TreePath, "/") - for i := range treeNames { - paths = append(paths, strings.Join(treeNames[:i+1], "/")) - } - - c.Data["HasParentPath"] = true - if len(paths)-2 >= 0 { - c.Data["ParentPath"] = "/" + paths[len(paths)-2] - } - } - - c.Data["Paths"] = paths - c.Data["TreeLink"] = treeLink - c.Data["TreeNames"] = treeNames - c.Data["BranchLink"] = branchLink - c.HTML(200, HOME) -} - -func RenderUserCards(c *context.Context, total int, getter func(page int) ([]*models.User, error), tpl string) { - page := c.QueryInt("page") - if page <= 0 { - page = 1 - } - pager := paginater.New(total, models.ItemsPerPage, page, 5) - c.Data["Page"] = pager - - items, err := getter(pager.Current()) - if err != nil { - c.Handle(500, "getter", err) - return - } - c.Data["Cards"] = items - - c.HTML(200, tpl) -} - -func Watchers(c *context.Context) { - c.Data["Title"] = c.Tr("repo.watchers") - c.Data["CardsTitle"] = c.Tr("repo.watchers") - c.Data["PageIsWatchers"] = true - RenderUserCards(c, c.Repo.Repository.NumWatches, c.Repo.Repository.GetWatchers, WATCHERS) -} - -func Stars(c *context.Context) { - c.Data["Title"] = c.Tr("repo.stargazers") - c.Data["CardsTitle"] = c.Tr("repo.stargazers") - c.Data["PageIsStargazers"] = true - RenderUserCards(c, c.Repo.Repository.NumStars, c.Repo.Repository.GetStargazers, WATCHERS) -} - -func Forks(c *context.Context) { - c.Data["Title"] = c.Tr("repos.forks") - - forks, err := c.Repo.Repository.GetForks() - if err != nil { - c.Handle(500, "GetForks", err) - return - } - - for _, fork := range forks { - if err = fork.GetOwner(); err != nil { - c.Handle(500, "GetOwner", err) - return - } - } - c.Data["Forks"] = forks - - c.HTML(200, FORKS) -} diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go deleted file mode 100644 index c572d446..00000000 --- a/routers/repo/webhook.go +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2015 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 repo - -import ( - "encoding/json" - "fmt" - "strings" - - "github.com/Unknwon/com" - - git "github.com/gogits/git-module" - api "github.com/gogits/go-gogs-client" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/setting" -) - -const ( - WEBHOOKS = "repo/settings/webhook/base" - WEBHOOK_NEW = "repo/settings/webhook/new" - ORG_WEBHOOK_NEW = "org/settings/webhook_new" -) - -func Webhooks(c *context.Context) { - c.Data["Title"] = c.Tr("repo.settings.hooks") - c.Data["PageIsSettingsHooks"] = true - c.Data["BaseLink"] = c.Repo.RepoLink - c.Data["Description"] = c.Tr("repo.settings.hooks_desc", "https://github.com/gogits/go-gogs-client/wiki/Repositories-Webhooks") - c.Data["Types"] = setting.Webhook.Types - - ws, err := models.GetWebhooksByRepoID(c.Repo.Repository.ID) - if err != nil { - c.Handle(500, "GetWebhooksByRepoID", err) - return - } - c.Data["Webhooks"] = ws - - c.HTML(200, WEBHOOKS) -} - -type OrgRepoCtx struct { - OrgID int64 - RepoID int64 - Link string - NewTemplate string -} - -// getOrgRepoCtx determines whether this is a repo context or organization context. -func getOrgRepoCtx(c *context.Context) (*OrgRepoCtx, error) { - if len(c.Repo.RepoLink) > 0 { - c.Data["PageIsRepositoryContext"] = true - return &OrgRepoCtx{ - RepoID: c.Repo.Repository.ID, - Link: c.Repo.RepoLink, - NewTemplate: WEBHOOK_NEW, - }, nil - } - - if len(c.Org.OrgLink) > 0 { - c.Data["PageIsOrganizationContext"] = true - return &OrgRepoCtx{ - OrgID: c.Org.Organization.ID, - Link: c.Org.OrgLink, - NewTemplate: ORG_WEBHOOK_NEW, - }, nil - } - - return nil, errors.New("Unable to set OrgRepo context") -} - -func checkHookType(c *context.Context) string { - hookType := strings.ToLower(c.Params(":type")) - if !com.IsSliceContainsStr(setting.Webhook.Types, hookType) { - c.Handle(404, "checkHookType", nil) - return "" - } - return hookType -} - -func WebhooksNew(c *context.Context) { - c.Data["Title"] = c.Tr("repo.settings.add_webhook") - c.Data["PageIsSettingsHooks"] = true - c.Data["PageIsSettingsHooksNew"] = true - c.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} - - orCtx, err := getOrgRepoCtx(c) - if err != nil { - c.Handle(500, "getOrgRepoCtx", err) - return - } - - c.Data["HookType"] = checkHookType(c) - if c.Written() { - return - } - c.Data["BaseLink"] = orCtx.Link - - c.HTML(200, orCtx.NewTemplate) -} - -func ParseHookEvent(f form.Webhook) *models.HookEvent { - return &models.HookEvent{ - PushOnly: f.PushOnly(), - SendEverything: f.SendEverything(), - ChooseEvents: f.ChooseEvents(), - HookEvents: models.HookEvents{ - Create: f.Create, - Delete: f.Delete, - Fork: f.Fork, - Push: f.Push, - Issues: f.Issues, - IssueComment: f.IssueComment, - PullRequest: f.PullRequest, - Release: f.Release, - }, - } -} - -func WebHooksNewPost(c *context.Context, f form.NewWebhook) { - c.Data["Title"] = c.Tr("repo.settings.add_webhook") - c.Data["PageIsSettingsHooks"] = true - c.Data["PageIsSettingsHooksNew"] = true - c.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} - c.Data["HookType"] = "gogs" - - orCtx, err := getOrgRepoCtx(c) - if err != nil { - c.Handle(500, "getOrgRepoCtx", err) - return - } - c.Data["BaseLink"] = orCtx.Link - - if c.HasError() { - c.HTML(200, orCtx.NewTemplate) - return - } - - contentType := models.JSON - if models.HookContentType(f.ContentType) == models.FORM { - contentType = models.FORM - } - - w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: f.PayloadURL, - ContentType: contentType, - Secret: f.Secret, - HookEvent: ParseHookEvent(f.Webhook), - IsActive: f.Active, - HookTaskType: models.GOGS, - OrgID: orCtx.OrgID, - } - if err := w.UpdateEvent(); err != nil { - c.Handle(500, "UpdateEvent", err) - return - } else if err := models.CreateWebhook(w); err != nil { - c.Handle(500, "CreateWebhook", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.add_hook_success")) - c.Redirect(orCtx.Link + "/settings/hooks") -} - -func SlackHooksNewPost(c *context.Context, f form.NewSlackHook) { - c.Data["Title"] = c.Tr("repo.settings") - c.Data["PageIsSettingsHooks"] = true - c.Data["PageIsSettingsHooksNew"] = true - c.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} - - orCtx, err := getOrgRepoCtx(c) - if err != nil { - c.Handle(500, "getOrgRepoCtx", err) - return - } - - if c.HasError() { - c.HTML(200, orCtx.NewTemplate) - return - } - - meta, err := json.Marshal(&models.SlackMeta{ - Channel: f.Channel, - Username: f.Username, - IconURL: f.IconURL, - Color: f.Color, - }) - if err != nil { - c.Handle(500, "Marshal", err) - return - } - - w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: f.PayloadURL, - ContentType: models.JSON, - HookEvent: ParseHookEvent(f.Webhook), - IsActive: f.Active, - HookTaskType: models.SLACK, - Meta: string(meta), - OrgID: orCtx.OrgID, - } - if err := w.UpdateEvent(); err != nil { - c.Handle(500, "UpdateEvent", err) - return - } else if err := models.CreateWebhook(w); err != nil { - c.Handle(500, "CreateWebhook", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.add_hook_success")) - c.Redirect(orCtx.Link + "/settings/hooks") -} - -// FIXME: merge logic to Slack -func DiscordHooksNewPost(c *context.Context, f form.NewDiscordHook) { - c.Data["Title"] = c.Tr("repo.settings") - c.Data["PageIsSettingsHooks"] = true - c.Data["PageIsSettingsHooksNew"] = true - c.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} - - orCtx, err := getOrgRepoCtx(c) - if err != nil { - c.Handle(500, "getOrgRepoCtx", err) - return - } - - if c.HasError() { - c.HTML(200, orCtx.NewTemplate) - return - } - - meta, err := json.Marshal(&models.SlackMeta{ - Username: f.Username, - IconURL: f.IconURL, - Color: f.Color, - }) - if err != nil { - c.Handle(500, "Marshal", err) - return - } - - w := &models.Webhook{ - RepoID: orCtx.RepoID, - URL: f.PayloadURL, - ContentType: models.JSON, - HookEvent: ParseHookEvent(f.Webhook), - IsActive: f.Active, - HookTaskType: models.DISCORD, - Meta: string(meta), - OrgID: orCtx.OrgID, - } - if err := w.UpdateEvent(); err != nil { - c.Handle(500, "UpdateEvent", err) - return - } else if err := models.CreateWebhook(w); err != nil { - c.Handle(500, "CreateWebhook", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.add_hook_success")) - c.Redirect(orCtx.Link + "/settings/hooks") -} - -func checkWebhook(c *context.Context) (*OrgRepoCtx, *models.Webhook) { - c.Data["RequireHighlightJS"] = true - - orCtx, err := getOrgRepoCtx(c) - if err != nil { - c.Handle(500, "getOrgRepoCtx", err) - return nil, nil - } - c.Data["BaseLink"] = orCtx.Link - - var w *models.Webhook - if orCtx.RepoID > 0 { - w, err = models.GetWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - } else { - w, err = models.GetWebhookByOrgID(c.Org.Organization.ID, c.ParamsInt64(":id")) - } - if err != nil { - c.NotFoundOrServerError("GetWebhookOfRepoByID/GetWebhookByOrgID", errors.IsWebhookNotExist, err) - return nil, nil - } - - switch w.HookTaskType { - case models.SLACK: - c.Data["SlackHook"] = w.GetSlackHook() - c.Data["HookType"] = "slack" - case models.DISCORD: - c.Data["SlackHook"] = w.GetSlackHook() - c.Data["HookType"] = "discord" - default: - c.Data["HookType"] = "gogs" - } - - c.Data["History"], err = w.History(1) - if err != nil { - c.Handle(500, "History", err) - } - return orCtx, w -} - -func WebHooksEdit(c *context.Context) { - c.Data["Title"] = c.Tr("repo.settings.update_webhook") - c.Data["PageIsSettingsHooks"] = true - c.Data["PageIsSettingsHooksEdit"] = true - - orCtx, w := checkWebhook(c) - if c.Written() { - return - } - c.Data["Webhook"] = w - - c.HTML(200, orCtx.NewTemplate) -} - -func WebHooksEditPost(c *context.Context, f form.NewWebhook) { - c.Data["Title"] = c.Tr("repo.settings.update_webhook") - c.Data["PageIsSettingsHooks"] = true - c.Data["PageIsSettingsHooksEdit"] = true - - orCtx, w := checkWebhook(c) - if c.Written() { - return - } - c.Data["Webhook"] = w - - if c.HasError() { - c.HTML(200, orCtx.NewTemplate) - return - } - - contentType := models.JSON - if models.HookContentType(f.ContentType) == models.FORM { - contentType = models.FORM - } - - w.URL = f.PayloadURL - w.ContentType = contentType - w.Secret = f.Secret - w.HookEvent = ParseHookEvent(f.Webhook) - w.IsActive = f.Active - if err := w.UpdateEvent(); err != nil { - c.Handle(500, "UpdateEvent", err) - return - } else if err := models.UpdateWebhook(w); err != nil { - c.Handle(500, "WebHooksEditPost", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.update_hook_success")) - c.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID)) -} - -func SlackHooksEditPost(c *context.Context, f form.NewSlackHook) { - c.Data["Title"] = c.Tr("repo.settings") - c.Data["PageIsSettingsHooks"] = true - c.Data["PageIsSettingsHooksEdit"] = true - - orCtx, w := checkWebhook(c) - if c.Written() { - return - } - c.Data["Webhook"] = w - - if c.HasError() { - c.HTML(200, orCtx.NewTemplate) - return - } - - meta, err := json.Marshal(&models.SlackMeta{ - Channel: f.Channel, - Username: f.Username, - IconURL: f.IconURL, - Color: f.Color, - }) - if err != nil { - c.Handle(500, "Marshal", err) - return - } - - w.URL = f.PayloadURL - w.Meta = string(meta) - w.HookEvent = ParseHookEvent(f.Webhook) - w.IsActive = f.Active - if err := w.UpdateEvent(); err != nil { - c.Handle(500, "UpdateEvent", err) - return - } else if err := models.UpdateWebhook(w); err != nil { - c.Handle(500, "UpdateWebhook", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.update_hook_success")) - c.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID)) -} - -// FIXME: merge logic to Slack -func DiscordHooksEditPost(c *context.Context, f form.NewDiscordHook) { - c.Data["Title"] = c.Tr("repo.settings") - c.Data["PageIsSettingsHooks"] = true - c.Data["PageIsSettingsHooksEdit"] = true - - orCtx, w := checkWebhook(c) - if c.Written() { - return - } - c.Data["Webhook"] = w - - if c.HasError() { - c.HTML(200, orCtx.NewTemplate) - return - } - - meta, err := json.Marshal(&models.SlackMeta{ - Username: f.Username, - IconURL: f.IconURL, - Color: f.Color, - }) - if err != nil { - c.Handle(500, "Marshal", err) - return - } - - w.URL = f.PayloadURL - w.Meta = string(meta) - w.HookEvent = ParseHookEvent(f.Webhook) - w.IsActive = f.Active - if err := w.UpdateEvent(); err != nil { - c.Handle(500, "UpdateEvent", err) - return - } else if err := models.UpdateWebhook(w); err != nil { - c.Handle(500, "UpdateWebhook", err) - return - } - - c.Flash.Success(c.Tr("repo.settings.update_hook_success")) - c.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID)) -} - -func TestWebhook(c *context.Context) { - var authorUsername, committerUsername string - - // Grab latest commit or fake one if it's empty repository. - commit := c.Repo.Commit - if commit == nil { - ghost := models.NewGhostUser() - commit = &git.Commit{ - ID: git.MustIDFromString(git.EMPTY_SHA), - Author: ghost.NewGitSig(), - Committer: ghost.NewGitSig(), - CommitMessage: "This is a fake commit", - } - authorUsername = ghost.Name - committerUsername = ghost.Name - } else { - // Try to match email with a real user. - author, err := models.GetUserByEmail(commit.Author.Email) - if err == nil { - authorUsername = author.Name - } else if !errors.IsUserNotExist(err) { - c.Handle(500, "GetUserByEmail.(author)", err) - return - } - - committer, err := models.GetUserByEmail(commit.Committer.Email) - if err == nil { - committerUsername = committer.Name - } else if !errors.IsUserNotExist(err) { - c.Handle(500, "GetUserByEmail.(committer)", err) - return - } - } - - fileStatus, err := commit.FileStatus() - if err != nil { - c.Handle(500, "FileStatus", err) - return - } - - apiUser := c.User.APIFormat() - p := &api.PushPayload{ - Ref: git.BRANCH_PREFIX + c.Repo.Repository.DefaultBranch, - Before: commit.ID.String(), - After: commit.ID.String(), - Commits: []*api.PayloadCommit{ - { - ID: commit.ID.String(), - Message: commit.Message(), - URL: c.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(), - Author: &api.PayloadUser{ - Name: commit.Author.Name, - Email: commit.Author.Email, - UserName: authorUsername, - }, - Committer: &api.PayloadUser{ - Name: commit.Committer.Name, - Email: commit.Committer.Email, - UserName: committerUsername, - }, - Added: fileStatus.Added, - Removed: fileStatus.Removed, - Modified: fileStatus.Modified, - }, - }, - Repo: c.Repo.Repository.APIFormat(nil), - Pusher: apiUser, - Sender: apiUser, - } - if err := models.TestWebhook(c.Repo.Repository, models.HOOK_EVENT_PUSH, p, c.ParamsInt64("id")); err != nil { - c.Handle(500, "TestWebhook", err) - } else { - c.Flash.Info(c.Tr("repo.settings.webhook.test_delivery_success")) - c.Status(200) - } -} - -func RedeliveryWebhook(c *context.Context) { - webhook, err := models.GetWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")) - if err != nil { - c.NotFoundOrServerError("GetWebhookOfRepoByID/GetWebhookByOrgID", errors.IsWebhookNotExist, err) - return - } - - hookTask, err := models.GetHookTaskOfWebhookByUUID(webhook.ID, c.Query("uuid")) - if err != nil { - c.NotFoundOrServerError("GetHookTaskOfWebhookByUUID/GetWebhookByOrgID", errors.IsHookTaskNotExist, err) - return - } - - hookTask.IsDelivered = false - if err = models.UpdateHookTask(hookTask); err != nil { - c.Handle(500, "UpdateHookTask", err) - } else { - go models.HookQueue.Add(c.Repo.Repository.ID) - c.Flash.Info(c.Tr("repo.settings.webhook.redelivery_success", hookTask.UUID)) - c.Status(200) - } -} - -func DeleteWebhook(c *context.Context) { - if err := models.DeleteWebhookOfRepoByID(c.Repo.Repository.ID, c.QueryInt64("id")); err != nil { - c.Flash.Error("DeleteWebhookByRepoID: " + err.Error()) - } else { - c.Flash.Success(c.Tr("repo.settings.webhook_deletion_success")) - } - - c.JSON(200, map[string]interface{}{ - "redirect": c.Repo.RepoLink + "/settings/hooks", - }) -} diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go deleted file mode 100644 index ad2cfbae..00000000 --- a/routers/repo/wiki.go +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2015 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 repo - -import ( - "io/ioutil" - "strings" - "time" - - "github.com/gogits/git-module" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/markup" -) - -const ( - WIKI_START = "repo/wiki/start" - WIKI_VIEW = "repo/wiki/view" - WIKI_NEW = "repo/wiki/new" - WIKI_PAGES = "repo/wiki/pages" -) - -func MustEnableWiki(c *context.Context) { - if !c.Repo.Repository.EnableWiki { - c.Handle(404, "MustEnableWiki", nil) - return - } - - if c.Repo.Repository.EnableExternalWiki { - c.Redirect(c.Repo.Repository.ExternalWikiURL) - return - } -} - -type PageMeta struct { - Name string - URL string - Updated time.Time -} - -func renderWikiPage(c *context.Context, isViewPage bool) (*git.Repository, string) { - wikiRepo, err := git.OpenRepository(c.Repo.Repository.WikiPath()) - if err != nil { - c.Handle(500, "OpenRepository", err) - return nil, "" - } - commit, err := wikiRepo.GetBranchCommit("master") - if err != nil { - c.Handle(500, "GetBranchCommit", err) - return nil, "" - } - - // Get page list. - if isViewPage { - entries, err := commit.ListEntries() - if err != nil { - c.Handle(500, "ListEntries", err) - return nil, "" - } - pages := make([]PageMeta, 0, len(entries)) - for i := range entries { - if entries[i].Type == git.OBJECT_BLOB && strings.HasSuffix(entries[i].Name(), ".md") { - name := strings.TrimSuffix(entries[i].Name(), ".md") - pages = append(pages, PageMeta{ - Name: name, - URL: models.ToWikiPageURL(name), - }) - } - } - c.Data["Pages"] = pages - } - - pageURL := c.Params(":page") - if len(pageURL) == 0 { - pageURL = "Home" - } - c.Data["PageURL"] = pageURL - - pageName := models.ToWikiPageName(pageURL) - c.Data["old_title"] = pageName - c.Data["Title"] = pageName - c.Data["title"] = pageName - c.Data["RequireHighlightJS"] = true - - blob, err := commit.GetBlobByPath(pageName + ".md") - if err != nil { - if git.IsErrNotExist(err) { - c.Redirect(c.Repo.RepoLink + "/wiki/_pages") - } else { - c.Handle(500, "GetBlobByPath", err) - } - return nil, "" - } - r, err := blob.Data() - if err != nil { - c.Handle(500, "Data", err) - return nil, "" - } - data, err := ioutil.ReadAll(r) - if err != nil { - c.Handle(500, "ReadAll", err) - return nil, "" - } - if isViewPage { - c.Data["content"] = string(markup.Markdown(data, c.Repo.RepoLink, c.Repo.Repository.ComposeMetas())) - } else { - c.Data["content"] = string(data) - } - - return wikiRepo, pageName -} - -func Wiki(c *context.Context) { - c.Data["PageIsWiki"] = true - - if !c.Repo.Repository.HasWiki() { - c.Data["Title"] = c.Tr("repo.wiki") - c.HTML(200, WIKI_START) - return - } - - wikiRepo, pageName := renderWikiPage(c, true) - if c.Written() { - return - } - - // Get last change information. - lastCommit, err := wikiRepo.GetCommitByPath(pageName + ".md") - if err != nil { - c.Handle(500, "GetCommitByPath", err) - return - } - c.Data["Author"] = lastCommit.Author - - c.HTML(200, WIKI_VIEW) -} - -func WikiPages(c *context.Context) { - c.Data["Title"] = c.Tr("repo.wiki.pages") - c.Data["PageIsWiki"] = true - - if !c.Repo.Repository.HasWiki() { - c.Redirect(c.Repo.RepoLink + "/wiki") - return - } - - wikiRepo, err := git.OpenRepository(c.Repo.Repository.WikiPath()) - if err != nil { - c.Handle(500, "OpenRepository", err) - return - } - commit, err := wikiRepo.GetBranchCommit("master") - if err != nil { - c.Handle(500, "GetBranchCommit", err) - return - } - - entries, err := commit.ListEntries() - if err != nil { - c.Handle(500, "ListEntries", err) - return - } - pages := make([]PageMeta, 0, len(entries)) - for i := range entries { - if entries[i].Type == git.OBJECT_BLOB && strings.HasSuffix(entries[i].Name(), ".md") { - commit, err := wikiRepo.GetCommitByPath(entries[i].Name()) - if err != nil { - c.ServerError("GetCommitByPath", err) - return - } - name := strings.TrimSuffix(entries[i].Name(), ".md") - pages = append(pages, PageMeta{ - Name: name, - URL: models.ToWikiPageURL(name), - Updated: commit.Author.When, - }) - } - } - c.Data["Pages"] = pages - - c.HTML(200, WIKI_PAGES) -} - -func NewWiki(c *context.Context) { - c.Data["Title"] = c.Tr("repo.wiki.new_page") - c.Data["PageIsWiki"] = true - c.Data["RequireSimpleMDE"] = true - - if !c.Repo.Repository.HasWiki() { - c.Data["title"] = "Home" - } - - c.HTML(200, WIKI_NEW) -} - -func NewWikiPost(c *context.Context, f form.NewWiki) { - c.Data["Title"] = c.Tr("repo.wiki.new_page") - c.Data["PageIsWiki"] = true - c.Data["RequireSimpleMDE"] = true - - if c.HasError() { - c.HTML(200, WIKI_NEW) - return - } - - if err := c.Repo.Repository.AddWikiPage(c.User, f.Title, f.Content, f.Message); err != nil { - if models.IsErrWikiAlreadyExist(err) { - c.Data["Err_Title"] = true - c.RenderWithErr(c.Tr("repo.wiki.page_already_exists"), WIKI_NEW, &f) - } else { - c.Handle(500, "AddWikiPage", err) - } - return - } - - c.Redirect(c.Repo.RepoLink + "/wiki/" + models.ToWikiPageURL(models.ToWikiPageName(f.Title))) -} - -func EditWiki(c *context.Context) { - c.Data["PageIsWiki"] = true - c.Data["PageIsWikiEdit"] = true - c.Data["RequireSimpleMDE"] = true - - if !c.Repo.Repository.HasWiki() { - c.Redirect(c.Repo.RepoLink + "/wiki") - return - } - - renderWikiPage(c, false) - if c.Written() { - return - } - - c.HTML(200, WIKI_NEW) -} - -func EditWikiPost(c *context.Context, f form.NewWiki) { - c.Data["Title"] = c.Tr("repo.wiki.new_page") - c.Data["PageIsWiki"] = true - c.Data["RequireSimpleMDE"] = true - - if c.HasError() { - c.HTML(200, WIKI_NEW) - return - } - - if err := c.Repo.Repository.EditWikiPage(c.User, f.OldTitle, f.Title, f.Content, f.Message); err != nil { - c.Handle(500, "EditWikiPage", err) - return - } - - c.Redirect(c.Repo.RepoLink + "/wiki/" + models.ToWikiPageURL(models.ToWikiPageName(f.Title))) -} - -func DeleteWikiPagePost(c *context.Context) { - pageURL := c.Params(":page") - if len(pageURL) == 0 { - pageURL = "Home" - } - - pageName := models.ToWikiPageName(pageURL) - if err := c.Repo.Repository.DeleteWikiPage(c.User, pageName); err != nil { - c.Handle(500, "DeleteWikiPage", err) - return - } - - c.JSON(200, map[string]interface{}{ - "redirect": c.Repo.RepoLink + "/wiki/", - }) -} diff --git a/routers/user/auth.go b/routers/user/auth.go deleted file mode 100644 index 34fdbd85..00000000 --- a/routers/user/auth.go +++ /dev/null @@ -1,534 +0,0 @@ -// 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 user - -import ( - "fmt" - "net/url" - - "github.com/go-macaron/captcha" - log "gopkg.in/clog.v1" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/form" - "github.com/gogits/gogs/pkg/mailer" - "github.com/gogits/gogs/pkg/setting" -) - -const ( - LOGIN = "user/auth/login" - TWO_FACTOR = "user/auth/two_factor" - TWO_FACTOR_RECOVERY_CODE = "user/auth/two_factor_recovery_code" - SIGNUP = "user/auth/signup" - ACTIVATE = "user/auth/activate" - FORGOT_PASSWORD = "user/auth/forgot_passwd" - RESET_PASSWORD = "user/auth/reset_passwd" -) - -// AutoLogin reads cookie and try to auto-login. -func AutoLogin(c *context.Context) (bool, error) { - if !models.HasEngine { - return false, nil - } - - uname := c.GetCookie(setting.CookieUserName) - if len(uname) == 0 { - return false, nil - } - - isSucceed := false - defer func() { - if !isSucceed { - log.Trace("auto-login cookie cleared: %s", uname) - c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL) - c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL) - c.SetCookie(setting.LoginStatusCookieName, "", -1, setting.AppSubURL) - } - }() - - u, err := models.GetUserByName(uname) - if err != nil { - if !errors.IsUserNotExist(err) { - return false, fmt.Errorf("GetUserByName: %v", err) - } - return false, nil - } - - if val, ok := c.GetSuperSecureCookie(u.Rands+u.Passwd, setting.CookieRememberName); !ok || val != u.Name { - return false, nil - } - - isSucceed = true - c.Session.Set("uid", u.ID) - c.Session.Set("uname", u.Name) - c.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL) - if setting.EnableLoginStatusCookie { - c.SetCookie(setting.LoginStatusCookieName, "true", 0, setting.AppSubURL) - } - return true, nil -} - -// isValidRedirect returns false if the URL does not redirect to same site. -// False: //url, http://url -// True: /url -func isValidRedirect(url string) bool { - return len(url) >= 2 && url[0] == '/' && url[1] != '/' -} - -func Login(c *context.Context) { - c.Data["Title"] = c.Tr("sign_in") - - // Check auto-login. - isSucceed, err := AutoLogin(c) - if err != nil { - c.Handle(500, "AutoLogin", err) - return - } - - redirectTo := c.Query("redirect_to") - if len(redirectTo) > 0 { - c.SetCookie("redirect_to", redirectTo, 0, setting.AppSubURL) - } else { - redirectTo, _ = url.QueryUnescape(c.GetCookie("redirect_to")) - } - c.SetCookie("redirect_to", "", -1, setting.AppSubURL) - - if isSucceed { - if isValidRedirect(redirectTo) { - c.Redirect(redirectTo) - } else { - c.Redirect(setting.AppSubURL + "/") - } - return - } - - c.HTML(200, LOGIN) -} - -func afterLogin(c *context.Context, u *models.User, remember bool) { - if remember { - days := 86400 * setting.LoginRememberDays - c.SetCookie(setting.CookieUserName, u.Name, days, setting.AppSubURL, "", setting.CookieSecure, true) - c.SetSuperSecureCookie(u.Rands+u.Passwd, setting.CookieRememberName, u.Name, days, setting.AppSubURL, "", setting.CookieSecure, true) - } - - c.Session.Set("uid", u.ID) - c.Session.Set("uname", u.Name) - c.Session.Delete("twoFactorRemember") - c.Session.Delete("twoFactorUserID") - - // Clear whatever CSRF has right now, force to generate a new one - c.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL) - if setting.EnableLoginStatusCookie { - c.SetCookie(setting.LoginStatusCookieName, "true", 0, setting.AppSubURL) - } - - redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")) - c.SetCookie("redirect_to", "", -1, setting.AppSubURL) - if isValidRedirect(redirectTo) { - c.Redirect(redirectTo) - return - } - - c.Redirect(setting.AppSubURL + "/") -} - -func LoginPost(c *context.Context, f form.SignIn) { - c.Data["Title"] = c.Tr("sign_in") - - if c.HasError() { - c.Success(LOGIN) - return - } - - u, err := models.UserSignIn(f.UserName, f.Password) - if err != nil { - if errors.IsUserNotExist(err) { - c.RenderWithErr(c.Tr("form.username_password_incorrect"), LOGIN, &f) - } else { - c.ServerError("UserSignIn", err) - } - return - } - - if !u.IsEnabledTwoFactor() { - afterLogin(c, u, f.Remember) - return - } - - c.Session.Set("twoFactorRemember", f.Remember) - c.Session.Set("twoFactorUserID", u.ID) - c.Redirect(setting.AppSubURL + "/user/login/two_factor") -} - -func LoginTwoFactor(c *context.Context) { - _, ok := c.Session.Get("twoFactorUserID").(int64) - if !ok { - c.NotFound() - return - } - - c.Success(TWO_FACTOR) -} - -func LoginTwoFactorPost(c *context.Context) { - userID, ok := c.Session.Get("twoFactorUserID").(int64) - if !ok { - c.NotFound() - return - } - - t, err := models.GetTwoFactorByUserID(userID) - if err != nil { - c.ServerError("GetTwoFactorByUserID", err) - return - } - valid, err := t.ValidateTOTP(c.Query("passcode")) - if err != nil { - c.ServerError("ValidateTOTP", err) - return - } else if !valid { - c.Flash.Error(c.Tr("settings.two_factor_invalid_passcode")) - c.Redirect(setting.AppSubURL + "/user/login/two_factor") - return - } - - u, err := models.GetUserByID(userID) - if err != nil { - c.ServerError("GetUserByID", err) - return - } - afterLogin(c, u, c.Session.Get("twoFactorRemember").(bool)) -} - -func LoginTwoFactorRecoveryCode(c *context.Context) { - _, ok := c.Session.Get("twoFactorUserID").(int64) - if !ok { - c.NotFound() - return - } - - c.Success(TWO_FACTOR_RECOVERY_CODE) -} - -func LoginTwoFactorRecoveryCodePost(c *context.Context) { - userID, ok := c.Session.Get("twoFactorUserID").(int64) - if !ok { - c.NotFound() - return - } - - if err := models.UseRecoveryCode(userID, c.Query("recovery_code")); err != nil { - if errors.IsTwoFactorRecoveryCodeNotFound(err) { - c.Flash.Error(c.Tr("auth.login_two_factor_invalid_recovery_code")) - c.Redirect(setting.AppSubURL + "/user/login/two_factor_recovery_code") - } else { - c.ServerError("UseRecoveryCode", err) - } - return - } - - u, err := models.GetUserByID(userID) - if err != nil { - c.ServerError("GetUserByID", err) - return - } - afterLogin(c, u, c.Session.Get("twoFactorRemember").(bool)) -} - -func SignOut(c *context.Context) { - c.Session.Delete("uid") - c.Session.Delete("uname") - c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubURL) - c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubURL) - c.SetCookie(setting.CSRFCookieName, "", -1, setting.AppSubURL) - c.Redirect(setting.AppSubURL + "/") -} - -func SignUp(c *context.Context) { - c.Data["Title"] = c.Tr("sign_up") - - c.Data["EnableCaptcha"] = setting.Service.EnableCaptcha - - if setting.Service.DisableRegistration { - c.Data["DisableRegistration"] = true - c.HTML(200, SIGNUP) - return - } - - c.HTML(200, SIGNUP) -} - -func SignUpPost(c *context.Context, cpt *captcha.Captcha, f form.Register) { - c.Data["Title"] = c.Tr("sign_up") - - c.Data["EnableCaptcha"] = setting.Service.EnableCaptcha - - if setting.Service.DisableRegistration { - c.Error(403) - return - } - - if c.HasError() { - c.HTML(200, SIGNUP) - return - } - - if setting.Service.EnableCaptcha && !cpt.VerifyReq(c.Req) { - c.Data["Err_Captcha"] = true - c.RenderWithErr(c.Tr("form.captcha_incorrect"), SIGNUP, &f) - return - } - - if f.Password != f.Retype { - c.Data["Err_Password"] = true - c.RenderWithErr(c.Tr("form.password_not_match"), SIGNUP, &f) - return - } - - u := &models.User{ - Name: f.UserName, - Email: f.Email, - Passwd: f.Password, - IsActive: !setting.Service.RegisterEmailConfirm, - } - 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"), SIGNUP, &f) - case models.IsErrEmailAlreadyUsed(err): - c.Data["Err_Email"] = true - c.RenderWithErr(c.Tr("form.email_been_used"), SIGNUP, &f) - case models.IsErrNameReserved(err): - c.Data["Err_UserName"] = true - c.RenderWithErr(c.Tr("user.form.name_reserved", err.(models.ErrNameReserved).Name), SIGNUP, &f) - case models.IsErrNamePatternNotAllowed(err): - c.Data["Err_UserName"] = true - c.RenderWithErr(c.Tr("user.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), SIGNUP, &f) - default: - c.Handle(500, "CreateUser", err) - } - return - } - log.Trace("Account created: %s", u.Name) - - // Auto-set admin for the only user. - if models.CountUsers() == 1 { - u.IsAdmin = true - u.IsActive = true - if err := models.UpdateUser(u); err != nil { - c.Handle(500, "UpdateUser", err) - return - } - } - - // Send confirmation email, no need for social account. - if setting.Service.RegisterEmailConfirm && u.ID > 1 { - mailer.SendActivateAccountMail(c.Context, models.NewMailerUser(u)) - c.Data["IsSendRegisterMail"] = true - c.Data["Email"] = u.Email - c.Data["Hours"] = setting.Service.ActiveCodeLives / 60 - c.HTML(200, ACTIVATE) - - if err := c.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { - log.Error(4, "Set cache(MailResendLimit) fail: %v", err) - } - return - } - - c.Redirect(setting.AppSubURL + "/user/login") -} - -func Activate(c *context.Context) { - code := c.Query("code") - if len(code) == 0 { - c.Data["IsActivatePage"] = true - if c.User.IsActive { - c.Error(404) - return - } - // Resend confirmation email. - if setting.Service.RegisterEmailConfirm { - if c.Cache.IsExist("MailResendLimit_" + c.User.LowerName) { - c.Data["ResendLimited"] = true - } else { - c.Data["Hours"] = setting.Service.ActiveCodeLives / 60 - mailer.SendActivateAccountMail(c.Context, models.NewMailerUser(c.User)) - - keyName := "MailResendLimit_" + c.User.LowerName - if err := c.Cache.Put(keyName, c.User.LowerName, 180); err != nil { - log.Error(2, "Set cache '%s' fail: %v", keyName, err) - } - } - } else { - c.Data["ServiceNotEnabled"] = true - } - c.HTML(200, ACTIVATE) - return - } - - // Verify code. - if user := models.VerifyUserActiveCode(code); user != nil { - user.IsActive = true - var err error - if user.Rands, err = models.GetUserSalt(); err != nil { - c.Handle(500, "UpdateUser", err) - return - } - if err := models.UpdateUser(user); err != nil { - c.Handle(500, "UpdateUser", err) - return - } - - log.Trace("User activated: %s", user.Name) - - c.Session.Set("uid", user.ID) - c.Session.Set("uname", user.Name) - c.Redirect(setting.AppSubURL + "/") - return - } - - c.Data["IsActivateFailed"] = true - c.HTML(200, ACTIVATE) -} - -func ActivateEmail(c *context.Context) { - code := c.Query("code") - email_string := c.Query("email") - - // Verify code. - if email := models.VerifyActiveEmailCode(code, email_string); email != nil { - if err := email.Activate(); err != nil { - c.Handle(500, "ActivateEmail", err) - } - - log.Trace("Email activated: %s", email.Email) - c.Flash.Success(c.Tr("settings.add_email_success")) - } - - c.Redirect(setting.AppSubURL + "/user/settings/email") - return -} - -func ForgotPasswd(c *context.Context) { - c.Data["Title"] = c.Tr("auth.forgot_password") - - if setting.MailService == nil { - c.Data["IsResetDisable"] = true - c.HTML(200, FORGOT_PASSWORD) - return - } - - c.Data["IsResetRequest"] = true - c.HTML(200, FORGOT_PASSWORD) -} - -func ForgotPasswdPost(c *context.Context) { - c.Data["Title"] = c.Tr("auth.forgot_password") - - if setting.MailService == nil { - c.Handle(403, "ForgotPasswdPost", nil) - return - } - c.Data["IsResetRequest"] = true - - email := c.Query("email") - c.Data["Email"] = email - - u, err := models.GetUserByEmail(email) - if err != nil { - if errors.IsUserNotExist(err) { - c.Data["Hours"] = setting.Service.ActiveCodeLives / 60 - c.Data["IsResetSent"] = true - c.HTML(200, FORGOT_PASSWORD) - return - } else { - c.Handle(500, "user.ResetPasswd(check existence)", err) - } - return - } - - if !u.IsLocal() { - c.Data["Err_Email"] = true - c.RenderWithErr(c.Tr("auth.non_local_account"), FORGOT_PASSWORD, nil) - return - } - - if c.Cache.IsExist("MailResendLimit_" + u.LowerName) { - c.Data["ResendLimited"] = true - c.HTML(200, FORGOT_PASSWORD) - return - } - - mailer.SendResetPasswordMail(c.Context, models.NewMailerUser(u)) - if err = c.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { - log.Error(4, "Set cache(MailResendLimit) fail: %v", err) - } - - c.Data["Hours"] = setting.Service.ActiveCodeLives / 60 - c.Data["IsResetSent"] = true - c.HTML(200, FORGOT_PASSWORD) -} - -func ResetPasswd(c *context.Context) { - c.Data["Title"] = c.Tr("auth.reset_password") - - code := c.Query("code") - if len(code) == 0 { - c.Error(404) - return - } - c.Data["Code"] = code - c.Data["IsResetForm"] = true - c.HTML(200, RESET_PASSWORD) -} - -func ResetPasswdPost(c *context.Context) { - c.Data["Title"] = c.Tr("auth.reset_password") - - code := c.Query("code") - if len(code) == 0 { - c.Error(404) - return - } - c.Data["Code"] = code - - if u := models.VerifyUserActiveCode(code); u != nil { - // Validate password length. - passwd := c.Query("password") - if len(passwd) < 6 { - c.Data["IsResetForm"] = true - c.Data["Err_Password"] = true - c.RenderWithErr(c.Tr("auth.password_too_short"), RESET_PASSWORD, nil) - return - } - - u.Passwd = passwd - var err error - if u.Rands, err = models.GetUserSalt(); err != nil { - c.Handle(500, "UpdateUser", err) - return - } - if u.Salt, err = models.GetUserSalt(); err != nil { - c.Handle(500, "UpdateUser", err) - return - } - u.EncodePasswd() - if err := models.UpdateUser(u); err != nil { - c.Handle(500, "UpdateUser", err) - return - } - - log.Trace("User password reset: %s", u.Name) - c.Redirect(setting.AppSubURL + "/user/login") - return - } - - c.Data["IsResetFailed"] = true - c.HTML(200, RESET_PASSWORD) -} diff --git a/routers/user/home.go b/routers/user/home.go deleted file mode 100644 index c3b9b182..00000000 --- a/routers/user/home.go +++ /dev/null @@ -1,424 +0,0 @@ -// 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 user - -import ( - "bytes" - "fmt" - - "github.com/Unknwon/com" - "github.com/Unknwon/paginater" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" -) - -const ( - DASHBOARD = "user/dashboard/dashboard" - NEWS_FEED = "user/dashboard/feeds" - ISSUES = "user/dashboard/issues" - PROFILE = "user/profile" - ORG_HOME = "org/home" -) - -// getDashboardContextUser finds out dashboard is viewing as which context user. -func getDashboardContextUser(c *context.Context) *models.User { - ctxUser := c.User - orgName := c.Params(":org") - if len(orgName) > 0 { - // Organization. - org, err := models.GetUserByName(orgName) - if err != nil { - c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err) - return nil - } - ctxUser = org - } - c.Data["ContextUser"] = ctxUser - - if err := c.User.GetOrganizations(true); err != nil { - c.Handle(500, "GetOrganizations", err) - return nil - } - c.Data["Orgs"] = c.User.Orgs - - return ctxUser -} - -// retrieveFeeds loads feeds from database by given context user. -// The user could be organization so it is not always the logged in user, -// which is why we have to explicitly pass the context user ID. -func retrieveFeeds(c *context.Context, ctxUser *models.User, userID int64, isProfile bool) { - actions, err := models.GetFeeds(ctxUser, userID, c.QueryInt64("after_id"), isProfile) - if err != nil { - c.Handle(500, "GetFeeds", err) - return - } - - // Check access of private repositories. - feeds := make([]*models.Action, 0, len(actions)) - unameAvatars := make(map[string]string) - for _, act := range actions { - // Cache results to reduce queries. - _, ok := unameAvatars[act.ActUserName] - if !ok { - u, err := models.GetUserByName(act.ActUserName) - if err != nil { - if errors.IsUserNotExist(err) { - continue - } - c.Handle(500, "GetUserByName", err) - return - } - unameAvatars[act.ActUserName] = u.RelAvatarLink() - } - - act.ActAvatar = unameAvatars[act.ActUserName] - feeds = append(feeds, act) - } - c.Data["Feeds"] = feeds - if len(feeds) > 0 { - afterID := feeds[len(feeds)-1].ID - c.Data["AfterID"] = afterID - c.Header().Set("X-AJAX-URL", fmt.Sprintf("%s?after_id=%d", c.Data["Link"], afterID)) - } -} - -func Dashboard(c *context.Context) { - ctxUser := getDashboardContextUser(c) - if c.Written() { - return - } - - retrieveFeeds(c, ctxUser, c.User.ID, false) - if c.Written() { - return - } - - if c.Req.Header.Get("X-AJAX") == "true" { - c.HTML(200, NEWS_FEED) - return - } - - c.Data["Title"] = ctxUser.DisplayName() + " - " + c.Tr("dashboard") - c.Data["PageIsDashboard"] = true - c.Data["PageIsNews"] = true - - // Only user can have collaborative repositories. - if !ctxUser.IsOrganization() { - collaborateRepos, err := c.User.GetAccessibleRepositories(setting.UI.User.RepoPagingNum) - if err != nil { - c.Handle(500, "GetAccessibleRepositories", err) - return - } else if err = models.RepositoryList(collaborateRepos).LoadAttributes(); err != nil { - c.Handle(500, "RepositoryList.LoadAttributes", err) - return - } - c.Data["CollaborativeRepos"] = collaborateRepos - } - - var err error - var repos, mirrors []*models.Repository - var repoCount int64 - if ctxUser.IsOrganization() { - repos, repoCount, err = ctxUser.GetUserRepositories(c.User.ID, 1, setting.UI.User.RepoPagingNum) - if err != nil { - c.Handle(500, "GetUserRepositories", err) - return - } - - mirrors, err = ctxUser.GetUserMirrorRepositories(c.User.ID) - if err != nil { - c.Handle(500, "GetUserMirrorRepositories", err) - return - } - } else { - if err = ctxUser.GetRepositories(1, setting.UI.User.RepoPagingNum); err != nil { - c.Handle(500, "GetRepositories", err) - return - } - repos = ctxUser.Repos - repoCount = int64(ctxUser.NumRepos) - - mirrors, err = ctxUser.GetMirrorRepositories() - if err != nil { - c.Handle(500, "GetMirrorRepositories", err) - return - } - } - c.Data["Repos"] = repos - c.Data["RepoCount"] = repoCount - c.Data["MaxShowRepoNum"] = setting.UI.User.RepoPagingNum - - if err := models.MirrorRepositoryList(mirrors).LoadAttributes(); err != nil { - c.Handle(500, "MirrorRepositoryList.LoadAttributes", err) - return - } - c.Data["MirrorCount"] = len(mirrors) - c.Data["Mirrors"] = mirrors - - c.HTML(200, DASHBOARD) -} - -func Issues(c *context.Context) { - isPullList := c.Params(":type") == "pulls" - if isPullList { - c.Data["Title"] = c.Tr("pull_requests") - c.Data["PageIsPulls"] = true - } else { - c.Data["Title"] = c.Tr("issues") - c.Data["PageIsIssues"] = true - } - - ctxUser := getDashboardContextUser(c) - if c.Written() { - return - } - - var ( - sortType = c.Query("sort") - filterMode = models.FILTER_MODE_YOUR_REPOS - ) - - // Note: Organization does not have view type and filter mode. - if !ctxUser.IsOrganization() { - viewType := c.Query("type") - types := []string{ - string(models.FILTER_MODE_YOUR_REPOS), - string(models.FILTER_MODE_ASSIGN), - string(models.FILTER_MODE_CREATE), - } - if !com.IsSliceContainsStr(types, viewType) { - viewType = string(models.FILTER_MODE_YOUR_REPOS) - } - filterMode = models.FilterMode(viewType) - } - - page := c.QueryInt("page") - if page <= 1 { - page = 1 - } - - repoID := c.QueryInt64("repo") - isShowClosed := c.Query("state") == "closed" - - // Get repositories. - var ( - err error - repos []*models.Repository - userRepoIDs []int64 - showRepos = make([]*models.Repository, 0, 10) - ) - if ctxUser.IsOrganization() { - repos, _, err = ctxUser.GetUserRepositories(c.User.ID, 1, ctxUser.NumRepos) - if err != nil { - c.Handle(500, "GetRepositories", err) - return - } - } else { - if err := ctxUser.GetRepositories(1, c.User.NumRepos); err != nil { - c.Handle(500, "GetRepositories", err) - return - } - repos = ctxUser.Repos - } - - userRepoIDs = make([]int64, 0, len(repos)) - for _, repo := range repos { - userRepoIDs = append(userRepoIDs, repo.ID) - - if filterMode != models.FILTER_MODE_YOUR_REPOS { - continue - } - - if isPullList { - if isShowClosed && repo.NumClosedPulls == 0 || - !isShowClosed && repo.NumOpenPulls == 0 { - continue - } - } else { - if !repo.EnableIssues || repo.EnableExternalTracker || - isShowClosed && repo.NumClosedIssues == 0 || - !isShowClosed && repo.NumOpenIssues == 0 { - continue - } - } - - showRepos = append(showRepos, repo) - } - - // Filter repositories if the page shows issues. - if !isPullList { - userRepoIDs, err = models.FilterRepositoryWithIssues(userRepoIDs) - if err != nil { - c.Handle(500, "FilterRepositoryWithIssues", err) - return - } - } - - issueOptions := &models.IssuesOptions{ - RepoID: repoID, - Page: page, - IsClosed: isShowClosed, - IsPull: isPullList, - SortType: sortType, - } - switch filterMode { - case models.FILTER_MODE_YOUR_REPOS: - // Get all issues from repositories from this user. - if userRepoIDs == nil { - issueOptions.RepoIDs = []int64{-1} - } else { - issueOptions.RepoIDs = userRepoIDs - } - - case models.FILTER_MODE_ASSIGN: - // Get all issues assigned to this user. - issueOptions.AssigneeID = ctxUser.ID - - case models.FILTER_MODE_CREATE: - // Get all issues created by this user. - issueOptions.PosterID = ctxUser.ID - } - - issues, err := models.Issues(issueOptions) - if err != nil { - c.Handle(500, "Issues", err) - return - } - - if repoID > 0 { - repo, err := models.GetRepositoryByID(repoID) - if err != nil { - c.Handle(500, "GetRepositoryByID", fmt.Errorf("[#%d] %v", repoID, err)) - return - } - - if err = repo.GetOwner(); err != nil { - c.Handle(500, "GetOwner", fmt.Errorf("[#%d] %v", repoID, err)) - return - } - - // Check if user has access to given repository. - if !repo.IsOwnedBy(ctxUser.ID) && !repo.HasAccess(ctxUser.ID) { - c.Handle(404, "Issues", fmt.Errorf("#%d", repoID)) - return - } - } - - for _, issue := range issues { - if err = issue.Repo.GetOwner(); err != nil { - c.Handle(500, "GetOwner", fmt.Errorf("[#%d] %v", issue.RepoID, err)) - return - } - } - - issueStats := models.GetUserIssueStats(repoID, ctxUser.ID, userRepoIDs, filterMode, isPullList) - - var total int - if !isShowClosed { - total = int(issueStats.OpenCount) - } else { - total = int(issueStats.ClosedCount) - } - - c.Data["Issues"] = issues - c.Data["Repos"] = showRepos - c.Data["Page"] = paginater.New(total, setting.UI.IssuePagingNum, page, 5) - c.Data["IssueStats"] = issueStats - c.Data["ViewType"] = string(filterMode) - c.Data["SortType"] = sortType - c.Data["RepoID"] = repoID - c.Data["IsShowClosed"] = isShowClosed - - if isShowClosed { - c.Data["State"] = "closed" - } else { - c.Data["State"] = "open" - } - - c.HTML(200, ISSUES) -} - -func ShowSSHKeys(c *context.Context, uid int64) { - keys, err := models.ListPublicKeys(uid) - if err != nil { - c.Handle(500, "ListPublicKeys", err) - return - } - - var buf bytes.Buffer - for i := range keys { - buf.WriteString(keys[i].OmitEmail()) - buf.WriteString("\n") - } - c.PlainText(200, buf.Bytes()) -} - -func showOrgProfile(c *context.Context) { - c.SetParams(":org", c.Params(":username")) - context.HandleOrgAssignment(c) - if c.Written() { - return - } - - org := c.Org.Organization - c.Data["Title"] = org.FullName - - page := c.QueryInt("page") - if page <= 0 { - page = 1 - } - - var ( - repos []*models.Repository - count int64 - err error - ) - if c.IsLogged && !c.User.IsAdmin { - repos, count, err = org.GetUserRepositories(c.User.ID, page, setting.UI.User.RepoPagingNum) - if err != nil { - c.Handle(500, "GetUserRepositories", err) - return - } - c.Data["Repos"] = repos - } else { - showPrivate := c.IsLogged && c.User.IsAdmin - repos, err = models.GetUserRepositories(&models.UserRepoOptions{ - UserID: org.ID, - Private: showPrivate, - Page: page, - PageSize: setting.UI.User.RepoPagingNum, - }) - if err != nil { - c.Handle(500, "GetRepositories", err) - return - } - c.Data["Repos"] = repos - count = models.CountUserRepositories(org.ID, showPrivate) - } - c.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5) - - if err := org.GetMembers(); err != nil { - c.Handle(500, "GetMembers", err) - return - } - c.Data["Members"] = org.Members - - c.Data["Teams"] = org.Teams - - c.HTML(200, ORG_HOME) -} - -func Email2User(c *context.Context) { - u, err := models.GetUserByEmail(c.Query("email")) - if err != nil { - c.NotFoundOrServerError("GetUserByEmail", errors.IsUserNotExist, err) - return - } - c.Redirect(setting.AppSubURL + "/user/" + u.Name) -} diff --git a/routers/user/profile.go b/routers/user/profile.go deleted file mode 100644 index dc8ba6ae..00000000 --- a/routers/user/profile.go +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2015 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 user - -import ( - "fmt" - "path" - "strings" - - "github.com/Unknwon/paginater" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "github.com/gogits/gogs/pkg/context" - "github.com/gogits/gogs/pkg/setting" - "github.com/gogits/gogs/routers/repo" -) - -const ( - FOLLOWERS = "user/meta/followers" - STARS = "user/meta/stars" -) - -func GetUserByName(c *context.Context, name string) *models.User { - user, err := models.GetUserByName(name) - if err != nil { - c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err) - return nil - } - return user -} - -// GetUserByParams returns user whose name is presented in URL paramenter. -func GetUserByParams(c *context.Context) *models.User { - return GetUserByName(c, c.Params(":username")) -} - -func Profile(c *context.Context) { - uname := c.Params(":username") - // Special handle for FireFox requests favicon.ico. - if uname == "favicon.ico" { - c.ServeFile(path.Join(setting.StaticRootPath, "public/img/favicon.png")) - return - } else if strings.HasSuffix(uname, ".png") { - c.Error(404) - return - } - - isShowKeys := false - if strings.HasSuffix(uname, ".keys") { - isShowKeys = true - } - - ctxUser := GetUserByName(c, strings.TrimSuffix(uname, ".keys")) - if c.Written() { - return - } - - // Show SSH keys. - if isShowKeys { - ShowSSHKeys(c, ctxUser.ID) - return - } - - if ctxUser.IsOrganization() { - showOrgProfile(c) - return - } - - c.Data["Title"] = ctxUser.DisplayName() - c.Data["PageIsUserProfile"] = true - c.Data["Owner"] = ctxUser - - orgs, err := models.GetOrgsByUserID(ctxUser.ID, c.IsLogged && (c.User.IsAdmin || c.User.ID == ctxUser.ID)) - if err != nil { - c.Handle(500, "GetOrgsByUserIDDesc", err) - return - } - - c.Data["Orgs"] = orgs - - tab := c.Query("tab") - c.Data["TabName"] = tab - switch tab { - case "activity": - retrieveFeeds(c, ctxUser, -1, true) - if c.Written() { - return - } - default: - page := c.QueryInt("page") - if page <= 0 { - page = 1 - } - - showPrivate := c.IsLogged && (ctxUser.ID == c.User.ID || c.User.IsAdmin) - c.Data["Repos"], err = models.GetUserRepositories(&models.UserRepoOptions{ - UserID: ctxUser.ID, - Private: showPrivate, - Page: page, - PageSize: setting.UI.User.RepoPagingNum, - }) - if err != nil { - c.Handle(500, "GetRepositories", err) - return - } - - count := models.CountUserRepositories(ctxUser.ID, showPrivate) - c.Data["Page"] = paginater.New(int(count), setting.UI.User.RepoPagingNum, page, 5) - } - - c.HTML(200, PROFILE) -} - -func Followers(c *context.Context) { - u := GetUserByParams(c) - if c.Written() { - return - } - c.Data["Title"] = u.DisplayName() - c.Data["CardsTitle"] = c.Tr("user.followers") - c.Data["PageIsFollowers"] = true - c.Data["Owner"] = u - repo.RenderUserCards(c, u.NumFollowers, u.GetFollowers, FOLLOWERS) -} - -func Following(c *context.Context) { - u := GetUserByParams(c) - if c.Written() { - return - } - c.Data["Title"] = u.DisplayName() - c.Data["CardsTitle"] = c.Tr("user.following") - c.Data["PageIsFollowing"] = true - c.Data["Owner"] = u - repo.RenderUserCards(c, u.NumFollowing, u.GetFollowing, FOLLOWERS) -} - -func Stars(c *context.Context) { - -} - -func Action(c *context.Context) { - u := GetUserByParams(c) - if c.Written() { - return - } - - var err error - switch c.Params(":action") { - case "follow": - err = models.FollowUser(c.User.ID, u.ID) - case "unfollow": - err = models.UnfollowUser(c.User.ID, u.ID) - } - - if err != nil { - c.Handle(500, fmt.Sprintf("Action (%s)", c.Params(":action")), err) - return - } - - redirectTo := c.Query("redirect_to") - if len(redirectTo) == 0 { - redirectTo = u.HomeLink() - } - c.Redirect(redirectTo) -} diff --git a/routers/user/setting.go b/routers/user/setting.go deleted file mode 100644 index 723b3da2..00000000 --- a/routers/user/setting.go +++ /dev/null @@ -1,664 +0,0 @@ -// 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 user - -import ( - "bytes" - "encoding/base64" - "fmt" - "html/template" - "image/png" - "io/ioutil" - "strings" - - "github.com/Unknwon/com" - "github.com/pquerna/otp" - "github.com/pquerna/otp/totp" - log "gopkg.in/clog.v1" - - "github.com/gogits/gogs/models" - "github.com/gogits/gogs/models/errors" - "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/pkg/tool" -) - -const ( - SETTINGS_PROFILE = "user/settings/profile" - SETTINGS_AVATAR = "user/settings/avatar" - SETTINGS_PASSWORD = "user/settings/password" - SETTINGS_EMAILS = "user/settings/email" - SETTINGS_SSH_KEYS = "user/settings/sshkeys" - SETTINGS_SECURITY = "user/settings/security" - SETTINGS_TWO_FACTOR_ENABLE = "user/settings/two_factor_enable" - SETTINGS_TWO_FACTOR_RECOVERY_CODES = "user/settings/two_factor_recovery_codes" - SETTINGS_REPOSITORIES = "user/settings/repositories" - SETTINGS_ORGANIZATIONS = "user/settings/organizations" - SETTINGS_APPLICATIONS = "user/settings/applications" - SETTINGS_DELETE = "user/settings/delete" - NOTIFICATION = "user/notification" -) - -func Settings(c *context.Context) { - c.Title("settings.profile") - c.PageIs("SettingsProfile") - c.Data["origin_name"] = c.User.Name - c.Data["name"] = c.User.Name - c.Data["full_name"] = c.User.FullName - c.Data["email"] = c.User.Email - c.Data["website"] = c.User.Website - c.Data["location"] = c.User.Location - c.Success(SETTINGS_PROFILE) -} - -func SettingsPost(c *context.Context, f form.UpdateProfile) { - c.Title("settings.profile") - c.PageIs("SettingsProfile") - c.Data["origin_name"] = c.User.Name - - if c.HasError() { - c.Success(SETTINGS_PROFILE) - return - } - - // Non-local users are not allowed to change their username - if c.User.IsLocal() { - // Check if username characters have been changed - if c.User.LowerName != strings.ToLower(f.Name) { - if err := models.ChangeUserName(c.User, f.Name); err != nil { - c.FormErr("Name") - var msg string - switch { - case models.IsErrUserAlreadyExist(err): - msg = c.Tr("form.username_been_taken") - case models.IsErrEmailAlreadyUsed(err): - msg = c.Tr("form.email_been_used") - case models.IsErrNameReserved(err): - msg = c.Tr("form.name_reserved") - case models.IsErrNamePatternNotAllowed(err): - msg = c.Tr("form.name_pattern_not_allowed") - default: - c.ServerError("ChangeUserName", err) - return - } - - c.RenderWithErr(msg, SETTINGS_PROFILE, &f) - return - } - - log.Trace("Username changed: %s -> %s", c.User.Name, f.Name) - } - - // In case it's just a case change - c.User.Name = f.Name - c.User.LowerName = strings.ToLower(f.Name) - } - - c.User.FullName = f.FullName - c.User.Email = f.Email - c.User.Website = f.Website - c.User.Location = f.Location - if err := models.UpdateUser(c.User); err != nil { - c.ServerError("UpdateUser", err) - return - } - - c.Flash.Success(c.Tr("settings.update_profile_success")) - c.SubURLRedirect("/user/settings") -} - -// FIXME: limit size. -func UpdateAvatarSetting(c *context.Context, f form.Avatar, ctxUser *models.User) error { - ctxUser.UseCustomAvatar = f.Source == form.AVATAR_LOCAL - if len(f.Gravatar) > 0 { - ctxUser.Avatar = tool.MD5(f.Gravatar) - ctxUser.AvatarEmail = f.Gravatar - } - - if f.Avatar != nil { - r, err := f.Avatar.Open() - if err != nil { - return fmt.Errorf("Avatar.Open: %v", err) - } - defer r.Close() - - data, err := ioutil.ReadAll(r) - if err != nil { - return fmt.Errorf("ioutil.ReadAll: %v", err) - } - if !tool.IsImageFile(data) { - return errors.New(c.Tr("settings.uploaded_avatar_not_a_image")) - } - if err = ctxUser.UploadAvatar(data); err != nil { - return fmt.Errorf("UploadAvatar: %v", err) - } - } else { - // No avatar is uploaded but setting has been changed to enable, - // generate a random one when needed. - if ctxUser.UseCustomAvatar && !com.IsFile(ctxUser.CustomAvatarPath()) { - if err := ctxUser.GenerateRandomAvatar(); err != nil { - log.Error(4, "GenerateRandomAvatar[%d]: %v", ctxUser.ID, err) - } - } - } - - if err := models.UpdateUser(ctxUser); err != nil { - return fmt.Errorf("UpdateUser: %v", err) - } - - return nil -} - -func SettingsAvatar(c *context.Context) { - c.Title("settings.avatar") - c.PageIs("SettingsAvatar") - c.Success(SETTINGS_AVATAR) -} - -func SettingsAvatarPost(c *context.Context, f form.Avatar) { - if err := UpdateAvatarSetting(c, f, c.User); err != nil { - c.Flash.Error(err.Error()) - } else { - c.Flash.Success(c.Tr("settings.update_avatar_success")) - } - - c.SubURLRedirect("/user/settings/avatar") -} - -func SettingsDeleteAvatar(c *context.Context) { - if err := c.User.DeleteAvatar(); err != nil { - c.Flash.Error(fmt.Sprintf("DeleteAvatar: %v", err)) - } - - c.SubURLRedirect("/user/settings/avatar") -} - -func SettingsPassword(c *context.Context) { - c.Title("settings.password") - c.PageIs("SettingsPassword") - c.Success(SETTINGS_PASSWORD) -} - -func SettingsPasswordPost(c *context.Context, f form.ChangePassword) { - c.Title("settings.password") - c.PageIs("SettingsPassword") - - if c.HasError() { - c.Success(SETTINGS_PASSWORD) - return - } - - if !c.User.ValidatePassword(f.OldPassword) { - c.Flash.Error(c.Tr("settings.password_incorrect")) - } else if f.Password != f.Retype { - c.Flash.Error(c.Tr("form.password_not_match")) - } else { - c.User.Passwd = f.Password - var err error - if c.User.Salt, err = models.GetUserSalt(); err != nil { - c.ServerError("GetUserSalt", err) - return - } - c.User.EncodePasswd() - if err := models.UpdateUser(c.User); err != nil { - c.ServerError("UpdateUser", err) - return - } - c.Flash.Success(c.Tr("settings.change_password_success")) - } - - c.SubURLRedirect("/user/settings/password") -} - -func SettingsEmails(c *context.Context) { - c.Title("settings.emails") - c.PageIs("SettingsEmails") - - emails, err := models.GetEmailAddresses(c.User.ID) - if err != nil { - c.ServerError("GetEmailAddresses", err) - return - } - c.Data["Emails"] = emails - - c.Success(SETTINGS_EMAILS) -} - -func SettingsEmailPost(c *context.Context, f form.AddEmail) { - c.Title("settings.emails") - c.PageIs("SettingsEmails") - - // Make emailaddress primary. - if c.Query("_method") == "PRIMARY" { - if err := models.MakeEmailPrimary(&models.EmailAddress{ID: c.QueryInt64("id")}); err != nil { - c.ServerError("MakeEmailPrimary", err) - return - } - - c.SubURLRedirect("/user/settings/email") - return - } - - // Add Email address. - emails, err := models.GetEmailAddresses(c.User.ID) - if err != nil { - c.ServerError("GetEmailAddresses", err) - return - } - c.Data["Emails"] = emails - - if c.HasError() { - c.Success(SETTINGS_EMAILS) - return - } - - email := &models.EmailAddress{ - UID: c.User.ID, - Email: f.Email, - IsActivated: !setting.Service.RegisterEmailConfirm, - } - if err := models.AddEmailAddress(email); err != nil { - if models.IsErrEmailAlreadyUsed(err) { - c.RenderWithErr(c.Tr("form.email_been_used"), SETTINGS_EMAILS, &f) - } else { - c.ServerError("AddEmailAddress", err) - } - return - } - - // Send confirmation email - if setting.Service.RegisterEmailConfirm { - mailer.SendActivateEmailMail(c.Context, models.NewMailerUser(c.User), email.Email) - - if err := c.Cache.Put("MailResendLimit_"+c.User.LowerName, c.User.LowerName, 180); err != nil { - log.Error(2, "Set cache 'MailResendLimit' failed: %v", err) - } - c.Flash.Info(c.Tr("settings.add_email_confirmation_sent", email.Email, setting.Service.ActiveCodeLives/60)) - } else { - c.Flash.Success(c.Tr("settings.add_email_success")) - } - - c.SubURLRedirect("/user/settings/email") -} - -func DeleteEmail(c *context.Context) { - if err := models.DeleteEmailAddress(&models.EmailAddress{ - ID: c.QueryInt64("id"), - UID: c.User.ID, - }); err != nil { - c.ServerError("DeleteEmailAddress", err) - return - } - - c.Flash.Success(c.Tr("settings.email_deletion_success")) - c.JSONSuccess(map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/email", - }) -} - -func SettingsSSHKeys(c *context.Context) { - c.Title("settings.ssh_keys") - c.PageIs("SettingsSSHKeys") - - keys, err := models.ListPublicKeys(c.User.ID) - if err != nil { - c.ServerError("ListPublicKeys", err) - return - } - c.Data["Keys"] = keys - - c.Success(SETTINGS_SSH_KEYS) -} - -func SettingsSSHKeysPost(c *context.Context, f form.AddSSHKey) { - c.Title("settings.ssh_keys") - c.PageIs("SettingsSSHKeys") - - keys, err := models.ListPublicKeys(c.User.ID) - if err != nil { - c.ServerError("ListPublicKeys", err) - return - } - c.Data["Keys"] = keys - - if c.HasError() { - c.Success(SETTINGS_SSH_KEYS) - return - } - - content, err := models.CheckPublicKeyString(f.Content) - if err != nil { - if models.IsErrKeyUnableVerify(err) { - c.Flash.Info(c.Tr("form.unable_verify_ssh_key")) - } else { - c.Flash.Error(c.Tr("form.invalid_ssh_key", err.Error())) - c.SubURLRedirect("/user/settings/ssh") - return - } - } - - if _, err = models.AddPublicKey(c.User.ID, f.Title, content); err != nil { - c.Data["HasError"] = true - switch { - case models.IsErrKeyAlreadyExist(err): - c.FormErr("Content") - c.RenderWithErr(c.Tr("settings.ssh_key_been_used"), SETTINGS_SSH_KEYS, &f) - case models.IsErrKeyNameAlreadyUsed(err): - c.FormErr("Title") - c.RenderWithErr(c.Tr("settings.ssh_key_name_used"), SETTINGS_SSH_KEYS, &f) - default: - c.ServerError("AddPublicKey", err) - } - return - } - - c.Flash.Success(c.Tr("settings.add_key_success", f.Title)) - c.SubURLRedirect("/user/settings/ssh") -} - -func DeleteSSHKey(c *context.Context) { - if err := models.DeletePublicKey(c.User, c.QueryInt64("id")); err != nil { - c.Flash.Error("DeletePublicKey: " + err.Error()) - } else { - c.Flash.Success(c.Tr("settings.ssh_key_deletion_success")) - } - - c.JSONSuccess(map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/ssh", - }) -} - -func SettingsSecurity(c *context.Context) { - c.Title("settings.security") - c.PageIs("SettingsSecurity") - - t, err := models.GetTwoFactorByUserID(c.UserID()) - if err != nil && !errors.IsTwoFactorNotFound(err) { - c.ServerError("GetTwoFactorByUserID", err) - return - } - c.Data["TwoFactor"] = t - - c.Success(SETTINGS_SECURITY) -} - -func SettingsTwoFactorEnable(c *context.Context) { - if c.User.IsEnabledTwoFactor() { - c.NotFound() - return - } - - c.Title("settings.two_factor_enable_title") - c.PageIs("SettingsSecurity") - - var key *otp.Key - var err error - keyURL := c.Session.Get("twoFactorURL") - if keyURL != nil { - key, _ = otp.NewKeyFromURL(keyURL.(string)) - } - if key == nil { - key, err = totp.Generate(totp.GenerateOpts{ - Issuer: setting.AppName, - AccountName: c.User.Email, - }) - if err != nil { - c.ServerError("Generate", err) - return - } - } - c.Data["TwoFactorSecret"] = key.Secret() - - img, err := key.Image(240, 240) - if err != nil { - c.ServerError("Image", err) - return - } - - var buf bytes.Buffer - if err = png.Encode(&buf, img); err != nil { - c.ServerError("Encode", err) - return - } - c.Data["QRCode"] = template.URL("data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes())) - - c.Session.Set("twoFactorSecret", c.Data["TwoFactorSecret"]) - c.Session.Set("twoFactorURL", key.String()) - c.Success(SETTINGS_TWO_FACTOR_ENABLE) -} - -func SettingsTwoFactorEnablePost(c *context.Context) { - secret, ok := c.Session.Get("twoFactorSecret").(string) - if !ok { - c.NotFound() - return - } - - if !totp.Validate(c.Query("passcode"), secret) { - c.Flash.Error(c.Tr("settings.two_factor_invalid_passcode")) - c.SubURLRedirect("/user/settings/security/two_factor_enable") - return - } - - if err := models.NewTwoFactor(c.UserID(), secret); err != nil { - c.Flash.Error(c.Tr("settings.two_factor_enable_error", err)) - c.SubURLRedirect("/user/settings/security/two_factor_enable") - return - } - - c.Session.Delete("twoFactorSecret") - c.Session.Delete("twoFactorURL") - c.Flash.Success(c.Tr("settings.two_factor_enable_success")) - c.SubURLRedirect("/user/settings/security/two_factor_recovery_codes") -} - -func SettingsTwoFactorRecoveryCodes(c *context.Context) { - if !c.User.IsEnabledTwoFactor() { - c.NotFound() - return - } - - c.Title("settings.two_factor_recovery_codes_title") - c.PageIs("SettingsSecurity") - - recoveryCodes, err := models.GetRecoveryCodesByUserID(c.UserID()) - if err != nil { - c.ServerError("GetRecoveryCodesByUserID", err) - return - } - c.Data["RecoveryCodes"] = recoveryCodes - - c.Success(SETTINGS_TWO_FACTOR_RECOVERY_CODES) -} - -func SettingsTwoFactorRecoveryCodesPost(c *context.Context) { - if !c.User.IsEnabledTwoFactor() { - c.NotFound() - return - } - - if err := models.RegenerateRecoveryCodes(c.UserID()); err != nil { - c.Flash.Error(c.Tr("settings.two_factor_regenerate_recovery_codes_error", err)) - } else { - c.Flash.Success(c.Tr("settings.two_factor_regenerate_recovery_codes_success")) - } - - c.SubURLRedirect("/user/settings/security/two_factor_recovery_codes") -} - -func SettingsTwoFactorDisable(c *context.Context) { - if !c.User.IsEnabledTwoFactor() { - c.NotFound() - return - } - - if err := models.DeleteTwoFactor(c.UserID()); err != nil { - c.ServerError("DeleteTwoFactor", err) - return - } - - c.Flash.Success(c.Tr("settings.two_factor_disable_success")) - c.JSONSuccess(map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/security", - }) -} - -func SettingsRepos(c *context.Context) { - c.Title("settings.repos") - c.PageIs("SettingsRepositories") - - repos, err := models.GetUserAndCollaborativeRepositories(c.User.ID) - if err != nil { - c.ServerError("GetUserAndCollaborativeRepositories", err) - return - } - if err = models.RepositoryList(repos).LoadAttributes(); err != nil { - c.ServerError("LoadAttributes", err) - return - } - c.Data["Repos"] = repos - - c.Success(SETTINGS_REPOSITORIES) -} - -func SettingsLeaveRepo(c *context.Context) { - repo, err := models.GetRepositoryByID(c.QueryInt64("id")) - if err != nil { - c.NotFoundOrServerError("GetRepositoryByID", errors.IsRepoNotExist, err) - return - } - - if err = repo.DeleteCollaboration(c.User.ID); err != nil { - c.ServerError("DeleteCollaboration", err) - return - } - - c.Flash.Success(c.Tr("settings.repos.leave_success", repo.FullName())) - c.JSONSuccess(map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/repositories", - }) -} - -func SettingsOrganizations(c *context.Context) { - c.Title("settings.orgs") - c.PageIs("SettingsOrganizations") - - orgs, err := models.GetOrgsByUserID(c.User.ID, true) - if err != nil { - c.ServerError("GetOrgsByUserID", err) - return - } - c.Data["Orgs"] = orgs - - c.Success(SETTINGS_ORGANIZATIONS) -} - -func SettingsLeaveOrganization(c *context.Context) { - if err := models.RemoveOrgUser(c.QueryInt64("id"), c.User.ID); err != nil { - if models.IsErrLastOrgOwner(err) { - c.Flash.Error(c.Tr("form.last_org_owner")) - } else { - c.ServerError("RemoveOrgUser", err) - return - } - } - - c.JSONSuccess(map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/organizations", - }) -} - -func SettingsApplications(c *context.Context) { - c.Title("settings.applications") - c.PageIs("SettingsApplications") - - tokens, err := models.ListAccessTokens(c.User.ID) - if err != nil { - c.ServerError("ListAccessTokens", err) - return - } - c.Data["Tokens"] = tokens - - c.Success(SETTINGS_APPLICATIONS) -} - -func SettingsApplicationsPost(c *context.Context, f form.NewAccessToken) { - c.Title("settings.applications") - c.PageIs("SettingsApplications") - - if c.HasError() { - tokens, err := models.ListAccessTokens(c.User.ID) - if err != nil { - c.ServerError("ListAccessTokens", err) - return - } - - c.Data["Tokens"] = tokens - c.Success(SETTINGS_APPLICATIONS) - return - } - - t := &models.AccessToken{ - UID: c.User.ID, - Name: f.Name, - } - if err := models.NewAccessToken(t); err != nil { - c.ServerError("NewAccessToken", err) - return - } - - c.Flash.Success(c.Tr("settings.generate_token_succees")) - c.Flash.Info(t.Sha1) - c.SubURLRedirect("/user/settings/applications") -} - -func SettingsDeleteApplication(c *context.Context) { - if err := models.DeleteAccessTokenOfUserByID(c.User.ID, c.QueryInt64("id")); err != nil { - c.Flash.Error("DeleteAccessTokenByID: " + err.Error()) - } else { - c.Flash.Success(c.Tr("settings.delete_token_success")) - } - - c.JSONSuccess(map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/applications", - }) -} - -func SettingsDelete(c *context.Context) { - c.Title("settings.delete") - c.PageIs("SettingsDelete") - - if c.Req.Method == "POST" { - if _, err := models.UserSignIn(c.User.Name, c.Query("password")); err != nil { - if errors.IsUserNotExist(err) { - c.RenderWithErr(c.Tr("form.enterred_invalid_password"), SETTINGS_DELETE, nil) - } else { - c.ServerError("UserSignIn", err) - } - return - } - - if err := models.DeleteUser(c.User); err != nil { - switch { - case models.IsErrUserOwnRepos(err): - c.Flash.Error(c.Tr("form.still_own_repo")) - c.Redirect(setting.AppSubURL + "/user/settings/delete") - case models.IsErrUserHasOrgs(err): - c.Flash.Error(c.Tr("form.still_has_org")) - c.Redirect(setting.AppSubURL + "/user/settings/delete") - default: - c.ServerError("DeleteUser", err) - } - } else { - log.Trace("Account deleted: %s", c.User.Name) - c.Redirect(setting.AppSubURL + "/") - } - return - } - - c.Success(SETTINGS_DELETE) -} |