2014-03-15 15:01:50 +04:00
// 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 middleware
import (
2014-03-15 17:17:16 +04:00
"fmt"
2014-03-22 21:44:02 +04:00
"html/template"
2014-04-15 20:27:29 +04:00
"io"
2014-03-15 15:01:50 +04:00
"net/http"
2014-03-23 00:40:09 +04:00
"strings"
2014-03-19 17:57:55 +04:00
"time"
2014-03-15 15:01:50 +04:00
2014-07-26 08:24:27 +04:00
"github.com/Unknwon/macaron"
2014-08-01 01:25:34 +04:00
"github.com/macaron-contrib/cache"
"github.com/macaron-contrib/csrf"
2014-07-26 08:24:27 +04:00
"github.com/macaron-contrib/i18n"
"github.com/macaron-contrib/session"
2014-03-21 17:06:47 +04:00
2014-03-15 15:01:50 +04:00
"github.com/gogits/gogs/models"
"github.com/gogits/gogs/modules/auth"
2014-03-21 17:31:47 +04:00
"github.com/gogits/gogs/modules/base"
2014-07-26 08:24:27 +04:00
"github.com/gogits/gogs/modules/git"
2014-03-15 15:01:50 +04:00
"github.com/gogits/gogs/modules/log"
2014-05-26 04:11:25 +04:00
"github.com/gogits/gogs/modules/setting"
2014-03-15 15:01:50 +04:00
)
2015-08-26 19:30:06 +03:00
type RepoContext struct {
AccessMode models . AccessMode
IsWatching bool
IsBranch bool
IsTag bool
IsCommit bool
Repository * models . Repository
Owner * models . User
Commit * git . Commit
Tag * git . Tag
GitRepo * git . Repository
BranchName string
TagName string
TreeName string
2015-08-31 10:24:28 +03:00
CommitID string
2015-08-26 19:30:06 +03:00
RepoLink string
CloneLink models . CloneLink
CommitsCount int
Mirror * models . Mirror
}
2014-03-15 17:17:16 +04:00
// Context represents context of a request.
2014-03-15 15:01:50 +04:00
type Context struct {
2014-07-26 08:24:27 +04:00
* macaron . Context
2014-08-01 01:25:34 +04:00
Cache cache . Cache
csrf csrf . CSRF
2014-07-26 08:24:27 +04:00
Flash * session . Flash
Session session . Store
2014-11-18 19:07:16 +03:00
User * models . User
IsSigned bool
IsBasicAuth bool
2014-03-15 20:03:23 +04:00
2015-02-16 13:51:56 +03:00
Repo RepoContext
2014-08-14 10:12:21 +04:00
Org struct {
IsOwner bool
IsMember bool
2014-08-15 14:29:41 +04:00
IsAdminTeam bool // In owner team or team that has admin permission level.
2014-08-14 10:12:21 +04:00
Organization * models . User
2014-08-15 14:29:41 +04:00
OrgLink string
2014-08-16 12:21:17 +04:00
Team * models . Team
2014-08-14 10:12:21 +04:00
}
2014-03-15 15:01:50 +04:00
}
2015-08-14 19:42:43 +03:00
// IsOwner returns true if current user is the owner of repository.
2015-02-16 13:51:56 +03:00
func ( r RepoContext ) IsOwner ( ) bool {
2015-08-14 19:42:43 +03:00
return r . AccessMode >= models . ACCESS_MODE_OWNER
}
// IsAdmin returns true if current user has admin or higher access of repository.
func ( r RepoContext ) IsAdmin ( ) bool {
return r . AccessMode >= models . ACCESS_MODE_ADMIN
2015-02-16 13:51:56 +03:00
}
// Return if the current user has read access for this repository
func ( r RepoContext ) HasAccess ( ) bool {
return r . AccessMode >= models . ACCESS_MODE_READ
}
2014-05-05 21:08:01 +04:00
// HasError returns true if error occurs in form validation.
func ( ctx * Context ) HasApiError ( ) bool {
hasErr , ok := ctx . Data [ "HasError" ]
if ! ok {
return false
}
return hasErr . ( bool )
}
func ( ctx * Context ) GetErrMsg ( ) string {
return ctx . Data [ "ErrorMsg" ] . ( string )
}
2014-03-15 18:52:14 +04:00
// HasError returns true if error occurs in form validation.
func ( ctx * Context ) HasError ( ) bool {
hasErr , ok := ctx . Data [ "HasError" ]
if ! ok {
return false
}
2014-04-14 02:12:07 +04:00
ctx . Flash . ErrorMsg = ctx . Data [ "ErrorMsg" ] . ( string )
ctx . Data [ "Flash" ] = ctx . Flash
2014-03-15 18:52:14 +04:00
return hasErr . ( bool )
}
2015-07-08 14:47:56 +03:00
// HasValue returns true if value of given name exists.
func ( ctx * Context ) HasValue ( name string ) bool {
_ , ok := ctx . Data [ name ]
return ok
}
2014-08-02 21:47:33 +04:00
// HTML calls Context.HTML and converts template name to string.
2014-07-26 08:24:27 +04:00
func ( ctx * Context ) HTML ( status int , name base . TplName ) {
2014-08-02 21:47:33 +04:00
ctx . Context . HTML ( status , string ( name ) )
2014-03-20 15:50:26 +04:00
}
2014-03-15 18:52:14 +04:00
// RenderWithErr used for page has form validation but need to prompt error to users.
2014-07-26 08:24:27 +04:00
func ( ctx * Context ) RenderWithErr ( msg string , tpl base . TplName , form interface { } ) {
2014-04-03 23:50:55 +04:00
if form != nil {
auth . AssignForm ( form , ctx . Data )
}
2014-04-11 00:36:50 +04:00
ctx . Flash . ErrorMsg = msg
ctx . Data [ "Flash" ] = ctx . Flash
2014-03-20 15:50:26 +04:00
ctx . HTML ( 200 , tpl )
2014-03-15 18:52:14 +04:00
}
2014-03-15 17:17:16 +04:00
// Handle handles and logs error by given status.
func ( ctx * Context ) Handle ( status int , title string , err error ) {
2014-05-02 02:53:41 +04:00
if err != nil {
2014-07-26 08:24:27 +04:00
log . Error ( 4 , "%s: %v" , title , err )
if macaron . Env != macaron . PROD {
2014-05-02 02:53:41 +04:00
ctx . Data [ "ErrorMsg" ] = err
}
2014-03-19 12:48:45 +04:00
}
2014-05-02 02:53:41 +04:00
switch status {
case 404 :
ctx . Data [ "Title" ] = "Page Not Found"
case 500 :
ctx . Data [ "Title" ] = "Internal Server Error"
}
2014-06-22 21:14:03 +04:00
ctx . HTML ( status , base . TplName ( fmt . Sprintf ( "status/%d" , status ) ) )
2014-03-15 15:01:50 +04:00
}
2015-03-28 17:30:05 +03:00
func ( ctx * Context ) HandleText ( status int , title string ) {
2015-07-08 14:47:56 +03:00
if ( status / 100 == 4 ) || ( status / 100 == 5 ) {
2015-03-28 17:30:05 +03:00
log . Error ( 4 , "%s" , title )
}
ctx . RenderData ( status , [ ] byte ( title ) )
}
2015-02-22 17:49:25 +03:00
func ( ctx * Context ) HandleAPI ( status int , obj interface { } ) {
var message string
if err , ok := obj . ( error ) ; ok {
message = err . Error ( )
} else {
message = obj . ( string )
}
ctx . JSON ( status , map [ string ] string {
"message" : message ,
} )
}
2014-04-15 20:27:29 +04:00
func ( ctx * 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
}
}
2014-07-26 08:24:27 +04:00
ctx . Resp . Header ( ) . Set ( "Content-Description" , "File Transfer" )
ctx . Resp . Header ( ) . Set ( "Content-Type" , "application/octet-stream" )
ctx . Resp . Header ( ) . Set ( "Content-Disposition" , "attachment; filename=" + name )
ctx . Resp . Header ( ) . Set ( "Content-Transfer-Encoding" , "binary" )
ctx . Resp . Header ( ) . Set ( "Expires" , "0" )
ctx . Resp . Header ( ) . Set ( "Cache-Control" , "must-revalidate" )
ctx . Resp . Header ( ) . Set ( "Pragma" , "public" )
2014-10-19 07:26:55 +04:00
http . ServeContent ( ctx . Resp , ctx . Req . Request , name , modtime , r )
2014-04-10 22:37:43 +04:00
}
2014-07-26 08:24:27 +04:00
// Contexter initializes a classic context for a request.
func Contexter ( ) macaron . Handler {
2014-08-01 01:25:34 +04:00
return func ( c * macaron . Context , l i18n . Locale , cache cache . Cache , sess session . Store , f * session . Flash , x csrf . CSRF ) {
2014-03-15 15:01:50 +04:00
ctx := & Context {
2014-07-26 08:24:27 +04:00
Context : c ,
2014-08-01 01:25:34 +04:00
Cache : cache ,
csrf : x ,
2014-07-26 08:24:27 +04:00
Flash : f ,
Session : sess ,
2014-03-15 15:01:50 +04:00
}
2014-07-26 08:24:27 +04:00
// Compute current URL for real-time change language.
2015-03-21 16:24:59 +03:00
ctx . Data [ "Link" ] = setting . AppSubUrl + ctx . Req . URL . Path
2014-04-10 22:37:43 +04:00
2014-07-26 08:24:27 +04:00
ctx . Data [ "PageStartTime" ] = time . Now ( )
2014-03-22 16:49:53 +04:00
2015-08-13 21:43:40 +03:00
// Check auto-signin.
if sess . Get ( "uid" ) == nil {
if _ , err := AutoSignIn ( ctx ) ; err != nil {
ctx . Handle ( 500 , "AutoSignIn" , err )
return
}
}
2014-03-15 15:01:50 +04:00
// Get user from session if logined.
2014-11-18 19:07:16 +03:00
ctx . User , ctx . IsBasicAuth = auth . SignedInUser ( ctx . Req . Request , ctx . Session )
2014-11-07 22:46:13 +03:00
2014-07-26 08:24:27 +04:00
if ctx . User != nil {
ctx . IsSigned = true
ctx . Data [ "IsSigned" ] = ctx . IsSigned
ctx . Data [ "SignedUser" ] = ctx . User
2015-08-19 18:14:57 +03:00
ctx . Data [ "SignedUserID" ] = ctx . User . Id
2014-11-07 06:06:41 +03:00
ctx . Data [ "SignedUserName" ] = ctx . User . Name
2014-03-20 16:02:14 +04:00
ctx . Data [ "IsAdmin" ] = ctx . User . IsAdmin
2014-11-07 06:06:41 +03:00
} else {
2015-08-19 18:14:57 +03:00
ctx . Data [ "SignedUserID" ] = 0
2014-11-07 06:06:41 +03:00
ctx . Data [ "SignedUserName" ] = ""
2014-03-15 16:50:17 +04:00
}
2014-03-15 15:01:50 +04:00
2014-07-24 17:19:59 +04:00
// If request sends files, parse them here otherwise the Query() can't be parsed and the CsrfToken will be invalid.
2014-07-26 08:24:27 +04:00
if ctx . Req . Method == "POST" && strings . Contains ( ctx . Req . Header . Get ( "Content-Type" ) , "multipart/form-data" ) {
if err := ctx . Req . ParseMultipartForm ( setting . AttachmentMaxSize << 20 ) ; err != nil && ! strings . Contains ( err . Error ( ) , "EOF" ) { // 32MB max size
ctx . Handle ( 500 , "ParseMultipartForm" , err )
2014-07-24 17:19:59 +04:00
return
}
}
2014-08-01 01:25:34 +04:00
ctx . Data [ "CsrfToken" ] = x . GetToken ( )
ctx . Data [ "CsrfTokenHtml" ] = template . HTML ( ` <input type="hidden" name="_csrf" value=" ` + x . GetToken ( ) + ` "> ` )
2014-03-19 17:57:55 +04:00
2015-02-07 05:16:23 +03:00
ctx . Data [ "ShowRegistrationButton" ] = setting . Service . ShowRegistrationButton
2015-03-23 17:19:19 +03:00
ctx . Data [ "ShowFooterBranding" ] = setting . ShowFooterBranding
2015-02-07 05:16:23 +03:00
2014-03-15 15:01:50 +04:00
c . Map ( ctx )
}
}