2018-11-20 04:07:36 +00:00
package routes
import (
"database/sql"
"net/http"
"path/filepath"
"strconv"
"strings"
2019-04-19 06:36:26 +00:00
c "github.com/Azareal/Gosora/common"
2020-01-23 06:17:50 +00:00
qgen "github.com/Azareal/Gosora/query_gen"
2018-11-20 04:07:36 +00:00
)
type AttachmentStmts struct {
get * sql . Stmt
}
var attachmentStmts AttachmentStmts
// TODO: Abstract this with an attachment store
func init ( ) {
2019-04-19 06:36:26 +00:00
c . DbInits . Add ( func ( acc * qgen . Accumulator ) error {
2018-11-20 04:07:36 +00:00
attachmentStmts = AttachmentStmts {
2020-01-23 06:17:50 +00:00
get : acc . Select ( "attachments" ) . Columns ( "sectionID, sectionTable, originID, originTable, uploadedBy, path" ) . Where ( "path=? AND sectionID=? AND sectionTable=?" ) . Prepare ( ) ,
2018-11-20 04:07:36 +00:00
}
return acc . FirstError ( )
} )
}
2020-01-23 06:17:50 +00:00
var maxAgeYear = "max-age=" + strconv . Itoa ( int ( c . Year ) )
2020-03-18 09:21:34 +00:00
func ShowAttachment ( w http . ResponseWriter , r * http . Request , user * c . User , filename string ) c . RouteError {
2019-04-19 06:36:26 +00:00
filename = c . Stripslashes ( filename )
2019-07-26 23:29:42 +00:00
ext := filepath . Ext ( "./attachs/" + filename )
2019-04-19 06:36:26 +00:00
if ! c . AllowedFileExts . Contains ( strings . TrimPrefix ( ext , "." ) ) {
return c . LocalError ( "Bad extension" , w , r , user )
2018-11-20 04:07:36 +00:00
}
2019-10-01 21:06:22 +00:00
sid , err := strconv . Atoi ( r . FormValue ( "sid" ) )
2018-11-20 04:07:36 +00:00
if err != nil {
2019-10-01 21:06:22 +00:00
return c . LocalError ( "The sid is not an integer" , w , r , user )
2018-11-20 04:07:36 +00:00
}
2019-07-25 07:00:49 +00:00
sectionTable := r . FormValue ( "stype" )
2018-11-20 04:07:36 +00:00
var originTable string
var originID , uploadedBy int
2019-10-01 21:06:22 +00:00
err = attachmentStmts . get . QueryRow ( filename , sid , sectionTable ) . Scan ( & sid , & sectionTable , & originID , & originTable , & uploadedBy , & filename )
2018-11-20 04:07:36 +00:00
if err == sql . ErrNoRows {
2019-04-19 06:36:26 +00:00
return c . NotFound ( w , r , nil )
2018-11-20 04:07:36 +00:00
} else if err != nil {
2019-04-19 06:36:26 +00:00
return c . InternalError ( err , w , r )
2018-11-20 04:07:36 +00:00
}
if sectionTable == "forums" {
2020-03-18 09:21:34 +00:00
_ , ferr := c . SimpleForumUserCheck ( w , r , user , sid )
2018-11-20 04:07:36 +00:00
if ferr != nil {
return ferr
}
if ! user . Perms . ViewTopic {
2019-04-19 06:36:26 +00:00
return c . NoPermissions ( w , r , user )
2018-11-20 04:07:36 +00:00
}
} else {
2019-04-19 06:36:26 +00:00
return c . LocalError ( "Unknown section" , w , r , user )
2018-11-20 04:07:36 +00:00
}
2020-01-23 06:17:50 +00:00
2018-11-20 04:07:36 +00:00
if originTable != "topics" && originTable != "replies" {
2019-04-19 06:36:26 +00:00
return c . LocalError ( "Unknown origin" , w , r , user )
2018-11-20 04:07:36 +00:00
}
if ! user . Loggedin {
2020-01-23 06:17:50 +00:00
w . Header ( ) . Set ( "Cache-Control" , maxAgeYear )
2018-11-20 04:07:36 +00:00
} else {
2019-04-19 06:36:26 +00:00
guest := c . GuestUser
2019-10-01 21:06:22 +00:00
_ , ferr := c . SimpleForumUserCheck ( w , r , & guest , sid )
2018-11-20 04:07:36 +00:00
if ferr != nil {
return ferr
}
2019-11-04 11:55:52 +00:00
h := w . Header ( )
2018-11-20 04:07:36 +00:00
if guest . Perms . ViewTopic {
2020-01-23 06:17:50 +00:00
h . Set ( "Cache-Control" , maxAgeYear )
2018-11-20 04:07:36 +00:00
} else {
2019-11-04 11:55:52 +00:00
h . Set ( "Cache-Control" , "private" )
2018-11-20 04:07:36 +00:00
}
}
// TODO: Fix the problem where non-existent files aren't greeted with custom 404s on ServeFile()'s side
http . ServeFile ( w , r , "./attachs/" + filename )
return nil
}
2018-12-28 02:08:35 +00:00
2020-03-21 07:44:33 +00:00
func deleteAttachment ( w http . ResponseWriter , r * http . Request , u * c . User , aid int , js bool ) c . RouteError {
2020-01-23 06:17:50 +00:00
err := c . DeleteAttachment ( aid )
2018-12-28 02:08:35 +00:00
if err == sql . ErrNoRows {
2019-04-19 06:36:26 +00:00
return c . NotFoundJSQ ( w , r , nil , js )
2020-02-18 22:43:55 +00:00
} else if err != nil {
return c . InternalErrorJSQ ( err , w , r , js )
2018-12-28 02:08:35 +00:00
}
2020-02-18 22:43:55 +00:00
return nil
2018-12-28 02:08:35 +00:00
}
// TODO: Stop duplicating this code
// TODO: Use a transaction here
// TODO: Move this function to neutral ground
2020-03-21 07:44:33 +00:00
func uploadAttachment ( w http . ResponseWriter , r * http . Request , u * c . User , sid int , stable string , oid int , otable , extra string ) ( pathMap map [ string ] string , rerr c . RouteError ) {
2018-12-28 02:08:35 +00:00
pathMap = make ( map [ string ] string )
2020-03-21 07:44:33 +00:00
files , rerr := uploadFilesWithHash ( w , r , u , "./attachs/" )
2018-12-28 02:08:35 +00:00
if rerr != nil {
return nil , rerr
}
for _ , filename := range files {
2020-03-21 07:44:33 +00:00
aid , err := c . Attachments . Add ( sid , stable , oid , otable , u . ID , filename , extra )
2018-12-28 02:08:35 +00:00
if err != nil {
2019-04-19 06:36:26 +00:00
return nil , c . InternalError ( err , w , r )
2018-12-28 02:08:35 +00:00
}
_ , ok := pathMap [ filename ]
if ok {
pathMap [ filename ] += "," + strconv . Itoa ( aid )
} else {
pathMap [ filename ] = strconv . Itoa ( aid )
}
2020-02-20 04:32:49 +00:00
err = c . Attachments . AddLinked ( otable , oid )
2020-02-19 10:32:26 +00:00
if err != nil {
return nil , c . InternalError ( err , w , r )
2018-12-28 02:08:35 +00:00
}
}
return pathMap , nil
}