2017-12-24 07:38:46 +00:00
package main
import (
2017-12-26 07:17:26 +00:00
"errors"
2017-12-24 07:38:46 +00:00
"log"
"net/http"
"strconv"
"strings"
"./common"
)
// TODO: Make this a static file somehow? Is it possible for us to put this file somewhere else?
// TODO: Add an API so that plugins can register disallowed areas. E.g. /guilds/join for plugin_guilds
func routeRobotsTxt ( w http . ResponseWriter , r * http . Request ) common . RouteError {
2018-01-15 08:24:18 +00:00
// TODO: Do we have to put * or something at the end of the paths?
2017-12-24 07:38:46 +00:00
_ , _ = w . Write ( [ ] byte ( ` User - agent : *
2018-01-18 12:31:25 +00:00
Disallow : / panel / *
2017-12-24 07:38:46 +00:00
Disallow : / topics / create /
2018-01-18 12:31:25 +00:00
Disallow : / user / edit / *
Disallow : / accounts / *
Disallow : / report / *
2017-12-24 07:38:46 +00:00
` ) )
return nil
}
var sitemapPageCap = 40000 // 40k, bump it up to 50k once we gzip this? Does brotli work on sitemaps?
func writeXMLHeader ( w http . ResponseWriter , r * http . Request ) {
w . Header ( ) . Set ( "Content-Type" , "application/xml" )
w . Write ( [ ] byte ( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ) )
}
// TODO: Keep track of when a sitemap was last modifed and add a lastmod element for it
func routeSitemapXml ( w http . ResponseWriter , r * http . Request ) common . RouteError {
var sslBit string
if common . Site . EnableSsl {
sslBit = "s"
}
var sitemapItem = func ( path string ) {
w . Write ( [ ] byte ( ` < sitemap >
< loc > http ` + sslBit + ` : //` + common.Site.URL + "/" + path + `</loc>
< / sitemap >
` ) )
}
writeXMLHeader ( w , r )
w . Write ( [ ] byte ( "<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n" ) )
sitemapItem ( "sitemaps/topics.xml" )
2017-12-24 22:08:35 +00:00
//sitemapItem("sitemaps/forums.xml")
2017-12-24 07:38:46 +00:00
//sitemapItem("sitemaps/users.xml")
w . Write ( [ ] byte ( "</sitemapindex>" ) )
return nil
}
type FuzzyRoute struct {
Path string
Handle func ( http . ResponseWriter , * http . Request , int ) common . RouteError
}
// TODO: Add a sitemap API and clean things up
// TODO: ^-- Make sure that the API is concurrent
// TODO: Add a social group sitemap
var sitemapRoutes = map [ string ] func ( http . ResponseWriter , * http . Request ) common . RouteError {
"forums.xml" : routeSitemapForums ,
"topics.xml" : routeSitemapTopics ,
}
// TODO: Use a router capable of parsing this rather than hard-coding the logic in
var fuzzySitemapRoutes = map [ string ] FuzzyRoute {
"topics_page_" : FuzzyRoute { "topics_page_(%d).xml" , routeSitemapTopic } ,
}
func sitemapSwitch ( w http . ResponseWriter , r * http . Request ) common . RouteError {
var path = r . URL . Path [ len ( "/sitemaps/" ) : ]
for name , fuzzy := range fuzzySitemapRoutes {
if strings . HasPrefix ( path , name ) && strings . HasSuffix ( path , ".xml" ) {
var spath = strings . TrimPrefix ( path , name )
spath = strings . TrimSuffix ( spath , ".xml" )
page , err := strconv . Atoi ( spath )
if err != nil {
if common . Dev . DebugMode {
log . Printf ( "Unable to convert string '%s' to integer in fuzzy route" , spath )
}
return common . NotFound ( w , r )
}
return fuzzy . Handle ( w , r , page )
}
}
route , ok := sitemapRoutes [ path ]
if ! ok {
return common . NotFound ( w , r )
}
return route ( w , r )
}
func routeSitemapForums ( w http . ResponseWriter , r * http . Request ) common . RouteError {
var sslBit string
if common . Site . EnableSsl {
sslBit = "s"
}
var sitemapItem = func ( path string ) {
w . Write ( [ ] byte ( ` < url >
< loc > http ` + sslBit + ` : //` + common.Site.URL + path + `</loc>
< / url >
` ) )
}
group , err := common . Groups . Get ( common . GuestUser . Group )
if err != nil {
2017-12-26 07:17:26 +00:00
return common . SilentInternalErrorXML ( errors . New ( "The guest group doesn't exist for some reason" ) , w , r )
2017-12-24 07:38:46 +00:00
}
writeXMLHeader ( w , r )
w . Write ( [ ] byte ( "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n" ) )
for _ , fid := range group . CanSee {
// Avoid data races by copying the struct into something we can freely mold without worrying about breaking something somewhere else
var forum = common . Forums . DirtyGet ( fid ) . Copy ( )
if forum . ParentID == 0 && forum . Name != "" && forum . Active {
sitemapItem ( common . BuildForumURL ( common . NameToSlug ( forum . Name ) , forum . ID ) )
}
}
w . Write ( [ ] byte ( "</urlset>" ) )
return nil
}
// TODO: Add a global ratelimit. 10 50MB files (smaller if compressed better) per minute?
// ? We might have problems with banned users, if they have fewer ViewTopic permissions than guests as they'll be able to see this list. Then again, a banned user could just logout to see it
func routeSitemapTopics ( w http . ResponseWriter , r * http . Request ) common . RouteError {
var sslBit string
if common . Site . EnableSsl {
sslBit = "s"
}
var sitemapItem = func ( path string ) {
w . Write ( [ ] byte ( ` < sitemap >
< loc > http ` + sslBit + ` : //` + common.Site.URL + "/" + path + `</loc>
< / sitemap >
` ) )
}
group , err := common . Groups . Get ( common . GuestUser . Group )
if err != nil {
2017-12-26 07:17:26 +00:00
return common . SilentInternalErrorXML ( errors . New ( "The guest group doesn't exist for some reason" ) , w , r )
2017-12-24 07:38:46 +00:00
}
2017-12-26 07:17:26 +00:00
var visibleForums [ ] common . Forum
2017-12-24 07:38:46 +00:00
for _ , fid := range group . CanSee {
forum := common . Forums . DirtyGet ( fid )
if forum . Name != "" && forum . Active {
2017-12-26 07:17:26 +00:00
visibleForums = append ( visibleForums , forum . Copy ( ) )
2017-12-24 07:38:46 +00:00
}
}
2017-12-26 07:17:26 +00:00
topicCount , err := common . TopicCountInForums ( visibleForums )
2017-12-24 07:38:46 +00:00
if err != nil {
2017-12-26 07:17:26 +00:00
return common . InternalErrorXML ( err , w , r )
2017-12-24 07:38:46 +00:00
}
var pageCount = topicCount / sitemapPageCap
//log.Print("topicCount", topicCount)
//log.Print("pageCount", pageCount)
2017-12-26 07:17:26 +00:00
writeXMLHeader ( w , r )
2017-12-24 07:38:46 +00:00
w . Write ( [ ] byte ( "<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n" ) )
for i := 0 ; i <= pageCount ; i ++ {
sitemapItem ( "sitemaps/topics_page_" + strconv . Itoa ( i ) + ".xml" )
}
w . Write ( [ ] byte ( "</sitemapindex>" ) )
return nil
}
func routeSitemapTopic ( w http . ResponseWriter , r * http . Request , page int ) common . RouteError {
/ * var sslBit string
if common . Site . EnableSsl {
sslBit = "s"
}
var sitemapItem = func ( path string ) {
w . Write ( [ ] byte ( ` < url >
< loc > http ` + sslBit + ` : //` + common.Site.URL + "/" + path + `</loc>
< / url >
` ) )
} * /
group , err := common . Groups . Get ( common . GuestUser . Group )
if err != nil {
2017-12-26 07:17:26 +00:00
return common . SilentInternalErrorXML ( errors . New ( "The guest group doesn't exist for some reason" ) , w , r )
2017-12-24 07:38:46 +00:00
}
2017-12-26 07:17:26 +00:00
var visibleForums [ ] common . Forum
2017-12-24 07:38:46 +00:00
for _ , fid := range group . CanSee {
forum := common . Forums . DirtyGet ( fid )
if forum . Name != "" && forum . Active {
2017-12-26 07:17:26 +00:00
visibleForums = append ( visibleForums , forum . Copy ( ) )
2017-12-24 07:38:46 +00:00
}
}
2017-12-26 07:17:26 +00:00
argList , qlist := common . ForumListToArgQ ( visibleForums )
topicCount , err := common . ArgQToTopicCount ( argList , qlist )
2017-12-24 07:38:46 +00:00
if err != nil {
2017-12-26 07:17:26 +00:00
return common . InternalErrorXML ( err , w , r )
2017-12-24 07:38:46 +00:00
}
var pageCount = topicCount / sitemapPageCap
//log.Print("topicCount", topicCount)
//log.Print("pageCount", pageCount)
//log.Print("page",page)
if page > pageCount {
page = pageCount
}
writeXMLHeader ( w , r )
w . Write ( [ ] byte ( "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n" ) )
w . Write ( [ ] byte ( "</urlset>" ) )
return nil
}
func routeSitemapUsers ( w http . ResponseWriter , r * http . Request ) common . RouteError {
writeXMLHeader ( w , r )
w . Write ( [ ] byte ( "<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n" ) )
return nil
}