2017-07-16 17:20:35 +02:00
package templates
2017-05-05 03:53:38 +02:00
2017-05-05 06:07:45 +02:00
import (
"html/template"
2017-10-07 01:39:38 +02:00
"path/filepath"
2017-05-05 06:07:45 +02:00
"math"
2017-09-15 02:57:32 +02:00
"math/rand"
2017-05-05 06:07:45 +02:00
"net/url"
"strconv"
2017-05-17 16:05:42 +02:00
"time"
2017-09-06 04:30:49 +02:00
"os"
"fmt"
2017-05-14 21:45:50 +02:00
2017-07-11 22:25:52 +02:00
"strings"
2017-06-28 13:42:38 +02:00
"github.com/CloudyKit/jet"
2017-05-17 07:58:40 +02:00
"github.com/NyaaPantsu/nyaa/config"
2017-06-29 13:15:23 +02:00
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/torrents"
2017-07-02 16:54:55 +02:00
"github.com/NyaaPantsu/nyaa/utils/categories"
"github.com/NyaaPantsu/nyaa/utils/filelist"
2017-07-02 23:53:23 +02:00
"github.com/NyaaPantsu/nyaa/utils/format"
2017-07-02 16:54:55 +02:00
"github.com/NyaaPantsu/nyaa/utils/publicSettings"
"github.com/NyaaPantsu/nyaa/utils/torrentLanguages"
Consistency, formatting, error checking, cleanup, and a couple bug fixes (#245)
* Checkpoint: it builds
The config, db, model, network, os, and public packages have had some
fixes to glaringly obvious flaws, dead code removed, and stylistic
changes.
* Style changes and old code removal in router
Router needs a lot of work done to its (lack of) error handling.
* Dead code removal and style changes
Now up to util/email/email.go. After I'm finished with the initial sweep
I'll go back and fix error handling and security issues. Then I'll fix
the broken API. Then I'll go through to add documentation and fix code
visibility.
* Finish dead code removal and style changes
Vendored libraries not touched. Everything still needs security fixes
and documentation. There's also one case of broken functionality.
* Fix accidental find-and-replace
* Style, error checking, saftey, bug fix changes
* Redo error checking erased during merge
* Re-add merge-erased fix. Make Safe safe.
2017-05-10 04:34:40 +02:00
)
2017-05-05 03:53:38 +02:00
2017-05-25 21:54:58 +02:00
// FuncMap : Functions accessible in templates by {{ $.Function }}
2017-06-28 13:42:38 +02:00
func templateFunctions ( vars jet . VarMap ) jet . VarMap {
2017-07-19 21:33:07 +02:00
vars . Set ( "getRawQuery" , getRawQuery )
vars . Set ( "genSearchWithOrdering" , genSearchWithOrdering )
2017-09-12 00:17:35 +02:00
vars . Set ( "genSearchWithCategory" , genSearchWithCategory )
2017-07-19 21:33:07 +02:00
vars . Set ( "genSortArrows" , genSortArrows )
vars . Set ( "genNav" , genNav )
vars . Set ( "Sukebei" , config . IsSukebei )
vars . Set ( "getDefaultLanguage" , publicSettings . GetDefaultLanguage )
vars . Set ( "FlagCode" , flagCode )
vars . Set ( "getAvatar" , getAvatar )
2017-09-06 04:30:49 +02:00
vars . Set ( "torrentFileExists" , torrentFileExists )
2017-07-19 21:33:07 +02:00
vars . Set ( "formatDateRFC" , formatDateRFC )
vars . Set ( "GetHostname" , format . GetHostname )
vars . Set ( "GetCategories" , categories . GetSelect )
vars . Set ( "GetCategory" , getCategory )
vars . Set ( "CategoryName" , categoryName )
vars . Set ( "GetTorrentLanguages" , torrentLanguages . GetTorrentLanguages )
vars . Set ( "LanguageName" , languageName )
vars . Set ( "LanguageNameFromCode" , languageNameFromCode )
vars . Set ( "fileSize" , fileSize )
vars . Set ( "DefaultUserSettings" , defaultUserSettings )
vars . Set ( "makeTreeViewData" , makeTreeViewData )
vars . Set ( "lastID" , lastID )
vars . Set ( "getReportDescription" , getReportDescription )
vars . Set ( "genUploaderLink" , genUploaderLink )
vars . Set ( "genActivityContent" , genActivityContent )
vars . Set ( "contains" , contains )
2017-09-11 19:45:39 +02:00
vars . Set ( "toString" , toString )
2017-09-08 15:08:12 +02:00
vars . Set ( "kilo_strcmp" , kilo_strcmp )
2017-09-09 14:05:51 +02:00
vars . Set ( "kilo_strfind" , kilo_strfind )
2017-09-15 02:57:32 +02:00
vars . Set ( "kilo_rand" , kilo_rand )
2017-09-17 22:10:43 +02:00
vars . Set ( "getDomainName" , getDomainName )
2017-10-07 01:39:38 +02:00
vars . Set ( "getThemeList" , getThemeList )
vars . Set ( "formatThemeName" , formatThemeName )
2017-10-11 03:24:09 +02:00
vars . Set ( "formatDate" , formatDate )
2017-07-19 21:33:07 +02:00
return vars
}
func getRawQuery ( currentURL * url . URL ) string {
return currentURL . RawQuery
}
func genSearchWithOrdering ( currentURL * url . URL , sortBy string ) string {
values := currentURL . Query ( )
order := false //Default is DESC
sort := "2" //Default is Date (Actually ID, but Date is the same thing)
2017-05-20 01:10:16 +02:00
2017-07-19 21:33:07 +02:00
if _ , ok := values [ "order" ] ; ok {
order , _ = strconv . ParseBool ( values [ "order" ] [ 0 ] )
}
if _ , ok := values [ "sort" ] ; ok {
sort = values [ "sort" ] [ 0 ]
}
2017-05-18 01:03:11 +02:00
2017-07-19 21:33:07 +02:00
if sort == sortBy {
order = ! order //Flip order by repeat-clicking
} else {
order = false //Default to descending when sorting by something new
}
2017-05-13 18:53:54 +02:00
2017-07-19 21:33:07 +02:00
values . Set ( "sort" , sortBy )
values . Set ( "order" , strconv . FormatBool ( order ) )
2017-05-14 14:30:09 +02:00
2017-07-19 21:33:07 +02:00
u , _ := url . Parse ( "/search" )
u . RawQuery = values . Encode ( )
2017-05-15 02:01:04 +02:00
2017-07-19 21:33:07 +02:00
return u . String ( )
}
2017-05-18 01:03:11 +02:00
2017-09-12 00:17:35 +02:00
func genSearchWithCategory ( currentURL * url . URL , category string ) string {
values := currentURL . Query ( )
cat := "_" //Default
if _ , ok := values [ "c" ] ; ok {
cat = values [ "c" ] [ 0 ]
}
cat = category
2017-09-11 19:45:39 +02:00
2017-09-12 00:17:35 +02:00
values . Set ( "c" , cat )
u , _ := url . Parse ( "/search" )
u . RawQuery = values . Encode ( )
return u . String ( )
}
2017-09-11 19:45:39 +02:00
2017-07-19 21:33:07 +02:00
func genSortArrows ( currentURL * url . URL , sortBy string ) template . HTML {
values := currentURL . Query ( )
leftclass := "sortarrowdim"
rightclass := "sortarrowdim"
2017-05-18 01:03:11 +02:00
2017-07-19 21:33:07 +02:00
order := false
sort := "2"
if _ , ok := values [ "order" ] ; ok {
order , _ = strconv . ParseBool ( values [ "order" ] [ 0 ] )
}
if _ , ok := values [ "sort" ] ; ok {
sort = values [ "sort" ] [ 0 ]
}
if sort == sortBy {
if order {
rightclass = ""
} else {
leftclass = ""
2017-05-15 02:01:04 +02:00
}
2017-07-19 21:33:07 +02:00
}
2017-05-15 02:01:04 +02:00
2017-07-19 21:33:07 +02:00
arrows := "<span class=\"sortarrowleft " + leftclass + "\">▼</span><span class=\"" + rightclass + "\">▲</span>"
2017-05-15 02:01:04 +02:00
2017-07-19 21:33:07 +02:00
return template . HTML ( arrows )
}
2017-05-05 03:53:38 +02:00
2017-09-12 15:03:26 +02:00
2017-07-19 21:33:07 +02:00
func genNav ( nav Navigation , currentURL * url . URL , pagesSelectable int ) template . HTML {
var ret = ""
if nav . TotalItem > 0 {
maxPages := math . Ceil ( float64 ( nav . TotalItem ) / float64 ( nav . MaxItemPerPage ) )
2017-07-02 23:53:23 +02:00
2017-09-12 15:03:26 +02:00
href := ""
display := " style=\"display:none;\""
2017-07-19 21:33:07 +02:00
if nav . CurrentPage - 1 > 0 {
2017-09-12 15:03:26 +02:00
display = ""
href = " href=\"" + "/" + nav . Route + "/1" + "?" + currentURL . RawQuery + "\""
2017-06-17 04:24:30 +02:00
}
2017-09-12 15:03:26 +02:00
ret = ret + "<a id=\"page-prev\"" + display + href + " aria-label=\"Previous\"><span aria-hidden=\"true\">«</span></a>"
2017-07-19 21:33:07 +02:00
startValue := 1
if nav . CurrentPage > pagesSelectable / 2 {
startValue = ( int ( math . Min ( ( float64 ( nav . CurrentPage ) + math . Floor ( float64 ( pagesSelectable ) / 2 ) ) , maxPages ) ) - pagesSelectable + 1 )
2017-05-22 18:25:04 +02:00
}
2017-07-19 21:33:07 +02:00
if startValue < 1 {
startValue = 1
2017-07-11 23:34:59 +02:00
}
2017-07-19 21:33:07 +02:00
endValue := ( startValue + pagesSelectable - 1 )
if endValue > int ( maxPages ) {
endValue = int ( maxPages )
}
for i := startValue ; i <= endValue ; i ++ {
pageNum := strconv . Itoa ( i )
url := "/" + nav . Route + "/" + pageNum
2017-09-12 15:03:26 +02:00
ret = ret + "<a aria-label=\"Page " + strconv . Itoa ( i ) + "\" href=\"" + url + "?" + currentURL . RawQuery + "\">" + "<span"
2017-07-19 21:33:07 +02:00
if i == nav . CurrentPage {
ret = ret + " class=\"active\""
2017-07-11 22:25:52 +02:00
}
2017-09-12 15:03:26 +02:00
ret = ret + ">" + strconv . Itoa ( i ) + "</span></a>"
2017-07-19 21:33:07 +02:00
}
2017-09-12 15:03:26 +02:00
href = ""
display = " style=\"display:none;\""
2017-07-19 21:33:07 +02:00
if nav . CurrentPage < int ( maxPages ) {
2017-09-12 15:03:26 +02:00
display = ""
href = " href=\"" + "/" + nav . Route + "/" + strconv . Itoa ( nav . CurrentPage + 1 ) + "?" + currentURL . RawQuery + "\""
2017-06-12 01:14:26 +02:00
}
2017-09-12 15:03:26 +02:00
ret = ret + "<a id=\"page-next\"" + display + href + " aria-label=\"Next\"><span aria-hidden=\"true\">»</span></a>"
2017-07-19 21:33:07 +02:00
itemsThisPageStart := nav . MaxItemPerPage * ( nav . CurrentPage - 1 ) + 1
itemsThisPageEnd := nav . MaxItemPerPage * nav . CurrentPage
if nav . TotalItem < itemsThisPageEnd {
itemsThisPageEnd = nav . TotalItem
2017-05-26 03:53:18 +02:00
}
2017-07-19 21:33:07 +02:00
ret = ret + "<p>" + strconv . Itoa ( itemsThisPageStart ) + "-" + strconv . Itoa ( itemsThisPageEnd ) + "/" + strconv . Itoa ( nav . TotalItem ) + "</p>"
}
return template . HTML ( ret )
}
2017-05-30 00:28:21 +02:00
2017-07-19 21:33:07 +02:00
func flagCode ( languageCode string ) string {
return publicSettings . Flag ( languageCode , true )
}
2017-05-30 00:28:21 +02:00
2017-07-19 21:33:07 +02:00
func getAvatar ( hash string , size int ) string {
return "https://www.gravatar.com/avatar/" + hash + "?s=" + strconv . Itoa ( size )
}
func formatDateRFC ( t time . Time ) string {
// because time.* isn't available in templates...
return t . Format ( time . RFC3339 )
}
func getCategory ( category string , keepParent bool ) categories . Categories {
cats := categories . GetSelect ( true , true )
found := false
categoryRet := categories . Categories { }
for _ , v := range cats {
if v . ID == category + "_" {
found = true
if keepParent {
categoryRet = append ( categoryRet , v )
2017-05-30 00:28:21 +02:00
}
2017-07-19 21:33:07 +02:00
} else if len ( v . ID ) <= 2 && len ( categoryRet ) > 0 {
break
} else if found {
categoryRet = append ( categoryRet , v )
}
}
return categoryRet
}
func categoryName ( category string , subCategory string ) string {
s := category + "_" + subCategory
if category , ok := categories . GetByID ( s ) ; ok {
return category . Name
}
return ""
}
func languageName ( lang publicSettings . Language , T publicSettings . TemplateTfunc ) string {
if strings . Contains ( lang . Name , "," ) {
langs := strings . Split ( lang . Name , ", " )
tags := strings . Split ( lang . Tag , ", " )
for k := range langs {
langs [ k ] = strings . Title ( publicSettings . Translate ( tags [ k ] , string ( T ( "language_code" ) ) ) )
2017-05-30 00:28:21 +02:00
}
2017-07-19 21:33:07 +02:00
return strings . Join ( langs , ", " )
}
return strings . Title ( lang . Translate ( T ( "language_code" ) ) )
}
func languageNameFromCode ( languageCode string , T publicSettings . TemplateTfunc ) string {
if strings . Contains ( languageCode , "," ) {
tags := strings . Split ( languageCode , ", " )
var langs [ ] string
for k := range tags {
langs = append ( langs , strings . Title ( publicSettings . Translate ( tags [ k ] , string ( T ( "language_code" ) ) ) ) )
2017-06-04 02:28:33 +02:00
}
2017-07-19 21:33:07 +02:00
return strings . Join ( langs , ", " )
}
return strings . Title ( publicSettings . Translate ( languageCode , string ( T ( "language_code" ) ) ) )
}
func fileSize ( filesize int64 , T publicSettings . TemplateTfunc ) template . HTML {
if filesize == 0 {
return T ( "unknown" )
}
return template . HTML ( format . FileSize ( filesize ) )
}
func defaultUserSettings ( s string ) bool {
return config . Get ( ) . Users . DefaultUserSettings [ s ]
}
2017-07-19 22:12:03 +02:00
func makeTreeViewData ( f * filelist . FileListFolder , nestLevel int , identifierChain string ) interface { } {
2017-07-19 21:33:07 +02:00
return struct {
Folder * filelist . FileListFolder
NestLevel int
IdentifierChain string
2017-07-19 22:12:03 +02:00
} { f , nestLevel , identifierChain }
2017-07-19 21:33:07 +02:00
}
func lastID ( currentURL * url . URL , torrents [ ] models . TorrentJSON ) int {
if len ( torrents ) == 0 {
return 0
}
values := currentURL . Query ( )
order := false
sort := "2"
if _ , ok := values [ "order" ] ; ok {
order , _ = strconv . ParseBool ( values [ "order" ] [ 0 ] )
}
if _ , ok := values [ "sort" ] ; ok {
sort = values [ "sort" ] [ 0 ]
}
lastID := 0
if sort == "2" || sort == "" {
if order {
lastID = int ( torrents [ len ( torrents ) - 1 ] . ID )
} else if len ( torrents ) > 0 {
lastID = int ( torrents [ 0 ] . ID )
2017-06-06 00:06:04 +02:00
}
2017-07-19 21:33:07 +02:00
}
return lastID
}
func getReportDescription ( d string , T publicSettings . TemplateTfunc ) string {
if d == "illegal" {
return "Illegal content"
} else if d == "spam" {
return "Spam / Garbage"
} else if d == "wrongcat" {
return "Wrong category"
} else if d == "dup" {
return "Duplicate / Deprecated"
}
return string ( T ( d ) )
}
func genUploaderLink ( uploaderID uint , uploaderName template . HTML , torrentHidden bool ) template . HTML {
uploaderID , username := torrents . HideUser ( uploaderID , string ( uploaderName ) , torrentHidden )
if uploaderID == 0 {
return template . HTML ( username )
}
url := "/user/" + strconv . Itoa ( int ( uploaderID ) ) + "/" + username
2017-06-28 13:42:38 +02:00
2017-07-19 21:33:07 +02:00
return template . HTML ( "<a href=\"" + url + "\">" + username + "</a>" )
}
func genActivityContent ( a models . Activity , T publicSettings . TemplateTfunc ) template . HTML {
return a . ToLocale ( T )
}
func contains ( arr interface { } , comp string ) bool {
switch str := arr . ( type ) {
case string :
if str == comp {
return true
2017-07-04 02:07:25 +02:00
}
2017-07-19 21:33:07 +02:00
case publicSettings . Language :
if str . Code == comp {
return true
}
default :
2017-07-04 02:07:25 +02:00
return false
2017-07-19 21:33:07 +02:00
}
return false
2017-05-05 06:07:45 +02:00
}
2017-09-06 04:30:49 +02:00
2017-09-09 14:05:51 +02:00
func torrentFileExists ( hash string , TorrentLink string ) bool {
2017-09-21 06:18:55 +02:00
domain := getDomainName ( )
if ( TorrentLink != "" && domain != "" && ! kilo_strfind ( TorrentLink , domain , len ( domain ) ) ) {
2017-09-09 14:05:51 +02:00
return true
}
2017-09-06 04:30:49 +02:00
Openfile , err := os . Open ( fmt . Sprintf ( "%s%c%s.torrent" , config . Get ( ) . Torrents . FileStorage , os . PathSeparator , hash ) )
if err != nil {
return false
}
defer Openfile . Close ( )
return true
}
2017-09-08 15:08:12 +02:00
2017-09-11 19:45:39 +02:00
func toString ( number int ) string {
return strconv . Itoa ( number )
}
2017-09-08 15:08:12 +02:00
func kilo_strcmp ( str1 string , str2 string , end int , start int ) bool {
//Compare two strings but has length arguments
len1 := len ( str1 )
len2 := len ( str2 )
if end == - 1 && len1 != len2 {
return false
}
if end == - 1 || end > len1 {
end = len1
}
if end > len2 {
end = len2
}
if start >= end {
return false
}
return strings . Compare ( str1 [ start : end ] , str2 [ start : end ] ) == 0
}
2017-09-09 14:05:51 +02:00
func kilo_strfind ( str1 string , searchfor string , start int ) bool {
//Search a string inside another with start parameter
//start parameter indicates where we start searching
len1 := len ( str1 )
if start >= len1 {
return false
}
return strings . Contains ( str1 [ start : len1 ] , searchfor )
}
2017-09-15 02:57:32 +02:00
2017-09-20 01:59:17 +02:00
func kilo_rand ( max int ) int {
return rand . Intn ( max )
2017-09-15 02:57:32 +02:00
}
2017-09-17 22:10:43 +02:00
func getDomainName ( ) string {
domain := config . Get ( ) . Cookies . DomainName
if config . Get ( ) . Environment == "DEVELOPMENT" {
domain = ""
}
return domain
}
2017-10-07 01:39:38 +02:00
func getThemeList ( ) ( [ ] string ) {
searchDir := "public/css/themes/"
themeList := [ ] string { }
filepath . Walk ( searchDir , func ( path string , f os . FileInfo , err error ) error {
if kilo_strfind ( path , ".css" , len ( searchDir ) ) {
//we only want .css file
fileName := path [ len ( searchDir ) : strings . Index ( path , ".css" ) ]
//Remove file extension and path, keep only file name
themeList = append ( themeList , fileName )
}
return nil
} )
return themeList
}
2017-10-10 02:33:38 +02:00
func formatThemeName ( name string , T publicSettings . TemplateTfunc ) string {
translationString := fmt . Sprintf ( "themes_%s" , name )
translatedName := string ( T ( translationString ) )
if translatedName != translationString {
//Translation string exists
return translatedName
}
2017-10-07 01:39:38 +02:00
2017-10-10 02:33:38 +02:00
if len ( name ) == 1 {
name = fmt . Sprintf ( "/%c/" , name [ 0 ] )
2017-10-07 01:39:38 +02:00
} else {
2017-10-10 02:33:38 +02:00
name = strings . Replace ( name , "_" , " " , - 1 )
name = strings . Title ( name )
2017-10-07 01:39:38 +02:00
//Upper case at each start of word
}
2017-10-10 02:33:38 +02:00
return name
2017-10-07 01:39:38 +02:00
}
2017-10-10 02:33:38 +02:00
2017-10-11 03:24:09 +02:00
func formatDate ( Date time . Time , short bool ) string {
Date = Date . UTC ( )
if short {
return fmt . Sprintf ( "%.3s %d, %d" , Date . Month ( ) , Date . Day ( ) , Date . Year ( ) )
}
if Date . Hour ( ) >= 12 {
return fmt . Sprintf ( "%d/%d/%d, %d:%.2d:%.2d PM UTC+0" , Date . Month ( ) , Date . Day ( ) , Date . Year ( ) , Date . Hour ( ) - 12 , Date . Minute ( ) , Date . Second ( ) )
} else {
return fmt . Sprintf ( "%d/%d/%d, %d:%.2d:%.2d AM UTC+0" , Date . Month ( ) , Date . Day ( ) , Date . Year ( ) , Date . Hour ( ) , Date . Minute ( ) , Date . Second ( ) )
}
}