@ -23,24 +23,52 @@ import (
"github.com/gorilla/sessions"
"github.com/gorilla/sessions"
"github.com/writeas/impart"
"github.com/writeas/impart"
"github.com/writeas/web-core/log"
"github.com/writeas/web-core/log"
"github.com/writeas/writefreely/config"
"github.com/writeas/writefreely/page"
"github.com/writeas/writefreely/page"
)
)
// UserLevel represents the required user level for accessing an endpoint
type UserLevel int
type UserLevel int
const (
const (
UserLevelNone UserLevel = iota // user or not -- ignored
UserLevelNoneType UserLevel = iota // user or not -- ignored
UserLevelOptional // user or not -- object fetched if user
UserLevelOptionalType // user or not -- object fetched if user
UserLevelNoneRequired // non-user (required)
UserLevelNoneRequiredType // non-user (required)
UserLevelUser // user (required)
UserLevelUserType // user (required)
)
)
func UserLevelNone ( cfg * config . Config ) UserLevel {
return UserLevelNoneType
}
func UserLevelOptional ( cfg * config . Config ) UserLevel {
return UserLevelOptionalType
}
func UserLevelNoneRequired ( cfg * config . Config ) UserLevel {
return UserLevelNoneRequiredType
}
func UserLevelUser ( cfg * config . Config ) UserLevel {
return UserLevelUserType
}
// UserLevelReader returns the permission level required for any route where
// users can read published content.
func UserLevelReader ( cfg * config . Config ) UserLevel {
if cfg . App . Private {
return UserLevelUserType
}
return UserLevelOptionalType
}
type (
type (
handlerFunc func ( app * App , w http . ResponseWriter , r * http . Request ) error
handlerFunc func ( app * App , w http . ResponseWriter , r * http . Request ) error
userHandlerFunc func ( app * App , u * User , w http . ResponseWriter , r * http . Request ) error
userHandlerFunc func ( app * App , u * User , w http . ResponseWriter , r * http . Request ) error
userApperHandlerFunc func ( apper Apper , u * User , w http . ResponseWriter , r * http . Request ) error
userApperHandlerFunc func ( apper Apper , u * User , w http . ResponseWriter , r * http . Request ) error
dataHandlerFunc func ( app * App , w http . ResponseWriter , r * http . Request ) ( [ ] byte , string , error )
dataHandlerFunc func ( app * App , w http . ResponseWriter , r * http . Request ) ( [ ] byte , string , error )
authFunc func ( app * App , r * http . Request ) ( * User , error )
authFunc func ( app * App , r * http . Request ) ( * User , error )
UserLevelFunc func ( cfg * config . Config ) UserLevel
)
)
type Handler struct {
type Handler struct {
@ -307,7 +335,7 @@ func (h *Handler) Page(n string) http.HandlerFunc {
} , UserLevelOptional )
} , UserLevelOptional )
}
}
func ( h * Handler ) WebErrors ( f handlerFunc , ul UserLevel ) http . HandlerFunc {
func ( h * Handler ) WebErrors ( f handlerFunc , ul UserLevelFunc ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
return func ( w http . ResponseWriter , r * http . Request ) {
// TODO: factor out this logic shared with Web()
// TODO: factor out this logic shared with Web()
h . handleHTTPError ( w , r , func ( ) error {
h . handleHTTPError ( w , r , func ( ) error {
@ -331,21 +359,21 @@ func (h *Handler) WebErrors(f handlerFunc, ul UserLevel) http.HandlerFunc {
var session * sessions . Session
var session * sessions . Session
var err error
var err error
if ul != UserLevelNone {
if ul ( h . app . App ( ) . cfg ) != UserLevelNoneTyp e {
session , err = h . sessionStore . Get ( r , cookieName )
session , err = h . sessionStore . Get ( r , cookieName )
if err != nil && ( ul == UserLevelNoneRequired || ul == UserLevelUser ) {
if err != nil && ( ul ( h . app . App ( ) . cfg ) == UserLevelNoneRequiredType || ul ( h . app . App ( ) . cfg ) == UserLevelUserType ) {
// Cookie is required, but we can ignore this error
// Cookie is required, but we can ignore this error
log . Error ( "Handler: Unable to get session (for user permission %d); ignoring: %v" , ul , err )
log . Error ( "Handler: Unable to get session (for user permission %d); ignoring: %v" , ul , err )
}
}
_ , gotUser := session . Values [ cookieUserVal ] . ( * User )
_ , gotUser := session . Values [ cookieUserVal ] . ( * User )
if ul == UserLevelNoneRequired && gotUser {
if ul ( h . app . App ( ) . cfg ) == UserLevelNoneRequiredType && gotUser {
to := correctPageFromLoginAttempt ( r )
to := correctPageFromLoginAttempt ( r )
log . Info ( "Handler: Required NO user, but got one. Redirecting to %s" , to )
log . Info ( "Handler: Required NO user, but got one. Redirecting to %s" , to )
err := impart . HTTPError { http . StatusFound , to }
err := impart . HTTPError { http . StatusFound , to }
status = err . Status
status = err . Status
return err
return err
} else if ul == UserLevelUser && ! gotUser {
} else if ul ( h . app . App ( ) . cfg ) == UserLevelUserType && ! gotUser {
log . Info ( "Handler: Required a user, but DIDN'T get one. Sending not logged in." )
log . Info ( "Handler: Required a user, but DIDN'T get one. Sending not logged in." )
err := ErrNotLoggedIn
err := ErrNotLoggedIn
status = err . Status
status = err . Status
@ -380,9 +408,18 @@ func (h *Handler) WebErrors(f handlerFunc, ul UserLevel) http.HandlerFunc {
}
}
}
}
func ( h * Handler ) CollectionPostOrStatic ( w http . ResponseWriter , r * http . Request ) {
if strings . Contains ( r . URL . Path , "." ) && ! isRaw ( r ) {
// Serve static file
h . app . App ( ) . shttp . ServeHTTP ( w , r )
}
h . Web ( viewCollectionPost , UserLevelReader ) ( w , r )
}
// Web handles requests made in the web application. This provides user-
// Web handles requests made in the web application. This provides user-
// friendly HTML pages and actions that work in the browser.
// friendly HTML pages and actions that work in the browser.
func ( h * Handler ) Web ( f handlerFunc , ul UserLevel ) http . HandlerFunc {
func ( h * Handler ) Web ( f handlerFunc , ul UserLevelFunc ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
return func ( w http . ResponseWriter , r * http . Request ) {
h . handleHTTPError ( w , r , func ( ) error {
h . handleHTTPError ( w , r , func ( ) error {
var status int
var status int
@ -404,21 +441,21 @@ func (h *Handler) Web(f handlerFunc, ul UserLevel) http.HandlerFunc {
log . Info ( "\"%s %s\" %d %s \"%s\"" , r . Method , r . RequestURI , status , time . Since ( start ) , r . UserAgent ( ) )
log . Info ( "\"%s %s\" %d %s \"%s\"" , r . Method , r . RequestURI , status , time . Since ( start ) , r . UserAgent ( ) )
} ( )
} ( )
if ul != UserLevelNone {
if ul ( h . app . App ( ) . cfg ) != UserLevelNoneTyp e {
session , err := h . sessionStore . Get ( r , cookieName )
session , err := h . sessionStore . Get ( r , cookieName )
if err != nil && ( ul == UserLevelNoneRequired || ul == UserLevelUser ) {
if err != nil && ( ul ( h . app . App ( ) . cfg ) == UserLevelNoneRequiredType || ul ( h . app . App ( ) . cfg ) == UserLevelUserType ) {
// Cookie is required, but we can ignore this error
// Cookie is required, but we can ignore this error
log . Error ( "Handler: Unable to get session (for user permission %d); ignoring: %v" , ul , err )
log . Error ( "Handler: Unable to get session (for user permission %d); ignoring: %v" , ul , err )
}
}
_ , gotUser := session . Values [ cookieUserVal ] . ( * User )
_ , gotUser := session . Values [ cookieUserVal ] . ( * User )
if ul == UserLevelNoneRequired && gotUser {
if ul ( h . app . App ( ) . cfg ) == UserLevelNoneRequiredType && gotUser {
to := correctPageFromLoginAttempt ( r )
to := correctPageFromLoginAttempt ( r )
log . Info ( "Handler: Required NO user, but got one. Redirecting to %s" , to )
log . Info ( "Handler: Required NO user, but got one. Redirecting to %s" , to )
err := impart . HTTPError { http . StatusFound , to }
err := impart . HTTPError { http . StatusFound , to }
status = err . Status
status = err . Status
return err
return err
} else if ul == UserLevelUser && ! gotUser {
} else if ul ( h . app . App ( ) . cfg ) == UserLevelUserType && ! gotUser {
log . Info ( "Handler: Required a user, but DIDN'T get one. Sending not logged in." )
log . Info ( "Handler: Required a user, but DIDN'T get one. Sending not logged in." )
err := ErrNotLoggedIn
err := ErrNotLoggedIn
status = err . Status
status = err . Status
@ -478,7 +515,7 @@ func (h *Handler) All(f handlerFunc) http.HandlerFunc {
}
}
}
}
func ( h * Handler ) Download ( f dataHandlerFunc , ul UserLevel ) http . HandlerFunc {
func ( h * Handler ) Download ( f dataHandlerFunc , ul UserLevelFunc ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
return func ( w http . ResponseWriter , r * http . Request ) {
h . handleHTTPError ( w , r , func ( ) error {
h . handleHTTPError ( w , r , func ( ) error {
var status int
var status int
@ -523,27 +560,27 @@ func (h *Handler) Download(f dataHandlerFunc, ul UserLevel) http.HandlerFunc {
}
}
}
}
func ( h * Handler ) Redirect ( url string , ul UserLevel ) http . HandlerFunc {
func ( h * Handler ) Redirect ( url string , ul UserLevelFunc ) http . HandlerFunc {
return func ( w http . ResponseWriter , r * http . Request ) {
return func ( w http . ResponseWriter , r * http . Request ) {
h . handleHTTPError ( w , r , func ( ) error {
h . handleHTTPError ( w , r , func ( ) error {
start := time . Now ( )
start := time . Now ( )
var status int
var status int
if ul != UserLevelNone {
if ul ( h . app . App ( ) . cfg ) != UserLevelNoneTyp e {
session , err := h . sessionStore . Get ( r , cookieName )
session , err := h . sessionStore . Get ( r , cookieName )
if err != nil && ( ul == UserLevelNoneRequired || ul == UserLevelUser ) {
if err != nil && ( ul ( h . app . App ( ) . cfg ) == UserLevelNoneRequiredType || ul ( h . app . App ( ) . cfg ) == UserLevelUserType ) {
// Cookie is required, but we can ignore this error
// Cookie is required, but we can ignore this error
log . Error ( "Handler: Unable to get session (for user permission %d); ignoring: %v" , ul , err )
log . Error ( "Handler: Unable to get session (for user permission %d); ignoring: %v" , ul , err )
}
}
_ , gotUser := session . Values [ cookieUserVal ] . ( * User )
_ , gotUser := session . Values [ cookieUserVal ] . ( * User )
if ul == UserLevelNoneRequired && gotUser {
if ul ( h . app . App ( ) . cfg ) == UserLevelNoneRequiredType && gotUser {
to := correctPageFromLoginAttempt ( r )
to := correctPageFromLoginAttempt ( r )
log . Info ( "Handler: Required NO user, but got one. Redirecting to %s" , to )
log . Info ( "Handler: Required NO user, but got one. Redirecting to %s" , to )
err := impart . HTTPError { http . StatusFound , to }
err := impart . HTTPError { http . StatusFound , to }
status = err . Status
status = err . Status
return err
return err
} else if ul == UserLevelUser && ! gotUser {
} else if ul ( h . app . App ( ) . cfg ) == UserLevelUserType && ! gotUser {
log . Info ( "Handler: Required a user, but DIDN'T get one. Sending not logged in." )
log . Info ( "Handler: Required a user, but DIDN'T get one. Sending not logged in." )
err := ErrNotLoggedIn
err := ErrNotLoggedIn
status = err . Status
status = err . Status