2017-05-05 16:39:15 +02:00
package search
2017-05-06 12:41:48 +02:00
import (
"net/http"
2017-05-05 16:39:15 +02:00
"strconv"
"strings"
2017-05-08 15:50:18 +02:00
"unicode"
"unicode/utf8"
2017-05-05 16:39:15 +02:00
2017-05-17 07:58:40 +02:00
"github.com/NyaaPantsu/nyaa/cache"
"github.com/NyaaPantsu/nyaa/common"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/db"
"github.com/NyaaPantsu/nyaa/model"
"github.com/NyaaPantsu/nyaa/service"
"github.com/NyaaPantsu/nyaa/service/torrent"
"github.com/NyaaPantsu/nyaa/util/log"
2017-05-09 13:31:58 +02:00
)
2017-05-11 15:24:20 +02:00
var searchOperator string
2017-05-12 17:41:26 +02:00
var useTSQuery bool
2017-05-11 15:24:20 +02:00
func Configure ( conf * config . SearchConfig ) ( err error ) {
2017-05-12 19:38:08 +02:00
useTSQuery = false
2017-05-12 17:41:26 +02:00
// Postgres needs ILIKE for case-insensitivity
if db . ORM . Dialect ( ) . GetName ( ) == "postgres" {
2017-05-11 15:24:20 +02:00
searchOperator = "ILIKE ?"
2017-05-12 19:38:08 +02:00
//useTSQuery = true
// !!DISABLED!! because this makes search a lot stricter
// (only matches at word borders)
2017-05-12 17:41:26 +02:00
} else {
searchOperator = "LIKE ?"
2017-05-11 15:24:20 +02:00
}
return
}
2017-05-12 17:41:26 +02:00
func stringIsAscii ( input string ) bool {
for _ , char := range input {
if char > 127 {
return false
}
}
return true
}
2017-05-10 11:03:49 +02:00
func SearchByQuery ( r * http . Request , pagenum int ) ( search common . SearchParam , tor [ ] model . Torrent , count int , err error ) {
2017-05-20 13:45:15 +02:00
search , tor , count , err = searchByQuery ( r , pagenum , true , false )
return
}
func SearchByQueryWithUser ( r * http . Request , pagenum int ) ( search common . SearchParam , tor [ ] model . Torrent , count int , err error ) {
search , tor , count , err = searchByQuery ( r , pagenum , true , true )
2017-05-09 17:07:42 +02:00
return
}
2017-05-10 11:03:49 +02:00
func SearchByQueryNoCount ( r * http . Request , pagenum int ) ( search common . SearchParam , tor [ ] model . Torrent , err error ) {
2017-05-20 13:45:15 +02:00
search , tor , _ , err = searchByQuery ( r , pagenum , false , false )
2017-05-09 17:07:42 +02:00
return
}
2017-05-20 13:45:15 +02:00
func searchByQuery ( r * http . Request , pagenum int , countAll bool , withUser bool ) (
2017-05-10 11:03:49 +02:00
search common . SearchParam , tor [ ] model . Torrent , count int , err error ,
) {
2017-05-09 13:31:58 +02:00
max , err := strconv . ParseUint ( r . URL . Query ( ) . Get ( "max" ) , 10 , 32 )
if err != nil {
max = 50 // default Value maxPerPage
} else if max > 300 {
max = 300
2017-05-05 16:39:15 +02:00
}
2017-05-09 13:31:58 +02:00
search . Max = uint ( max )
2017-05-10 11:32:49 +02:00
search . Page = pagenum
2017-05-09 13:31:58 +02:00
search . Query = r . URL . Query ( ) . Get ( "q" )
2017-05-11 03:52:36 +02:00
userID , _ := strconv . Atoi ( r . URL . Query ( ) . Get ( "userID" ) )
2017-05-11 13:40:50 +02:00
search . UserID = uint ( userID )
2017-05-06 12:41:48 +02:00
2017-05-09 13:31:58 +02:00
switch s := r . URL . Query ( ) . Get ( "s" ) ; s {
case "1" :
2017-05-10 11:03:49 +02:00
search . Status = common . FilterRemakes
2017-05-09 13:31:58 +02:00
case "2" :
2017-05-10 11:03:49 +02:00
search . Status = common . Trusted
2017-05-09 13:31:58 +02:00
case "3" :
2017-05-10 11:03:49 +02:00
search . Status = common . APlus
2017-05-06 12:41:48 +02:00
}
2017-05-05 16:39:15 +02:00
2017-05-09 13:31:58 +02:00
catString := r . URL . Query ( ) . Get ( "c" )
if s := catString ; len ( s ) > 1 && s != "_" {
var tmp uint64
tmp , err = strconv . ParseUint ( string ( s [ 0 ] ) , 10 , 8 )
if err != nil {
return
}
search . Category . Main = uint8 ( tmp )
2017-05-05 16:39:15 +02:00
2017-05-14 06:03:04 +02:00
if len ( s ) > 2 && len ( s ) < 5 {
tmp , err = strconv . ParseUint ( s [ 2 : ] , 10 , 8 )
2017-05-09 13:31:58 +02:00
if err != nil {
return
}
search . Category . Sub = uint8 ( tmp )
}
2017-05-05 16:39:15 +02:00
}
2017-05-08 16:39:41 +02:00
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
orderBy := ""
2017-05-09 13:31:58 +02:00
switch s := r . URL . Query ( ) . Get ( "sort" ) ; s {
case "1" :
2017-05-10 11:03:49 +02:00
search . Sort = common . Name
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
orderBy += "torrent_name"
2017-05-11 13:40:50 +02:00
break
2017-05-09 13:31:58 +02:00
case "2" :
2017-05-10 11:03:49 +02:00
search . Sort = common . Date
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
orderBy += "date"
2017-05-14 17:27:18 +02:00
search . NotNull = "date IS NOT NULL"
2017-05-11 13:40:50 +02:00
break
2017-05-09 13:31:58 +02:00
case "3" :
2017-05-10 11:03:49 +02:00
search . Sort = common . Downloads
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
orderBy += "downloads"
2017-05-11 13:40:50 +02:00
break
2017-05-09 13:31:58 +02:00
case "4" :
2017-05-10 11:03:49 +02:00
search . Sort = common . Size
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
orderBy += "filesize"
2017-05-14 17:27:18 +02:00
// avoid sorting completely breaking on postgres
2017-05-17 23:41:18 +02:00
search . NotNull = ""
2017-05-11 13:40:50 +02:00
break
2017-05-11 02:26:58 +02:00
case "5" :
2017-05-11 13:40:50 +02:00
search . Sort = common . Seeders
2017-05-11 02:26:58 +02:00
orderBy += "seeders"
2017-05-17 23:41:18 +02:00
search . NotNull = ""
2017-05-11 13:40:50 +02:00
break
2017-05-11 02:26:58 +02:00
case "6" :
2017-05-11 13:40:50 +02:00
search . Sort = common . Leechers
2017-05-11 02:26:58 +02:00
orderBy += "leechers"
2017-05-17 23:41:18 +02:00
search . NotNull = ""
2017-05-11 13:40:50 +02:00
break
2017-05-11 02:26:58 +02:00
case "7" :
2017-05-11 13:40:50 +02:00
search . Sort = common . Completed
2017-05-11 02:26:58 +02:00
orderBy += "completed"
2017-05-17 23:41:18 +02:00
search . NotNull = ""
2017-05-11 13:40:50 +02:00
break
2017-05-08 16:39:41 +02:00
default :
2017-05-11 13:40:50 +02:00
search . Sort = common . ID
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
orderBy += "torrent_id"
2017-05-05 16:39:15 +02:00
}
2017-05-08 16:39:41 +02:00
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
orderBy += " "
2017-05-09 13:31:58 +02:00
switch s := r . URL . Query ( ) . Get ( "order" ) ; s {
case "true" :
search . Order = true
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
orderBy += "asc"
2017-05-17 23:41:18 +02:00
if db . ORM . Dialect ( ) . GetName ( ) == "postgres" {
orderBy += " NULLS FIRST"
}
2017-05-08 16:39:41 +02:00
default :
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
orderBy += "desc"
2017-05-17 23:41:18 +02:00
if db . ORM . Dialect ( ) . GetName ( ) == "postgres" {
orderBy += " NULLS LAST"
}
}
2017-05-11 14:22:49 +02:00
parameters := serviceBase . WhereParams {
Params : make ( [ ] interface { } , 0 , 64 ) ,
}
conditions := make ( [ ] string , 0 , 64 )
2017-05-08 16:39:41 +02:00
2017-05-11 14:22:49 +02:00
if search . Category . Main != 0 {
conditions = append ( conditions , "category = ?" )
2017-05-14 06:03:04 +02:00
parameters . Params = append ( parameters . Params , search . Category . Main )
2017-05-11 14:22:49 +02:00
}
if search . UserID != 0 {
conditions = append ( conditions , "uploader = ?" )
parameters . Params = append ( parameters . Params , search . UserID )
}
if search . Category . Sub != 0 {
conditions = append ( conditions , "sub_category = ?" )
2017-05-14 06:03:04 +02:00
parameters . Params = append ( parameters . Params , search . Category . Sub )
2017-05-11 14:22:49 +02:00
}
if search . Status != 0 {
if search . Status == common . FilterRemakes {
2017-05-11 21:46:23 +02:00
conditions = append ( conditions , "status <> ?" )
2017-05-11 14:22:49 +02:00
} else {
conditions = append ( conditions , "status >= ?" )
2017-05-11 13:40:50 +02:00
}
2017-05-11 14:22:49 +02:00
parameters . Params = append ( parameters . Params , strconv . Itoa ( int ( search . Status ) + 1 ) )
}
if len ( search . NotNull ) > 0 {
conditions = append ( conditions , search . NotNull )
}
2017-05-09 13:31:58 +02:00
2017-05-11 14:22:49 +02:00
searchQuerySplit := strings . Fields ( search . Query )
2017-05-12 17:41:26 +02:00
for _ , word := range searchQuerySplit {
2017-05-11 14:22:49 +02:00
firstRune , _ := utf8 . DecodeRuneInString ( word )
if len ( word ) == 1 && unicode . IsPunct ( firstRune ) {
// some queries have a single punctuation character
// which causes a full scan instead of using the index
// and yields no meaningful results.
// due to len() == 1 we're just looking at 1-byte/ascii
// punctuation characters.
continue
2017-05-08 15:50:18 +02:00
}
2017-05-09 14:31:47 +02:00
2017-05-12 17:41:26 +02:00
if useTSQuery && stringIsAscii ( word ) {
conditions = append ( conditions , "torrent_name @@ plainto_tsquery(?)" )
parameters . Params = append ( parameters . Params , word )
} else {
// TODO: possible to make this faster?
conditions = append ( conditions , "torrent_name " + searchOperator )
parameters . Params = append ( parameters . Params , "%" + word + "%" )
}
2017-05-11 14:22:49 +02:00
}
parameters . Conditions = strings . Join ( conditions [ : ] , " AND " )
2017-05-11 15:24:20 +02:00
2017-05-11 14:22:49 +02:00
log . Infof ( "SQL query is :: %s\n" , parameters . Conditions )
2017-05-05 16:39:15 +02:00
2017-05-11 15:24:20 +02:00
tor , count , err = cache . Impl . Get ( search , func ( ) ( tor [ ] model . Torrent , count int , err error ) {
2017-05-20 13:45:15 +02:00
if countAll && ! withUser {
2017-05-10 11:32:49 +02:00
tor , count , err = torrentService . GetTorrentsOrderBy ( & parameters , orderBy , int ( search . Max ) , int ( search . Max ) * ( search . Page - 1 ) )
2017-05-20 13:45:15 +02:00
} else if withUser {
tor , count , err = torrentService . GetTorrentsWithUserOrderBy ( & parameters , orderBy , int ( search . Max ) , int ( search . Max ) * ( search . Page - 1 ) )
2017-05-09 14:31:47 +02:00
} else {
2017-05-10 11:32:49 +02:00
tor , err = torrentService . GetTorrentsOrderByNoCount ( & parameters , orderBy , int ( search . Max ) , int ( search . Max ) * ( search . Page - 1 ) )
2017-05-09 14:31:47 +02:00
}
2017-05-10 11:03:49 +02:00
return
} )
2017-05-09 13:31:58 +02:00
return
2017-05-12 17:41:26 +02:00
}