2020-07-29 15:39:46 +00:00
package main
import (
"database/sql"
"errors"
"net/http"
2020-09-18 10:34:52 +00:00
"strings"
2020-07-29 15:39:46 +00:00
)
2020-07-30 19:18:13 +00:00
var errRedirectNotFound = errors . New ( "redirect not found" )
2020-07-29 15:39:46 +00:00
func serveRedirect ( w http . ResponseWriter , r * http . Request ) {
2020-10-19 18:25:30 +00:00
redirect , err := getRedirect ( slashTrimmedPath ( r ) )
2020-07-30 19:18:13 +00:00
if err == errRedirectNotFound {
2020-07-31 19:02:47 +00:00
serve404 ( w , r )
2020-07-29 15:39:46 +00:00
return
} else if err != nil {
http . Error ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
2020-07-31 19:02:47 +00:00
// Send redirect
w . Header ( ) . Set ( "Location" , redirect )
2020-10-12 16:47:23 +00:00
render ( w , templateRedirect , & renderData {
Data : redirect ,
2020-07-31 13:48:01 +00:00
} )
2020-07-31 19:02:47 +00:00
w . WriteHeader ( http . StatusFound )
2020-07-29 15:39:46 +00:00
}
2020-10-19 18:25:30 +00:00
func getRedirect ( fromPath string ) ( string , error ) {
2020-07-29 15:39:46 +00:00
var toPath string
2020-10-19 18:25:30 +00:00
row := appDb . QueryRow ( "with recursive f (i, fp, tp) as (select 1, fromPath, toPath from redirects where fromPath = ? union all select f.i + 1, r.fromPath, r.toPath from redirects as r join f on f.tp = r.fromPath) select tp from f order by i desc limit 1" , fromPath )
2020-08-01 09:39:24 +00:00
err := row . Scan ( & toPath )
2020-07-29 15:39:46 +00:00
if err == sql . ErrNoRows {
2020-08-01 09:39:24 +00:00
return "" , errRedirectNotFound
2020-07-29 15:39:46 +00:00
} else if err != nil {
2020-08-01 09:39:24 +00:00
return "" , err
2020-07-29 15:39:46 +00:00
}
2020-08-01 09:39:24 +00:00
return toPath , nil
2020-07-29 15:39:46 +00:00
}
func allRedirectPaths ( ) ( [ ] string , error ) {
var redirectPaths [ ] string
rows , err := appDb . Query ( "select fromPath from redirects" )
if err != nil {
return nil , err
}
for rows . Next ( ) {
var path string
_ = rows . Scan ( & path )
redirectPaths = append ( redirectPaths , path )
}
return redirectPaths , nil
}
2020-09-18 10:34:52 +00:00
2020-09-20 20:04:42 +00:00
func createOrReplaceRedirect ( from , to string ) error {
2020-09-18 10:34:52 +00:00
if from == "" || to == "" {
return errors . New ( "empty path" )
}
2020-10-06 18:04:07 +00:00
if from == to {
// Don't need a redirect
return nil
}
2020-09-18 10:34:52 +00:00
from = strings . TrimSuffix ( from , "/" )
startWritingToDb ( )
tx , err := appDb . Begin ( )
if err != nil {
2020-09-20 20:04:42 +00:00
finishWritingToDb ( )
2020-09-18 10:34:52 +00:00
return err
}
2020-09-20 20:04:42 +00:00
_ , err = tx . Exec ( "insert or replace into redirects (fromPath, toPath) values (?, ?)" , from , to )
2020-09-18 10:34:52 +00:00
if err != nil {
_ = tx . Rollback ( )
2020-09-20 20:04:42 +00:00
finishWritingToDb ( )
2020-09-18 10:34:52 +00:00
return err
}
err = tx . Commit ( )
if err != nil {
2020-09-20 20:04:42 +00:00
finishWritingToDb ( )
2020-09-18 10:34:52 +00:00
return err
}
finishWritingToDb ( )
return reloadRouter ( )
}