mirror of
https://github.com/gogs/gogs.git
synced 2026-07-10 23:02:09 +02:00
internal: move packages under this directory (#5836)
* Rename pkg -> internal * Rename routes -> route * Move route -> internal/route * Rename models -> db * Move db -> internal/db * Fix route2 -> route * Move cmd -> internal/cmd * Bump version
This commit is contained in:
107
internal/context/api.go
Normal file
107
internal/context/api.go
Normal file
@@ -0,0 +1,107 @@
|
||||
// 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 context
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/unknwon/paginater"
|
||||
log "gopkg.in/clog.v1"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"gogs.io/gogs/internal/setting"
|
||||
)
|
||||
|
||||
type APIContext struct {
|
||||
*Context // TODO: Reduce to only needed fields instead of full shadow
|
||||
|
||||
// Base URL for the version of API endpoints, e.g. https://try.gogs.io/api/v1
|
||||
BaseURL string
|
||||
|
||||
Org *APIOrganization
|
||||
}
|
||||
|
||||
// FIXME: move this constant to github.com/gogs/go-gogs-client
|
||||
const DocURL = "https://github.com/gogs/docs-api"
|
||||
|
||||
// Error responses error message to client with given message.
|
||||
// If status is 500, also it prints error to log.
|
||||
func (c *APIContext) Error(status int, title string, obj interface{}) {
|
||||
var message string
|
||||
if err, ok := obj.(error); ok {
|
||||
message = err.Error()
|
||||
} else {
|
||||
message = obj.(string)
|
||||
}
|
||||
|
||||
if status == http.StatusInternalServerError {
|
||||
log.Error(3, "%s: %s", title, message)
|
||||
}
|
||||
|
||||
c.JSON(status, map[string]string{
|
||||
"message": message,
|
||||
"url": DocURL,
|
||||
})
|
||||
}
|
||||
|
||||
// NoContent renders the 204 response.
|
||||
func (c *APIContext) NoContent() {
|
||||
c.Status(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// NotFound renders the 404 response.
|
||||
func (c *APIContext) NotFound() {
|
||||
c.Status(http.StatusNotFound)
|
||||
}
|
||||
|
||||
// ServerError renders the 500 response.
|
||||
func (c *APIContext) ServerError(title string, err error) {
|
||||
c.Error(http.StatusInternalServerError, title, err)
|
||||
}
|
||||
|
||||
// NotFoundOrServerError use error check function to determine if the error
|
||||
// is about not found. It responses with 404 status code for not found error,
|
||||
// or error context description for logging purpose of 500 server error.
|
||||
func (c *APIContext) NotFoundOrServerError(title string, errck func(error) bool, err error) {
|
||||
if errck(err) {
|
||||
c.NotFound()
|
||||
return
|
||||
}
|
||||
c.ServerError(title, err)
|
||||
}
|
||||
|
||||
// SetLinkHeader sets pagination link header by given total number and page size.
|
||||
func (c *APIContext) SetLinkHeader(total, pageSize int) {
|
||||
page := paginater.New(total, pageSize, c.QueryInt("page"), 0)
|
||||
links := make([]string, 0, 4)
|
||||
if page.HasNext() {
|
||||
links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"next\"", setting.AppURL, c.Req.URL.Path[1:], page.Next()))
|
||||
}
|
||||
if !page.IsLast() {
|
||||
links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"last\"", setting.AppURL, c.Req.URL.Path[1:], page.TotalPages()))
|
||||
}
|
||||
if !page.IsFirst() {
|
||||
links = append(links, fmt.Sprintf("<%s%s?page=1>; rel=\"first\"", setting.AppURL, c.Req.URL.Path[1:]))
|
||||
}
|
||||
if page.HasPrevious() {
|
||||
links = append(links, fmt.Sprintf("<%s%s?page=%d>; rel=\"prev\"", setting.AppURL, c.Req.URL.Path[1:], page.Previous()))
|
||||
}
|
||||
|
||||
if len(links) > 0 {
|
||||
c.Header().Set("Link", strings.Join(links, ","))
|
||||
}
|
||||
}
|
||||
|
||||
func APIContexter() macaron.Handler {
|
||||
return func(ctx *Context) {
|
||||
c := &APIContext{
|
||||
Context: ctx,
|
||||
BaseURL: setting.AppURL + "api/v1",
|
||||
}
|
||||
ctx.Map(c)
|
||||
}
|
||||
}
|
||||
14
internal/context/api_org.go
Normal file
14
internal/context/api_org.go
Normal file
@@ -0,0 +1,14 @@
|
||||
// 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 context
|
||||
|
||||
import (
|
||||
"gogs.io/gogs/internal/db"
|
||||
)
|
||||
|
||||
type APIOrganization struct {
|
||||
Organization *db.User
|
||||
Team *db.Team
|
||||
}
|
||||
112
internal/context/auth.go
Normal file
112
internal/context/auth.go
Normal file
@@ -0,0 +1,112 @@
|
||||
// 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 context
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/go-macaron/csrf"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"gogs.io/gogs/internal/auth"
|
||||
"gogs.io/gogs/internal/setting"
|
||||
"gogs.io/gogs/internal/tool"
|
||||
)
|
||||
|
||||
type ToggleOptions struct {
|
||||
SignInRequired bool
|
||||
SignOutRequired bool
|
||||
AdminRequired bool
|
||||
DisableCSRF bool
|
||||
}
|
||||
|
||||
func Toggle(options *ToggleOptions) macaron.Handler {
|
||||
return func(c *Context) {
|
||||
// Cannot view any page before installation.
|
||||
if !setting.InstallLock {
|
||||
c.Redirect(setting.AppSubURL + "/install")
|
||||
return
|
||||
}
|
||||
|
||||
// Check prohibit login users.
|
||||
if c.IsLogged && c.User.ProhibitLogin {
|
||||
c.Data["Title"] = c.Tr("auth.prohibit_login")
|
||||
c.HTML(200, "user/auth/prohibit_login")
|
||||
return
|
||||
}
|
||||
|
||||
// Check non-logged users landing page.
|
||||
if !c.IsLogged && c.Req.RequestURI == "/" && setting.LandingPageURL != setting.LANDING_PAGE_HOME {
|
||||
c.Redirect(setting.AppSubURL + string(setting.LandingPageURL))
|
||||
return
|
||||
}
|
||||
|
||||
// Redirect to dashboard if user tries to visit any non-login page.
|
||||
if options.SignOutRequired && c.IsLogged && c.Req.RequestURI != "/" {
|
||||
c.Redirect(setting.AppSubURL + "/")
|
||||
return
|
||||
}
|
||||
|
||||
if !options.SignOutRequired && !options.DisableCSRF && c.Req.Method == "POST" && !auth.IsAPIPath(c.Req.URL.Path) {
|
||||
csrf.Validate(c.Context, c.csrf)
|
||||
if c.Written() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if options.SignInRequired {
|
||||
if !c.IsLogged {
|
||||
// Restrict API calls with error message.
|
||||
if auth.IsAPIPath(c.Req.URL.Path) {
|
||||
c.JSON(403, map[string]string{
|
||||
"message": "Only signed in user is allowed to call APIs.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
c.SetCookie("redirect_to", url.QueryEscape(setting.AppSubURL+c.Req.RequestURI), 0, setting.AppSubURL)
|
||||
c.Redirect(setting.AppSubURL + "/user/login")
|
||||
return
|
||||
} else if !c.User.IsActive && setting.Service.RegisterEmailConfirm {
|
||||
c.Data["Title"] = c.Tr("auth.active_your_account")
|
||||
c.HTML(200, "user/auth/activate")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect to log in page if auto-signin info is provided and has not signed in.
|
||||
if !options.SignOutRequired && !c.IsLogged && !auth.IsAPIPath(c.Req.URL.Path) &&
|
||||
len(c.GetCookie(setting.CookieUserName)) > 0 {
|
||||
c.SetCookie("redirect_to", url.QueryEscape(setting.AppSubURL+c.Req.RequestURI), 0, setting.AppSubURL)
|
||||
c.Redirect(setting.AppSubURL + "/user/login")
|
||||
return
|
||||
}
|
||||
|
||||
if options.AdminRequired {
|
||||
if !c.User.IsAdmin {
|
||||
c.Error(403)
|
||||
return
|
||||
}
|
||||
c.Data["PageIsAdmin"] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RequireBasicAuth verifies HTTP Basic Authentication header with given credentials
|
||||
func (c *Context) RequireBasicAuth(username, password string) {
|
||||
fields := strings.Fields(c.Req.Header.Get("Authorization"))
|
||||
if len(fields) != 2 || fields[0] != "Basic" {
|
||||
c.Status(http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
uname, passwd, _ := tool.BasicAuthDecode(fields[1])
|
||||
if uname != username || passwd != password {
|
||||
c.Status(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
}
|
||||
334
internal/context/context.go
Normal file
334
internal/context/context.go
Normal file
@@ -0,0 +1,334 @@
|
||||
// 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 context
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-macaron/cache"
|
||||
"github.com/go-macaron/csrf"
|
||||
"github.com/go-macaron/i18n"
|
||||
"github.com/go-macaron/session"
|
||||
"github.com/unknwon/com"
|
||||
log "gopkg.in/clog.v1"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"gogs.io/gogs/internal/auth"
|
||||
"gogs.io/gogs/internal/db"
|
||||
"gogs.io/gogs/internal/db/errors"
|
||||
"gogs.io/gogs/internal/form"
|
||||
"gogs.io/gogs/internal/setting"
|
||||
"gogs.io/gogs/internal/template"
|
||||
)
|
||||
|
||||
// Context represents context of a request.
|
||||
type Context struct {
|
||||
*macaron.Context
|
||||
Cache cache.Cache
|
||||
csrf csrf.CSRF
|
||||
Flash *session.Flash
|
||||
Session session.Store
|
||||
|
||||
Link string // Current request URL
|
||||
User *db.User
|
||||
IsLogged bool
|
||||
IsBasicAuth bool
|
||||
IsTokenAuth bool
|
||||
|
||||
Repo *Repository
|
||||
Org *Organization
|
||||
}
|
||||
|
||||
// Title sets "Title" field in template data.
|
||||
func (c *Context) Title(locale string) {
|
||||
c.Data["Title"] = c.Tr(locale)
|
||||
}
|
||||
|
||||
// PageIs sets "PageIsxxx" field in template data.
|
||||
func (c *Context) PageIs(name string) {
|
||||
c.Data["PageIs"+name] = true
|
||||
}
|
||||
|
||||
// Require sets "Requirexxx" field in template data.
|
||||
func (c *Context) Require(name string) {
|
||||
c.Data["Require"+name] = true
|
||||
}
|
||||
|
||||
func (c *Context) RequireHighlightJS() {
|
||||
c.Require("HighlightJS")
|
||||
}
|
||||
|
||||
func (c *Context) RequireSimpleMDE() {
|
||||
c.Require("SimpleMDE")
|
||||
}
|
||||
|
||||
func (c *Context) RequireAutosize() {
|
||||
c.Require("Autosize")
|
||||
}
|
||||
|
||||
func (c *Context) RequireDropzone() {
|
||||
c.Require("Dropzone")
|
||||
}
|
||||
|
||||
// FormErr sets "Err_xxx" field in template data.
|
||||
func (c *Context) FormErr(names ...string) {
|
||||
for i := range names {
|
||||
c.Data["Err_"+names[i]] = true
|
||||
}
|
||||
}
|
||||
|
||||
// UserID returns ID of current logged in user.
|
||||
// It returns 0 if visitor is anonymous.
|
||||
func (c *Context) UserID() int64 {
|
||||
if !c.IsLogged {
|
||||
return 0
|
||||
}
|
||||
return c.User.ID
|
||||
}
|
||||
|
||||
// HasError returns true if error occurs in form validation.
|
||||
func (c *Context) HasApiError() bool {
|
||||
hasErr, ok := c.Data["HasError"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return hasErr.(bool)
|
||||
}
|
||||
|
||||
func (c *Context) GetErrMsg() string {
|
||||
return c.Data["ErrorMsg"].(string)
|
||||
}
|
||||
|
||||
// HasError returns true if error occurs in form validation.
|
||||
func (c *Context) HasError() bool {
|
||||
hasErr, ok := c.Data["HasError"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
c.Flash.ErrorMsg = c.Data["ErrorMsg"].(string)
|
||||
c.Data["Flash"] = c.Flash
|
||||
return hasErr.(bool)
|
||||
}
|
||||
|
||||
// HasValue returns true if value of given name exists.
|
||||
func (c *Context) HasValue(name string) bool {
|
||||
_, ok := c.Data[name]
|
||||
return ok
|
||||
}
|
||||
|
||||
// HTML responses template with given status.
|
||||
func (c *Context) HTML(status int, name string) {
|
||||
log.Trace("Template: %s", name)
|
||||
c.Context.HTML(status, name)
|
||||
}
|
||||
|
||||
// Success responses template with status http.StatusOK.
|
||||
func (c *Context) Success(name string) {
|
||||
c.HTML(http.StatusOK, name)
|
||||
}
|
||||
|
||||
// JSONSuccess responses JSON with status http.StatusOK.
|
||||
func (c *Context) JSONSuccess(data interface{}) {
|
||||
c.JSON(http.StatusOK, data)
|
||||
}
|
||||
|
||||
// RawRedirect simply calls underlying Redirect method with no escape.
|
||||
func (c *Context) RawRedirect(location string, status ...int) {
|
||||
c.Context.Redirect(location, status...)
|
||||
}
|
||||
|
||||
// Redirect responses redirection wtih given location and status.
|
||||
// It escapes special characters in the location string.
|
||||
func (c *Context) Redirect(location string, status ...int) {
|
||||
c.Context.Redirect(template.EscapePound(location), status...)
|
||||
}
|
||||
|
||||
// SubURLRedirect responses redirection wtih given location and status.
|
||||
// It prepends setting.AppSubURL to the location string.
|
||||
func (c *Context) SubURLRedirect(location string, status ...int) {
|
||||
c.Redirect(setting.AppSubURL+location, status...)
|
||||
}
|
||||
|
||||
// RenderWithErr used for page has form validation but need to prompt error to users.
|
||||
func (c *Context) RenderWithErr(msg, tpl string, f interface{}) {
|
||||
if f != nil {
|
||||
form.Assign(f, c.Data)
|
||||
}
|
||||
c.Flash.ErrorMsg = msg
|
||||
c.Data["Flash"] = c.Flash
|
||||
c.HTML(http.StatusOK, tpl)
|
||||
}
|
||||
|
||||
// Handle handles and logs error by given status.
|
||||
func (c *Context) Handle(status int, title string, err error) {
|
||||
switch status {
|
||||
case http.StatusNotFound:
|
||||
c.Data["Title"] = "Page Not Found"
|
||||
case http.StatusInternalServerError:
|
||||
c.Data["Title"] = "Internal Server Error"
|
||||
log.Error(3, "%s: %v", title, err)
|
||||
if !setting.ProdMode || (c.IsLogged && c.User.IsAdmin) {
|
||||
c.Data["ErrorMsg"] = err
|
||||
}
|
||||
}
|
||||
c.HTML(status, fmt.Sprintf("status/%d", status))
|
||||
}
|
||||
|
||||
// NotFound renders the 404 page.
|
||||
func (c *Context) NotFound() {
|
||||
c.Handle(http.StatusNotFound, "", nil)
|
||||
}
|
||||
|
||||
// ServerError renders the 500 page.
|
||||
func (c *Context) ServerError(title string, err error) {
|
||||
c.Handle(http.StatusInternalServerError, title, err)
|
||||
}
|
||||
|
||||
// NotFoundOrServerError use error check function to determine if the error
|
||||
// is about not found. It responses with 404 status code for not found error,
|
||||
// or error context description for logging purpose of 500 server error.
|
||||
func (c *Context) NotFoundOrServerError(title string, errck func(error) bool, err error) {
|
||||
if errck(err) {
|
||||
c.NotFound()
|
||||
return
|
||||
}
|
||||
c.ServerError(title, err)
|
||||
}
|
||||
|
||||
func (c *Context) HandleText(status int, title string) {
|
||||
c.PlainText(status, []byte(title))
|
||||
}
|
||||
|
||||
func (c *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
|
||||
modtime := time.Now()
|
||||
for _, p := range params {
|
||||
switch v := p.(type) {
|
||||
case time.Time:
|
||||
modtime = v
|
||||
}
|
||||
}
|
||||
c.Resp.Header().Set("Content-Description", "File Transfer")
|
||||
c.Resp.Header().Set("Content-Type", "application/octet-stream")
|
||||
c.Resp.Header().Set("Content-Disposition", "attachment; filename="+name)
|
||||
c.Resp.Header().Set("Content-Transfer-Encoding", "binary")
|
||||
c.Resp.Header().Set("Expires", "0")
|
||||
c.Resp.Header().Set("Cache-Control", "must-revalidate")
|
||||
c.Resp.Header().Set("Pragma", "public")
|
||||
http.ServeContent(c.Resp, c.Req.Request, name, modtime, r)
|
||||
}
|
||||
|
||||
// Contexter initializes a classic context for a request.
|
||||
func Contexter() macaron.Handler {
|
||||
return func(ctx *macaron.Context, l i18n.Locale, cache cache.Cache, sess session.Store, f *session.Flash, x csrf.CSRF) {
|
||||
c := &Context{
|
||||
Context: ctx,
|
||||
Cache: cache,
|
||||
csrf: x,
|
||||
Flash: f,
|
||||
Session: sess,
|
||||
Link: setting.AppSubURL + strings.TrimSuffix(ctx.Req.URL.Path, "/"),
|
||||
Repo: &Repository{
|
||||
PullRequest: &PullRequest{},
|
||||
},
|
||||
Org: &Organization{},
|
||||
}
|
||||
c.Data["Link"] = template.EscapePound(c.Link)
|
||||
c.Data["PageStartTime"] = time.Now()
|
||||
|
||||
// Quick responses appropriate go-get meta with status 200
|
||||
// regardless of if user have access to the repository,
|
||||
// or the repository does not exist at all.
|
||||
// This is particular a workaround for "go get" command which does not respect
|
||||
// .netrc file.
|
||||
if c.Query("go-get") == "1" {
|
||||
ownerName := c.Params(":username")
|
||||
repoName := c.Params(":reponame")
|
||||
branchName := "master"
|
||||
|
||||
owner, err := db.GetUserByName(ownerName)
|
||||
if err != nil {
|
||||
c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
|
||||
return
|
||||
}
|
||||
|
||||
repo, err := db.GetRepositoryByName(owner.ID, repoName)
|
||||
if err == nil && len(repo.DefaultBranch) > 0 {
|
||||
branchName = repo.DefaultBranch
|
||||
}
|
||||
|
||||
prefix := setting.AppURL + path.Join(ownerName, repoName, "src", branchName)
|
||||
insecureFlag := ""
|
||||
if !strings.HasPrefix(setting.AppURL, "https://") {
|
||||
insecureFlag = "--insecure "
|
||||
}
|
||||
c.PlainText(http.StatusOK, []byte(com.Expand(`<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="go-import" content="{GoGetImport} git {CloneLink}">
|
||||
<meta name="go-source" content="{GoGetImport} _ {GoDocDirectory} {GoDocFile}">
|
||||
</head>
|
||||
<body>
|
||||
go get {InsecureFlag}{GoGetImport}
|
||||
</body>
|
||||
</html>
|
||||
`, map[string]string{
|
||||
"GoGetImport": path.Join(setting.HostAddress, setting.AppSubURL, repo.FullName()),
|
||||
"CloneLink": db.ComposeHTTPSCloneURL(ownerName, repoName),
|
||||
"GoDocDirectory": prefix + "{/dir}",
|
||||
"GoDocFile": prefix + "{/dir}/{file}#L{line}",
|
||||
"InsecureFlag": insecureFlag,
|
||||
})))
|
||||
return
|
||||
}
|
||||
|
||||
if len(setting.HTTP.AccessControlAllowOrigin) > 0 {
|
||||
c.Header().Set("Access-Control-Allow-Origin", setting.HTTP.AccessControlAllowOrigin)
|
||||
c.Header().Set("'Access-Control-Allow-Credentials' ", "true")
|
||||
c.Header().Set("Access-Control-Max-Age", "3600")
|
||||
c.Header().Set("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With")
|
||||
}
|
||||
|
||||
// Get user from session or header when possible
|
||||
c.User, c.IsBasicAuth, c.IsTokenAuth = auth.SignedInUser(c.Context, c.Session)
|
||||
|
||||
if c.User != nil {
|
||||
c.IsLogged = true
|
||||
c.Data["IsLogged"] = c.IsLogged
|
||||
c.Data["LoggedUser"] = c.User
|
||||
c.Data["LoggedUserID"] = c.User.ID
|
||||
c.Data["LoggedUserName"] = c.User.Name
|
||||
c.Data["IsAdmin"] = c.User.IsAdmin
|
||||
} else {
|
||||
c.Data["LoggedUserID"] = 0
|
||||
c.Data["LoggedUserName"] = ""
|
||||
}
|
||||
|
||||
// If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
|
||||
if c.Req.Method == "POST" && strings.Contains(c.Req.Header.Get("Content-Type"), "multipart/form-data") {
|
||||
if err := c.Req.ParseMultipartForm(setting.AttachmentMaxSize << 20); err != nil && !strings.Contains(err.Error(), "EOF") { // 32MB max size
|
||||
c.ServerError("ParseMultipartForm", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.Data["CSRFToken"] = x.GetToken()
|
||||
c.Data["CSRFTokenHTML"] = template.Safe(`<input type="hidden" name="_csrf" value="` + x.GetToken() + `">`)
|
||||
log.Trace("Session ID: %s", sess.ID())
|
||||
log.Trace("CSRF Token: %v", c.Data["CSRFToken"])
|
||||
|
||||
c.Data["ShowRegistrationButton"] = setting.Service.ShowRegistrationButton
|
||||
c.Data["ShowFooterBranding"] = setting.ShowFooterBranding
|
||||
c.Data["ShowFooterVersion"] = setting.ShowFooterVersion
|
||||
|
||||
c.renderNoticeBanner()
|
||||
|
||||
ctx.Map(c)
|
||||
}
|
||||
}
|
||||
62
internal/context/notice.go
Normal file
62
internal/context/notice.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2019 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 context
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/unknwon/com"
|
||||
log "gopkg.in/clog.v1"
|
||||
|
||||
"gogs.io/gogs/internal/markup"
|
||||
"gogs.io/gogs/internal/setting"
|
||||
"gogs.io/gogs/internal/tool"
|
||||
)
|
||||
|
||||
// renderNoticeBanner checks if a notice banner file exists and loads the message to display
|
||||
// on all pages.
|
||||
func (c *Context) renderNoticeBanner() {
|
||||
fpath := path.Join(setting.CustomPath, "notice", "banner.md")
|
||||
if !com.IsExist(fpath) {
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Open(fpath)
|
||||
if err != nil {
|
||||
log.Error(2, "Failed to open file %q: %v", fpath, err)
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
log.Error(2, "Failed to stat file %q: %v", fpath, err)
|
||||
return
|
||||
}
|
||||
|
||||
// Limit size to prevent very large messages from breaking pages
|
||||
var maxSize int64 = 1024
|
||||
|
||||
if fi.Size() > maxSize { // Refuse to print very long messages
|
||||
log.Warn("Notice banner file %q size too large [%d > %d]: refusing to render", fpath, fi.Size(), maxSize)
|
||||
return
|
||||
}
|
||||
|
||||
buf := make([]byte, maxSize)
|
||||
n, err := f.Read(buf)
|
||||
if err != nil {
|
||||
log.Error(2, "Failed to read file %q: %v", fpath, err)
|
||||
return
|
||||
}
|
||||
buf = buf[:n]
|
||||
|
||||
if !tool.IsTextFile(buf) {
|
||||
log.Warn("Notice banner file %q does not appear to be a text file: aborting", fpath)
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["ServerNotice"] = string(markup.RawMarkdown(buf, ""))
|
||||
}
|
||||
150
internal/context/org.go
Normal file
150
internal/context/org.go
Normal file
@@ -0,0 +1,150 @@
|
||||
// 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 context
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"gogs.io/gogs/internal/db"
|
||||
"gogs.io/gogs/internal/db/errors"
|
||||
"gogs.io/gogs/internal/setting"
|
||||
)
|
||||
|
||||
type Organization struct {
|
||||
IsOwner bool
|
||||
IsMember bool
|
||||
IsTeamMember bool // Is member of team.
|
||||
IsTeamAdmin bool // In owner team or team that has admin permission level.
|
||||
Organization *db.User
|
||||
OrgLink string
|
||||
|
||||
Team *db.Team
|
||||
}
|
||||
|
||||
func HandleOrgAssignment(c *Context, args ...bool) {
|
||||
var (
|
||||
requireMember bool
|
||||
requireOwner bool
|
||||
requireTeamMember bool
|
||||
requireTeamAdmin bool
|
||||
)
|
||||
if len(args) >= 1 {
|
||||
requireMember = args[0]
|
||||
}
|
||||
if len(args) >= 2 {
|
||||
requireOwner = args[1]
|
||||
}
|
||||
if len(args) >= 3 {
|
||||
requireTeamMember = args[2]
|
||||
}
|
||||
if len(args) >= 4 {
|
||||
requireTeamAdmin = args[3]
|
||||
}
|
||||
|
||||
orgName := c.Params(":org")
|
||||
|
||||
var err error
|
||||
c.Org.Organization, err = db.GetUserByName(orgName)
|
||||
if err != nil {
|
||||
c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
|
||||
return
|
||||
}
|
||||
org := c.Org.Organization
|
||||
c.Data["Org"] = org
|
||||
|
||||
// Force redirection when username is actually a user.
|
||||
if !org.IsOrganization() {
|
||||
c.Redirect("/" + org.Name)
|
||||
return
|
||||
}
|
||||
|
||||
// Admin has super access.
|
||||
if c.IsLogged && c.User.IsAdmin {
|
||||
c.Org.IsOwner = true
|
||||
c.Org.IsMember = true
|
||||
c.Org.IsTeamMember = true
|
||||
c.Org.IsTeamAdmin = true
|
||||
} else if c.IsLogged {
|
||||
c.Org.IsOwner = org.IsOwnedBy(c.User.ID)
|
||||
if c.Org.IsOwner {
|
||||
c.Org.IsMember = true
|
||||
c.Org.IsTeamMember = true
|
||||
c.Org.IsTeamAdmin = true
|
||||
} else {
|
||||
if org.IsOrgMember(c.User.ID) {
|
||||
c.Org.IsMember = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fake data.
|
||||
c.Data["SignedUser"] = &db.User{}
|
||||
}
|
||||
if (requireMember && !c.Org.IsMember) ||
|
||||
(requireOwner && !c.Org.IsOwner) {
|
||||
c.Handle(404, "OrgAssignment", err)
|
||||
return
|
||||
}
|
||||
c.Data["IsOrganizationOwner"] = c.Org.IsOwner
|
||||
c.Data["IsOrganizationMember"] = c.Org.IsMember
|
||||
|
||||
c.Org.OrgLink = setting.AppSubURL + "/org/" + org.Name
|
||||
c.Data["OrgLink"] = c.Org.OrgLink
|
||||
|
||||
// Team.
|
||||
if c.Org.IsMember {
|
||||
if c.Org.IsOwner {
|
||||
if err := org.GetTeams(); err != nil {
|
||||
c.Handle(500, "GetTeams", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
org.Teams, err = org.GetUserTeams(c.User.ID)
|
||||
if err != nil {
|
||||
c.Handle(500, "GetUserTeams", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
teamName := c.Params(":team")
|
||||
if len(teamName) > 0 {
|
||||
teamExists := false
|
||||
for _, team := range org.Teams {
|
||||
if team.LowerName == strings.ToLower(teamName) {
|
||||
teamExists = true
|
||||
c.Org.Team = team
|
||||
c.Org.IsTeamMember = true
|
||||
c.Data["Team"] = c.Org.Team
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !teamExists {
|
||||
c.Handle(404, "OrgAssignment", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["IsTeamMember"] = c.Org.IsTeamMember
|
||||
if requireTeamMember && !c.Org.IsTeamMember {
|
||||
c.Handle(404, "OrgAssignment", err)
|
||||
return
|
||||
}
|
||||
|
||||
c.Org.IsTeamAdmin = c.Org.Team.IsOwnerTeam() || c.Org.Team.Authorize >= db.ACCESS_MODE_ADMIN
|
||||
c.Data["IsTeamAdmin"] = c.Org.IsTeamAdmin
|
||||
if requireTeamAdmin && !c.Org.IsTeamAdmin {
|
||||
c.Handle(404, "OrgAssignment", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func OrgAssignment(args ...bool) macaron.Handler {
|
||||
return func(c *Context) {
|
||||
HandleOrgAssignment(c, args...)
|
||||
}
|
||||
}
|
||||
437
internal/context/repo.go
Normal file
437
internal/context/repo.go
Normal file
@@ -0,0 +1,437 @@
|
||||
// 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 context
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/editorconfig/editorconfig-core-go.v1"
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"github.com/gogs/git-module"
|
||||
|
||||
"gogs.io/gogs/internal/db"
|
||||
"gogs.io/gogs/internal/db/errors"
|
||||
"gogs.io/gogs/internal/setting"
|
||||
)
|
||||
|
||||
type PullRequest struct {
|
||||
BaseRepo *db.Repository
|
||||
Allowed bool
|
||||
SameRepo bool
|
||||
HeadInfo string // [<user>:]<branch>
|
||||
}
|
||||
|
||||
type Repository struct {
|
||||
AccessMode db.AccessMode
|
||||
IsWatching bool
|
||||
IsViewBranch bool
|
||||
IsViewTag bool
|
||||
IsViewCommit bool
|
||||
Repository *db.Repository
|
||||
Owner *db.User
|
||||
Commit *git.Commit
|
||||
Tag *git.Tag
|
||||
GitRepo *git.Repository
|
||||
BranchName string
|
||||
TagName string
|
||||
TreePath string
|
||||
CommitID string
|
||||
RepoLink string
|
||||
CloneLink db.CloneLink
|
||||
CommitsCount int64
|
||||
Mirror *db.Mirror
|
||||
|
||||
PullRequest *PullRequest
|
||||
}
|
||||
|
||||
// IsOwner returns true if current user is the owner of repository.
|
||||
func (r *Repository) IsOwner() bool {
|
||||
return r.AccessMode >= db.ACCESS_MODE_OWNER
|
||||
}
|
||||
|
||||
// IsAdmin returns true if current user has admin or higher access of repository.
|
||||
func (r *Repository) IsAdmin() bool {
|
||||
return r.AccessMode >= db.ACCESS_MODE_ADMIN
|
||||
}
|
||||
|
||||
// IsWriter returns true if current user has write or higher access of repository.
|
||||
func (r *Repository) IsWriter() bool {
|
||||
return r.AccessMode >= db.ACCESS_MODE_WRITE
|
||||
}
|
||||
|
||||
// HasAccess returns true if the current user has at least read access for this repository
|
||||
func (r *Repository) HasAccess() bool {
|
||||
return r.AccessMode >= db.ACCESS_MODE_READ
|
||||
}
|
||||
|
||||
// CanEnableEditor returns true if repository is editable and user has proper access level.
|
||||
func (r *Repository) CanEnableEditor() bool {
|
||||
return r.Repository.CanEnableEditor() && r.IsViewBranch && r.IsWriter() && !r.Repository.IsBranchRequirePullRequest(r.BranchName)
|
||||
}
|
||||
|
||||
// GetEditorconfig returns the .editorconfig definition if found in the
|
||||
// HEAD of the default repo branch.
|
||||
func (r *Repository) GetEditorconfig() (*editorconfig.Editorconfig, error) {
|
||||
commit, err := r.GitRepo.GetBranchCommit(r.Repository.DefaultBranch)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
treeEntry, err := commit.GetTreeEntryByPath(".editorconfig")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reader, err := treeEntry.Blob().Data()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return editorconfig.ParseBytes(data)
|
||||
}
|
||||
|
||||
// PullRequestURL returns URL for composing a pull request.
|
||||
// This function does not check if the repository can actually compose a pull request.
|
||||
func (r *Repository) PullRequestURL(baseBranch, headBranch string) string {
|
||||
repoLink := r.RepoLink
|
||||
if r.PullRequest.BaseRepo != nil {
|
||||
repoLink = r.PullRequest.BaseRepo.Link()
|
||||
}
|
||||
return fmt.Sprintf("%s/compare/%s...%s:%s", repoLink, baseBranch, r.Owner.Name, headBranch)
|
||||
}
|
||||
|
||||
// [0]: issues, [1]: wiki
|
||||
func RepoAssignment(pages ...bool) macaron.Handler {
|
||||
return func(c *Context) {
|
||||
var (
|
||||
owner *db.User
|
||||
err error
|
||||
isIssuesPage bool
|
||||
isWikiPage bool
|
||||
)
|
||||
|
||||
if len(pages) > 0 {
|
||||
isIssuesPage = pages[0]
|
||||
}
|
||||
if len(pages) > 1 {
|
||||
isWikiPage = pages[1]
|
||||
}
|
||||
|
||||
ownerName := c.Params(":username")
|
||||
repoName := strings.TrimSuffix(c.Params(":reponame"), ".git")
|
||||
refName := c.Params(":branchname")
|
||||
if len(refName) == 0 {
|
||||
refName = c.Params(":path")
|
||||
}
|
||||
|
||||
// Check if the user is the same as the repository owner
|
||||
if c.IsLogged && c.User.LowerName == strings.ToLower(ownerName) {
|
||||
owner = c.User
|
||||
} else {
|
||||
owner, err = db.GetUserByName(ownerName)
|
||||
if err != nil {
|
||||
c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
c.Repo.Owner = owner
|
||||
c.Data["Username"] = c.Repo.Owner.Name
|
||||
|
||||
repo, err := db.GetRepositoryByName(owner.ID, repoName)
|
||||
if err != nil {
|
||||
c.NotFoundOrServerError("GetRepositoryByName", errors.IsRepoNotExist, err)
|
||||
return
|
||||
}
|
||||
|
||||
c.Repo.Repository = repo
|
||||
c.Data["RepoName"] = c.Repo.Repository.Name
|
||||
c.Data["IsBareRepo"] = c.Repo.Repository.IsBare
|
||||
c.Repo.RepoLink = repo.Link()
|
||||
c.Data["RepoLink"] = c.Repo.RepoLink
|
||||
c.Data["RepoRelPath"] = c.Repo.Owner.Name + "/" + c.Repo.Repository.Name
|
||||
|
||||
// Admin has super access.
|
||||
if c.IsLogged && c.User.IsAdmin {
|
||||
c.Repo.AccessMode = db.ACCESS_MODE_OWNER
|
||||
} else {
|
||||
mode, err := db.UserAccessMode(c.UserID(), repo)
|
||||
if err != nil {
|
||||
c.ServerError("UserAccessMode", err)
|
||||
return
|
||||
}
|
||||
c.Repo.AccessMode = mode
|
||||
}
|
||||
|
||||
// Check access
|
||||
if c.Repo.AccessMode == db.ACCESS_MODE_NONE {
|
||||
// Redirect to any accessible page if not yet on it
|
||||
if repo.IsPartialPublic() &&
|
||||
(!(isIssuesPage || isWikiPage) ||
|
||||
(isIssuesPage && !repo.CanGuestViewIssues()) ||
|
||||
(isWikiPage && !repo.CanGuestViewWiki())) {
|
||||
switch {
|
||||
case repo.CanGuestViewIssues():
|
||||
c.Redirect(repo.Link() + "/issues")
|
||||
case repo.CanGuestViewWiki():
|
||||
c.Redirect(repo.Link() + "/wiki")
|
||||
default:
|
||||
c.NotFound()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Response 404 if user is on completely private repository or possible accessible page but owner doesn't enabled
|
||||
if !repo.IsPartialPublic() ||
|
||||
(isIssuesPage && !repo.CanGuestViewIssues()) ||
|
||||
(isWikiPage && !repo.CanGuestViewWiki()) {
|
||||
c.NotFound()
|
||||
return
|
||||
}
|
||||
|
||||
c.Repo.Repository.EnableIssues = repo.CanGuestViewIssues()
|
||||
c.Repo.Repository.EnableWiki = repo.CanGuestViewWiki()
|
||||
}
|
||||
|
||||
if repo.IsMirror {
|
||||
c.Repo.Mirror, err = db.GetMirrorByRepoID(repo.ID)
|
||||
if err != nil {
|
||||
c.ServerError("GetMirror", err)
|
||||
return
|
||||
}
|
||||
c.Data["MirrorEnablePrune"] = c.Repo.Mirror.EnablePrune
|
||||
c.Data["MirrorInterval"] = c.Repo.Mirror.Interval
|
||||
c.Data["Mirror"] = c.Repo.Mirror
|
||||
}
|
||||
|
||||
gitRepo, err := git.OpenRepository(db.RepoPath(ownerName, repoName))
|
||||
if err != nil {
|
||||
c.ServerError(fmt.Sprintf("RepoAssignment Invalid repo '%s'", c.Repo.Repository.RepoPath()), err)
|
||||
return
|
||||
}
|
||||
c.Repo.GitRepo = gitRepo
|
||||
|
||||
tags, err := c.Repo.GitRepo.GetTags()
|
||||
if err != nil {
|
||||
c.ServerError(fmt.Sprintf("GetTags '%s'", c.Repo.Repository.RepoPath()), err)
|
||||
return
|
||||
}
|
||||
c.Data["Tags"] = tags
|
||||
c.Repo.Repository.NumTags = len(tags)
|
||||
|
||||
c.Data["Title"] = owner.Name + "/" + repo.Name
|
||||
c.Data["Repository"] = repo
|
||||
c.Data["Owner"] = c.Repo.Repository.Owner
|
||||
c.Data["IsRepositoryOwner"] = c.Repo.IsOwner()
|
||||
c.Data["IsRepositoryAdmin"] = c.Repo.IsAdmin()
|
||||
c.Data["IsRepositoryWriter"] = c.Repo.IsWriter()
|
||||
|
||||
c.Data["DisableSSH"] = setting.SSH.Disabled
|
||||
c.Data["DisableHTTP"] = setting.Repository.DisableHTTPGit
|
||||
c.Data["CloneLink"] = repo.CloneLink()
|
||||
c.Data["WikiCloneLink"] = repo.WikiCloneLink()
|
||||
|
||||
if c.IsLogged {
|
||||
c.Data["IsWatchingRepo"] = db.IsWatching(c.User.ID, repo.ID)
|
||||
c.Data["IsStaringRepo"] = db.IsStaring(c.User.ID, repo.ID)
|
||||
}
|
||||
|
||||
// repo is bare and display enable
|
||||
if c.Repo.Repository.IsBare {
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["TagName"] = c.Repo.TagName
|
||||
brs, err := c.Repo.GitRepo.GetBranches()
|
||||
if err != nil {
|
||||
c.ServerError("GetBranches", err)
|
||||
return
|
||||
}
|
||||
c.Data["Branches"] = brs
|
||||
c.Data["BrancheCount"] = len(brs)
|
||||
|
||||
// If not branch selected, try default one.
|
||||
// If default branch doesn't exists, fall back to some other branch.
|
||||
if len(c.Repo.BranchName) == 0 {
|
||||
if len(c.Repo.Repository.DefaultBranch) > 0 && gitRepo.IsBranchExist(c.Repo.Repository.DefaultBranch) {
|
||||
c.Repo.BranchName = c.Repo.Repository.DefaultBranch
|
||||
} else if len(brs) > 0 {
|
||||
c.Repo.BranchName = brs[0]
|
||||
}
|
||||
}
|
||||
c.Data["BranchName"] = c.Repo.BranchName
|
||||
c.Data["CommitID"] = c.Repo.CommitID
|
||||
|
||||
c.Data["IsGuest"] = !c.Repo.HasAccess()
|
||||
}
|
||||
}
|
||||
|
||||
// RepoRef handles repository reference name including those contain `/`.
|
||||
func RepoRef() macaron.Handler {
|
||||
return func(c *Context) {
|
||||
// Empty repository does not have reference information.
|
||||
if c.Repo.Repository.IsBare {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
refName string
|
||||
err error
|
||||
)
|
||||
|
||||
// For API calls.
|
||||
if c.Repo.GitRepo == nil {
|
||||
repoPath := db.RepoPath(c.Repo.Owner.Name, c.Repo.Repository.Name)
|
||||
c.Repo.GitRepo, err = git.OpenRepository(repoPath)
|
||||
if err != nil {
|
||||
c.Handle(500, "RepoRef Invalid repo "+repoPath, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Get default branch.
|
||||
if len(c.Params("*")) == 0 {
|
||||
refName = c.Repo.Repository.DefaultBranch
|
||||
if !c.Repo.GitRepo.IsBranchExist(refName) {
|
||||
brs, err := c.Repo.GitRepo.GetBranches()
|
||||
if err != nil {
|
||||
c.Handle(500, "GetBranches", err)
|
||||
return
|
||||
}
|
||||
refName = brs[0]
|
||||
}
|
||||
c.Repo.Commit, err = c.Repo.GitRepo.GetBranchCommit(refName)
|
||||
if err != nil {
|
||||
c.Handle(500, "GetBranchCommit", err)
|
||||
return
|
||||
}
|
||||
c.Repo.CommitID = c.Repo.Commit.ID.String()
|
||||
c.Repo.IsViewBranch = true
|
||||
|
||||
} else {
|
||||
hasMatched := false
|
||||
parts := strings.Split(c.Params("*"), "/")
|
||||
for i, part := range parts {
|
||||
refName = strings.TrimPrefix(refName+"/"+part, "/")
|
||||
|
||||
if c.Repo.GitRepo.IsBranchExist(refName) ||
|
||||
c.Repo.GitRepo.IsTagExist(refName) {
|
||||
if i < len(parts)-1 {
|
||||
c.Repo.TreePath = strings.Join(parts[i+1:], "/")
|
||||
}
|
||||
hasMatched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasMatched && len(parts[0]) == 40 {
|
||||
refName = parts[0]
|
||||
c.Repo.TreePath = strings.Join(parts[1:], "/")
|
||||
}
|
||||
|
||||
if c.Repo.GitRepo.IsBranchExist(refName) {
|
||||
c.Repo.IsViewBranch = true
|
||||
|
||||
c.Repo.Commit, err = c.Repo.GitRepo.GetBranchCommit(refName)
|
||||
if err != nil {
|
||||
c.Handle(500, "GetBranchCommit", err)
|
||||
return
|
||||
}
|
||||
c.Repo.CommitID = c.Repo.Commit.ID.String()
|
||||
|
||||
} else if c.Repo.GitRepo.IsTagExist(refName) {
|
||||
c.Repo.IsViewTag = true
|
||||
c.Repo.Commit, err = c.Repo.GitRepo.GetTagCommit(refName)
|
||||
if err != nil {
|
||||
c.Handle(500, "GetTagCommit", err)
|
||||
return
|
||||
}
|
||||
c.Repo.CommitID = c.Repo.Commit.ID.String()
|
||||
} else if len(refName) == 40 {
|
||||
c.Repo.IsViewCommit = true
|
||||
c.Repo.CommitID = refName
|
||||
|
||||
c.Repo.Commit, err = c.Repo.GitRepo.GetCommit(refName)
|
||||
if err != nil {
|
||||
c.NotFound()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
c.Handle(404, "RepoRef invalid repo", fmt.Errorf("branch or tag not exist: %s", refName))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.Repo.BranchName = refName
|
||||
c.Data["BranchName"] = c.Repo.BranchName
|
||||
c.Data["CommitID"] = c.Repo.CommitID
|
||||
c.Data["TreePath"] = c.Repo.TreePath
|
||||
c.Data["IsViewBranch"] = c.Repo.IsViewBranch
|
||||
c.Data["IsViewTag"] = c.Repo.IsViewTag
|
||||
c.Data["IsViewCommit"] = c.Repo.IsViewCommit
|
||||
|
||||
// People who have push access or have fored repository can propose a new pull request.
|
||||
if c.Repo.IsWriter() || (c.IsLogged && c.User.HasForkedRepo(c.Repo.Repository.ID)) {
|
||||
// Pull request is allowed if this is a fork repository
|
||||
// and base repository accepts pull requests.
|
||||
if c.Repo.Repository.BaseRepo != nil {
|
||||
if c.Repo.Repository.BaseRepo.AllowsPulls() {
|
||||
c.Repo.PullRequest.Allowed = true
|
||||
// In-repository pull requests has higher priority than cross-repository if user is viewing
|
||||
// base repository and 1) has write access to it 2) has forked it.
|
||||
if c.Repo.IsWriter() {
|
||||
c.Data["BaseRepo"] = c.Repo.Repository.BaseRepo
|
||||
c.Repo.PullRequest.BaseRepo = c.Repo.Repository.BaseRepo
|
||||
c.Repo.PullRequest.HeadInfo = c.Repo.Owner.Name + ":" + c.Repo.BranchName
|
||||
} else {
|
||||
c.Data["BaseRepo"] = c.Repo.Repository
|
||||
c.Repo.PullRequest.BaseRepo = c.Repo.Repository
|
||||
c.Repo.PullRequest.HeadInfo = c.User.Name + ":" + c.Repo.BranchName
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Or, this is repository accepts pull requests between branches.
|
||||
if c.Repo.Repository.AllowsPulls() {
|
||||
c.Data["BaseRepo"] = c.Repo.Repository
|
||||
c.Repo.PullRequest.BaseRepo = c.Repo.Repository
|
||||
c.Repo.PullRequest.Allowed = true
|
||||
c.Repo.PullRequest.SameRepo = true
|
||||
c.Repo.PullRequest.HeadInfo = c.Repo.BranchName
|
||||
}
|
||||
}
|
||||
}
|
||||
c.Data["PullRequestCtx"] = c.Repo.PullRequest
|
||||
}
|
||||
}
|
||||
|
||||
func RequireRepoAdmin() macaron.Handler {
|
||||
return func(c *Context) {
|
||||
if !c.IsLogged || (!c.Repo.IsAdmin() && !c.User.IsAdmin) {
|
||||
c.NotFound()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RequireRepoWriter() macaron.Handler {
|
||||
return func(c *Context) {
|
||||
if !c.IsLogged || (!c.Repo.IsWriter() && !c.User.IsAdmin) {
|
||||
c.NotFound()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GitHookService checks if repository Git hooks service has been enabled.
|
||||
func GitHookService() macaron.Handler {
|
||||
return func(c *Context) {
|
||||
if !c.User.CanEditGitHook() {
|
||||
c.NotFound()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
30
internal/context/user.go
Normal file
30
internal/context/user.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2018 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 context
|
||||
|
||||
import (
|
||||
"gopkg.in/macaron.v1"
|
||||
|
||||
"gogs.io/gogs/internal/db"
|
||||
"gogs.io/gogs/internal/db/errors"
|
||||
)
|
||||
|
||||
// ParamsUser is the wrapper type of the target user defined by URL parameter, namely ':username'.
|
||||
type ParamsUser struct {
|
||||
*db.User
|
||||
}
|
||||
|
||||
// InjectParamsUser returns a handler that retrieves target user based on URL parameter ':username',
|
||||
// and injects it as *ParamsUser.
|
||||
func InjectParamsUser() macaron.Handler {
|
||||
return func(c *Context) {
|
||||
user, err := db.GetUserByName(c.Params(":username"))
|
||||
if err != nil {
|
||||
c.NotFoundOrServerError("GetUserByName", errors.IsUserNotExist, err)
|
||||
return
|
||||
}
|
||||
c.Map(&ParamsUser{user})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user