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.
Cette révision appartient à :
Parent
130ef6f6ad
révision
c9b72206a5
|
@ -3,7 +3,6 @@ package config
|
|||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
|
@ -11,19 +10,20 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
// Highest torrent ID that was copied from nyaa
|
||||
LastOldTorrentId = 923000
|
||||
// LastOldTorrentID is the highest torrent ID
|
||||
// that was copied from the original Nyaa
|
||||
LastOldTorrentID = 923000
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Host string `json: "host"`
|
||||
Port int `json: "port"`
|
||||
DBType string `json: "db_type"`
|
||||
// This will be directly passed to Gorm, and its internal
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
DBType string `json:"db_type"`
|
||||
// DBParams will be directly passed to Gorm, and its internal
|
||||
// structure depends on the dialect for each db type
|
||||
DBParams string `json: "db_params"`
|
||||
DBParams string `json:"db_params"`
|
||||
// optional i2p configuration
|
||||
I2P *I2PConfig `json: "i2p"`
|
||||
I2P *I2PConfig `json:"i2p"`
|
||||
}
|
||||
|
||||
var Defaults = Config{"localhost", 9999, "sqlite3", "./nyaa.db?cache_size=50", nil}
|
||||
|
@ -35,7 +35,7 @@ var allowedDatabaseTypes = map[string]bool{
|
|||
"mssql": true,
|
||||
}
|
||||
|
||||
func NewConfig() *Config {
|
||||
func New() *Config {
|
||||
var config Config
|
||||
config.Host = Defaults.Host
|
||||
config.Port = Defaults.Port
|
||||
|
@ -44,28 +44,25 @@ func NewConfig() *Config {
|
|||
return &config
|
||||
}
|
||||
|
||||
type processFlags func() error
|
||||
|
||||
func (config *Config) BindFlags() processFlags {
|
||||
// This function returns a function which is to be used after
|
||||
// flag.Parse to check and copy the flags' values to the Config instance.
|
||||
|
||||
conf_file := flag.String("conf", "", "path to the configuration file")
|
||||
db_type := flag.String("dbtype", Defaults.DBType, "database backend")
|
||||
// BindFlags returns a function which is to be used after
|
||||
// flag.Parse to check and copy the flags' values to the Config instance.
|
||||
func (config *Config) BindFlags() func() error {
|
||||
confFile := flag.String("conf", "", "path to the configuration file")
|
||||
dbType := flag.String("dbtype", Defaults.DBType, "database backend")
|
||||
host := flag.String("host", Defaults.Host, "binding address of the server")
|
||||
port := flag.Int("port", Defaults.Port, "port of the server")
|
||||
db_params := flag.String("dbparams", Defaults.DBParams, "parameters to open the database (see Gorm's doc)")
|
||||
dbParams := flag.String("dbparams", Defaults.DBParams, "parameters to open the database (see Gorm's doc)")
|
||||
|
||||
return func() error {
|
||||
// You can override fields in the config file with flags.
|
||||
config.Host = *host
|
||||
config.Port = *port
|
||||
config.DBParams = *db_params
|
||||
err := config.SetDBType(*db_type)
|
||||
config.DBParams = *dbParams
|
||||
err := config.SetDBType(*dbType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = config.HandleConfFileFlag(*conf_file)
|
||||
err = config.HandleConfFileFlag(*confFile)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -74,12 +71,12 @@ func (config *Config) HandleConfFileFlag(path string) error {
|
|||
if path != "" {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Can't read file '%s'.", path))
|
||||
return fmt.Errorf("can't read file '%s'", path)
|
||||
}
|
||||
|
||||
err = config.Read(bufio.NewReader(file))
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf("Failed to parse file '%s' (%s).", path, err))
|
||||
return fmt.Errorf("failed to parse file '%s' (%s)", path, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -87,7 +84,7 @@ func (config *Config) HandleConfFileFlag(path string) error {
|
|||
|
||||
func (config *Config) SetDBType(db_type string) error {
|
||||
if !allowedDatabaseTypes[db_type] {
|
||||
return errors.New(fmt.Sprintf("Unknown database backend '%s'.", db_type))
|
||||
return fmt.Errorf("unknown database backend '%s'", db_type)
|
||||
}
|
||||
config.DBType = db_type
|
||||
return nil
|
||||
|
|
|
@ -2,6 +2,9 @@ package config
|
|||
|
||||
import "time"
|
||||
|
||||
// TODO: Perform email configuration at runtime
|
||||
// Future hosts shouldn't have to rebuild the binary to update a setting
|
||||
|
||||
const (
|
||||
SendEmail = true
|
||||
EmailFrom = "donotrespond@nyaa.pantsu.cat"
|
||||
|
@ -10,8 +13,7 @@ const (
|
|||
EmailUsername = ""
|
||||
EmailPassword = ""
|
||||
EmailPort = 465
|
||||
// EmailTimeout = 80 * time.Millisecond
|
||||
EmailTimeout = 10 * time.Second
|
||||
EmailTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
var EmailTokenHashKey = []byte("CHANGE_THIS_BEFORE_DEPLOYING_YOU_RETARD")
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package config
|
||||
|
||||
// Constants for environment.
|
||||
// TODO: Perform environment configuration at runtime
|
||||
// Future hosts shouldn't have to rebuild the binary to update a setting
|
||||
|
||||
const (
|
||||
// DEVELOPMENT | TEST | PRODUCTION
|
||||
Environment = "DEVELOPMENT"
|
||||
// Environment = "PRODUCTION"
|
||||
WebAddress = "nyaa.pantsu.cat"
|
||||
// Environment should be one of: DEVELOPMENT, TEST, PRODUCTION
|
||||
Environment = "DEVELOPMENT"
|
||||
WebAddress = "nyaa.pantsu.cat"
|
||||
AuthTokenExpirationDay = 1000
|
||||
)
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package config
|
||||
|
||||
// i2p connectivity config
|
||||
type I2PConfig struct {
|
||||
Name string `json: "name"`
|
||||
Addr string `json: "samaddr"`
|
||||
Keyfile string `json: "keyfile"`
|
||||
Name string `json:"name"`
|
||||
Addr string `json:"samaddr"`
|
||||
Keyfile string `json:"keyfile"`
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package config
|
||||
|
||||
// Constants for logger.
|
||||
const (
|
||||
AccessLogFilePath = "log/access"
|
||||
AccessLogFileExtension = ".txt"
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package config
|
||||
|
||||
// Constants for pagination.
|
||||
// TODO: Perform navigation configuration at runtime
|
||||
// Future hosts shouldn't have to rebuild the binary to update a setting
|
||||
|
||||
const (
|
||||
TorrentsPerPage = 50
|
||||
TorrentsPerPage = 50
|
||||
)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package config
|
||||
|
||||
// Constants for ordering models.
|
||||
// TODO: Perform sorting configuration at runtime
|
||||
// Future hosts shouldn't have to rebuild the binary to update a setting
|
||||
|
||||
const (
|
||||
TorrentOrder = "torrent_id"
|
||||
TorrentOrder = "torrent_id"
|
||||
TorrentSort = "DESC"
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package config
|
||||
|
||||
// remember to update the FAQ when updating these
|
||||
// TODO: Update FAQ template to use this variable
|
||||
|
||||
var Trackers = []string{
|
||||
"udp://tracker.coppersurfer.tk:6969",
|
||||
"udp://zer0day.to:1337/announce",
|
||||
|
|
|
@ -8,7 +8,5 @@ const (
|
|||
|
||||
// TODO: deprecate this and move all files to the same server
|
||||
TorrentCacheLink = "http://anicache.com/torrent/%s.torrent"
|
||||
|
||||
//disable uploads by default
|
||||
UploadsDisabled = 1
|
||||
UploadsDisabled = true
|
||||
)
|
||||
|
|
31
db/gorm.go
31
db/gorm.go
|
@ -5,36 +5,33 @@ import (
|
|||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"github.com/jinzhu/gorm"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||
// _ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||
)
|
||||
|
||||
var ORM *gorm.DB
|
||||
|
||||
// GormInit init gorm ORM.
|
||||
func GormInit(conf *config.Config) (*gorm.DB, error) {
|
||||
db, err := gorm.Open(conf.DBType, conf.DBParams)
|
||||
// db, err := gorm.Open("mysql", config.MysqlDSL())
|
||||
//db, err := gorm.Open("sqlite3", "/tmp/gorm.db")
|
||||
db, openErr := gorm.Open(conf.DBType, conf.DBParams)
|
||||
if openErr != nil {
|
||||
log.CheckError(openErr)
|
||||
return nil, openErr
|
||||
}
|
||||
|
||||
// Get database connection handle [*sql.DB](http://golang.org/pkg/database/sql/#DB)
|
||||
db.DB()
|
||||
|
||||
// Then you could invoke `*sql.DB`'s functions with it
|
||||
db.DB().Ping()
|
||||
connectionErr := db.DB().Ping()
|
||||
if connectionErr != nil {
|
||||
log.CheckError(connectionErr)
|
||||
return nil, connectionErr
|
||||
}
|
||||
db.DB().SetMaxIdleConns(10)
|
||||
db.DB().SetMaxOpenConns(100)
|
||||
|
||||
// Disable table name's pluralization
|
||||
// db.SingularTable(true)
|
||||
// TODO: Enable Gorm initialization for non-development builds
|
||||
if config.Environment == "DEVELOPMENT" {
|
||||
db.LogMode(true)
|
||||
db.AutoMigrate(&model.Torrents{}, &model.UserFollows{}, &model.User{}, &model.Comment{}, &model.OldComment{})
|
||||
// db.Model(&model.User{}).AddIndex("idx_user_token", "token")
|
||||
|
||||
db.AutoMigrate(&model.Torrent{}, &model.UserFollows{}, &model.User{}, &model.Comment{}, &model.OldComment{})
|
||||
}
|
||||
log.CheckError(err)
|
||||
|
||||
return db, err
|
||||
return db, nil
|
||||
}
|
||||
|
|
21
main.go
21
main.go
|
@ -48,17 +48,23 @@ func RunServer(conf *config.Config) {
|
|||
}
|
||||
|
||||
func main() {
|
||||
conf := config.NewConfig()
|
||||
process_flags := conf.BindFlags()
|
||||
conf := config.New()
|
||||
processFlags := conf.BindFlags()
|
||||
defaults := flag.Bool("print-defaults", false, "print the default configuration file on stdout")
|
||||
flag.Parse()
|
||||
if *defaults {
|
||||
stdout := bufio.NewWriter(os.Stdout)
|
||||
conf.Pretty(stdout)
|
||||
stdout.Flush()
|
||||
err := conf.Pretty(stdout)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
err = stdout.Flush()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
os.Exit(0)
|
||||
} else {
|
||||
err := process_flags()
|
||||
err := processFlags()
|
||||
if err != nil {
|
||||
log.CheckError(err)
|
||||
}
|
||||
|
@ -69,7 +75,10 @@ func main() {
|
|||
initI18N()
|
||||
go signals.Handle()
|
||||
if len(config.TorrentFileStorage) > 0 {
|
||||
os.MkdirAll(config.TorrentFileStorage, 0755)
|
||||
err := os.MkdirAll(config.TorrentFileStorage, 0700)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
RunServer(conf)
|
||||
}
|
||||
|
|
|
@ -5,27 +5,29 @@ import (
|
|||
)
|
||||
|
||||
type Comment struct {
|
||||
Id uint `gorm:"column:comment_id;primary_key"`
|
||||
TorrentId uint `gorm:"column:torrent_id"`
|
||||
UserId uint `gorm:"column:user_id"`
|
||||
ID uint `gorm:"column:comment_id;primary_key"`
|
||||
TorrentID uint `gorm:"column:torrent_id"`
|
||||
UserID uint `gorm:"column:user_id"`
|
||||
Content string `gorm:"column:content"`
|
||||
CreatedAt time.Time `gorm:"column:created_at"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at"`
|
||||
|
||||
Torrent *Torrents `gorm:"ForeignKey:torrent_id"`
|
||||
User *User `gorm:"ForeignKey:user_id"`
|
||||
Torrent *Torrent `gorm:"ForeignKey:torrent_id"`
|
||||
User *User `gorm:"ForeignKey:user_id"`
|
||||
}
|
||||
|
||||
type OldComment struct {
|
||||
TorrentId uint `gorm:"column:torrent_id"`
|
||||
TorrentID uint `gorm:"column:torrent_id"`
|
||||
Username string `gorm:"column:username"`
|
||||
Content string `gorm:"column:content"`
|
||||
Date time.Time `gorm:"column:date"`
|
||||
|
||||
Torrent *Torrents `gorm:"ForeignKey:torrent_id"`
|
||||
Torrent *Torrent `gorm:"ForeignKey:torrent_id"`
|
||||
}
|
||||
|
||||
func (c OldComment) TableName() string {
|
||||
// cba to rename this in the db
|
||||
// TODO: Update database schema to fix this hack
|
||||
// I find this odd considering how often the schema changes already
|
||||
return "comments_old"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package model
|
||||
|
||||
// Language is a language model.
|
||||
type Language struct {
|
||||
Id uint `json:"id"`
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
|
112
model/torrent.go
112
model/torrent.go
|
@ -5,6 +5,7 @@ import (
|
|||
"github.com/ewhal/nyaa/util"
|
||||
|
||||
"fmt"
|
||||
"html"
|
||||
"html/template"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -12,100 +13,101 @@ import (
|
|||
)
|
||||
|
||||
type Feed struct {
|
||||
Id int
|
||||
ID int
|
||||
Name string
|
||||
Hash string
|
||||
Magnet string
|
||||
Timestamp string
|
||||
}
|
||||
|
||||
type Torrents struct {
|
||||
Id uint `gorm:"column:torrent_id;primary_key"`
|
||||
Name string `gorm:"column:torrent_name"`
|
||||
Hash string `gorm:"column:torrent_hash"`
|
||||
Category int `gorm:"column:category"`
|
||||
Sub_Category int `gorm:"column:sub_category"`
|
||||
Status int `gorm:"column:status"`
|
||||
Date time.Time `gorm:"column:date"`
|
||||
UploaderId uint `gorm:"column:uploader"`
|
||||
Downloads int `gorm:"column:downloads"`
|
||||
Stardom int `gorm:"column:stardom"`
|
||||
Filesize int64 `gorm:"column:filesize"`
|
||||
Description string `gorm:"column:description"`
|
||||
WebsiteLink string `gorm:"column:website_link"`
|
||||
type Torrent struct {
|
||||
ID uint `gorm:"column:torrent_id;primary_key"`
|
||||
Name string `gorm:"column:torrent_name"`
|
||||
Hash string `gorm:"column:torrent_hash"`
|
||||
Category int `gorm:"column:category"`
|
||||
SubCategory int `gorm:"column:sub_category"`
|
||||
Status int `gorm:"column:status"`
|
||||
Date time.Time `gorm:"column:date"`
|
||||
UploaderID uint `gorm:"column:uploader"`
|
||||
Downloads int `gorm:"column:downloads"`
|
||||
Stardom int `gorm:"column:stardom"`
|
||||
Filesize int64 `gorm:"column:filesize"`
|
||||
Description string `gorm:"column:description"`
|
||||
WebsiteLink string `gorm:"column:website_link"`
|
||||
|
||||
Uploader *User `gorm:"ForeignKey:UploaderId"`
|
||||
OldComments []OldComment `gorm:"ForeignKey:torrent_id"`
|
||||
Comments []Comment `gorm:"ForeignKey:torrent_id"`
|
||||
}
|
||||
|
||||
/* We need JSON Object instead because of Magnet URL that is not in the database but generated dynamically */
|
||||
/* We need a JSON object instead of a Gorm structure because magnet URLs are
|
||||
not in the database and have to be generated dynamically */
|
||||
|
||||
type ApiResultJson struct {
|
||||
Torrents []TorrentsJson `json:"torrents"`
|
||||
QueryRecordCount int `json:"queryRecordCount"`
|
||||
TotalRecordCount int `json:"totalRecordCount"`
|
||||
type ApiResultJSON struct {
|
||||
Torrents []TorrentJSON `json:"torrents"`
|
||||
QueryRecordCount int `json:"queryRecordCount"`
|
||||
TotalRecordCount int `json:"totalRecordCount"`
|
||||
}
|
||||
|
||||
type CommentsJson struct {
|
||||
type CommentJSON struct {
|
||||
Username string `json:"username"`
|
||||
Content template.HTML `json:"content"`
|
||||
Date time.Time `json:"date"`
|
||||
}
|
||||
|
||||
type TorrentsJson struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status int `json:"status"`
|
||||
Hash string `json:"hash"`
|
||||
Date string `json:"date"`
|
||||
Filesize string `json:"filesize"`
|
||||
Description template.HTML `json:"description"`
|
||||
Comments []CommentsJson `json:"comments"`
|
||||
Sub_Category string `json:"sub_category"`
|
||||
Category string `json:"category"`
|
||||
Downloads int `json:"downloads"`
|
||||
UploaderId uint `json:"uploader_id"`
|
||||
UploaderName template.HTML `json:"uploader_name"`
|
||||
WebsiteLink template.URL `json:"website_link"`
|
||||
Magnet template.URL `json:"magnet"`
|
||||
TorrentLink template.URL `json:"torrent"`
|
||||
type TorrentJSON struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status int `json:"status"`
|
||||
Hash string `json:"hash"`
|
||||
Date string `json:"date"`
|
||||
Filesize string `json:"filesize"`
|
||||
Description template.HTML `json:"description"`
|
||||
Comments []CommentJSON `json:"comments"`
|
||||
SubCategory string `json:"sub_category"`
|
||||
Category string `json:"category"`
|
||||
Downloads int `json:"downloads"`
|
||||
UploaderID uint `json:"uploader_id"`
|
||||
UploaderName template.HTML `json:"uploader_name"`
|
||||
WebsiteLink template.URL `json:"website_link"`
|
||||
Magnet template.URL `json:"magnet"`
|
||||
TorrentLink template.URL `json:"torrent"`
|
||||
}
|
||||
|
||||
/* Model Conversion to Json */
|
||||
|
||||
func (t *Torrents) ToJson() TorrentsJson {
|
||||
// ToJSON converts a model.Torrent to its equivalent JSON structure
|
||||
func (t *Torrent) ToJSON() TorrentJSON {
|
||||
magnet := util.InfoHashToMagnet(strings.TrimSpace(t.Hash), t.Name, config.Trackers...)
|
||||
commentsJson := make([]CommentsJson, 0, len(t.OldComments)+len(t.Comments))
|
||||
commentsJSON := make([]CommentJSON, 0, len(t.OldComments)+len(t.Comments))
|
||||
for _, c := range t.OldComments {
|
||||
commentsJson = append(commentsJson, CommentsJson{Username: c.Username, Content: template.HTML(c.Content), Date: c.Date})
|
||||
escapedContent := template.HTML(html.EscapeString(c.Content))
|
||||
commentsJSON = append(commentsJSON, CommentJSON{Username: c.Username, Content: escapedContent, Date: c.Date})
|
||||
}
|
||||
for _, c := range t.Comments {
|
||||
commentsJson = append(commentsJson, CommentsJson{Username: c.User.Username, Content: util.MarkdownToHTML(c.Content), Date: c.CreatedAt})
|
||||
commentsJSON = append(commentsJSON, CommentJSON{Username: c.User.Username, Content: util.MarkdownToHTML(c.Content), Date: c.CreatedAt})
|
||||
}
|
||||
uploader := ""
|
||||
if t.Uploader != nil {
|
||||
uploader = t.Uploader.Username
|
||||
}
|
||||
torrentlink := ""
|
||||
if t.Id <= config.LastOldTorrentId && len(config.TorrentCacheLink) > 0 {
|
||||
if t.ID <= config.LastOldTorrentID && len(config.TorrentCacheLink) > 0 {
|
||||
torrentlink = fmt.Sprintf(config.TorrentCacheLink, t.Hash)
|
||||
} else if t.Id > config.LastOldTorrentId && len(config.TorrentStorageLink) > 0 {
|
||||
torrentlink = fmt.Sprintf(config.TorrentStorageLink, t.Hash)
|
||||
} else if t.ID > config.LastOldTorrentID && len(config.TorrentStorageLink) > 0 {
|
||||
torrentlink = fmt.Sprintf(config.TorrentStorageLink, t.Hash) // TODO: Fix as part of configuration changes
|
||||
}
|
||||
res := TorrentsJson{
|
||||
Id: strconv.FormatUint(uint64(t.Id), 10),
|
||||
res := TorrentJSON{
|
||||
ID: strconv.FormatUint(uint64(t.ID), 10),
|
||||
Name: t.Name,
|
||||
Status: t.Status,
|
||||
Hash: t.Hash,
|
||||
Date: t.Date.Format(time.RFC3339),
|
||||
Filesize: util.FormatFilesize2(t.Filesize),
|
||||
Description: util.MarkdownToHTML(t.Description),
|
||||
Comments: commentsJson,
|
||||
Sub_Category: strconv.Itoa(t.Sub_Category),
|
||||
Comments: commentsJSON,
|
||||
SubCategory: strconv.Itoa(t.SubCategory),
|
||||
Category: strconv.Itoa(t.Category),
|
||||
Downloads: t.Downloads,
|
||||
UploaderId: t.UploaderId,
|
||||
UploaderID: t.UploaderID,
|
||||
UploaderName: util.SafeText(uploader),
|
||||
WebsiteLink: util.Safe(t.WebsiteLink),
|
||||
Magnet: util.Safe(magnet),
|
||||
|
@ -117,10 +119,10 @@ func (t *Torrents) ToJson() TorrentsJson {
|
|||
/* Complete the functions when necessary... */
|
||||
|
||||
// Map Torrents to TorrentsToJSON without reallocations
|
||||
func TorrentsToJSON(t []Torrents) []TorrentsJson {
|
||||
json := make([]TorrentsJson, len(t))
|
||||
func TorrentsToJSON(t []Torrent) []TorrentJSON { // TODO: Convert to singular version
|
||||
json := make([]TorrentJSON, len(t))
|
||||
for i := range t {
|
||||
json[i] = t[i].ToJson()
|
||||
json[i] = t[i].ToJSON()
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
)
|
||||
|
||||
type User struct {
|
||||
Id uint `gorm:"column:user_id;primary_key"`
|
||||
ID uint `gorm:"column:user_id;primary_key"`
|
||||
Username string `gorm:"column:username"`
|
||||
Password string `gorm:"column:password"`
|
||||
Email string `gorm:"column:email"`
|
||||
|
@ -17,17 +17,17 @@ type User struct {
|
|||
Language string `gorm:"column:language"`
|
||||
|
||||
// TODO: move this to PublicUser
|
||||
LikingCount int `json:"likingCount" gorm:"-"`
|
||||
LikedCount int `json:"likedCount" gorm:"-"`
|
||||
Likings []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"`
|
||||
Liked []User // Don't work `gorm:"foreignkey:follower_id;associationforeignkey:user_id;many2many:user_follows"`
|
||||
LikingCount int `json:"likingCount" gorm:"-"`
|
||||
LikedCount int `json:"likedCount" gorm:"-"`
|
||||
Likings []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"`
|
||||
Liked []User // Don't work `gorm:"foreignkey:follower_id;associationforeignkey:user_id;many2many:user_follows"`
|
||||
|
||||
Md5 string `json:"md5"` // Used for gravatar
|
||||
Torrents []Torrents `gorm:"ForeignKey:UploaderId"`
|
||||
MD5 string `json:"md5"` // Hash of email address, used for Gravatar
|
||||
Torrents []Torrent `gorm:"ForeignKey:UploaderId"`
|
||||
}
|
||||
|
||||
type PublicUser struct {
|
||||
User *User
|
||||
User *User
|
||||
}
|
||||
|
||||
// different users following eachother
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"fmt"
|
||||
"html"
|
||||
"net/http"
|
||||
//"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
@ -15,6 +14,7 @@ import (
|
|||
"github.com/ewhal/nyaa/service/api"
|
||||
"github.com/ewhal/nyaa/service/torrent"
|
||||
"github.com/ewhal/nyaa/util"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
|
@ -40,26 +40,32 @@ func ApiHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
whereParams = req.ToParams()
|
||||
} else {
|
||||
var errConv error
|
||||
req.MaxPerPage, errConv = strconv.Atoi(r.URL.Query().Get("max"))
|
||||
if errConv != nil || req.MaxPerPage == 0 {
|
||||
req.MaxPerPage = 50 // default Value maxPerPage
|
||||
var err error
|
||||
maxString := r.URL.Query().Get("max")
|
||||
if maxString != "" {
|
||||
req.MaxPerPage, err = strconv.Atoi(maxString)
|
||||
if !log.CheckError(err) {
|
||||
req.MaxPerPage = 50 // default Value maxPerPage
|
||||
}
|
||||
}
|
||||
|
||||
req.Page, _ = strconv.Atoi(html.EscapeString(page))
|
||||
if req.Page == 0 {
|
||||
req.Page = 1
|
||||
req.Page = 1
|
||||
if page != "" {
|
||||
req.Page, err = strconv.Atoi(html.EscapeString(page))
|
||||
if !log.CheckError(err) {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nbTorrents := 0
|
||||
torrents, nbTorrents, err := torrentService.GetTorrents(whereParams, req.MaxPerPage, req.MaxPerPage*(req.Page-1))
|
||||
if err != nil {
|
||||
util.SendError(w, err, 400)
|
||||
return
|
||||
}
|
||||
|
||||
b := model.ApiResultJson{
|
||||
b := model.ApiResultJSON{
|
||||
Torrents: model.TorrentsToJSON(torrents),
|
||||
}
|
||||
b.QueryRecordCount = req.MaxPerPage
|
||||
|
@ -73,13 +79,11 @@ func ApiHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func ApiViewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
|
||||
torrent, err := torrentService.GetTorrentById(id)
|
||||
b := torrent.ToJson()
|
||||
|
||||
b := torrent.ToJSON()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
err = json.NewEncoder(w).Encode(b)
|
||||
|
||||
|
@ -90,7 +94,7 @@ func ApiViewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func ApiUploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if config.UploadsDisabled == 1 {
|
||||
if config.UploadsDisabled {
|
||||
http.Error(w, "Error uploads are disabled", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
@ -100,13 +104,16 @@ func ApiUploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||
token := r.Header.Get("Authorization")
|
||||
user := model.User{}
|
||||
db.ORM.Where("api_token = ?", token).First(&user) //i don't like this
|
||||
if user.Id == 0 {
|
||||
if user.ID == 0 {
|
||||
http.Error(w, apiService.ErrApiKey.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
defer r.Body.Close()
|
||||
|
||||
//verify token
|
||||
//token := r.Header.Get("Authorization")
|
||||
|
||||
upload := apiService.TorrentRequest{}
|
||||
d := json.NewDecoder(r.Body)
|
||||
if err := d.Decode(&upload); err != nil {
|
||||
|
@ -119,17 +126,17 @@ func ApiUploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
torrent := model.Torrents{
|
||||
Name: upload.Name,
|
||||
Category: upload.Category,
|
||||
Sub_Category: upload.SubCategory,
|
||||
Status: 1,
|
||||
Hash: upload.Hash,
|
||||
Date: time.Now(),
|
||||
Filesize: 0, //?
|
||||
Description: upload.Description,
|
||||
UploaderId: user.Id,
|
||||
Uploader: &user,
|
||||
torrent := model.Torrent{
|
||||
Name: upload.Name,
|
||||
Category: upload.Category,
|
||||
SubCategory: upload.SubCategory,
|
||||
Status: 1,
|
||||
Hash: upload.Hash,
|
||||
Date: time.Now(),
|
||||
Filesize: 0, //?
|
||||
Description: upload.Description,
|
||||
UploaderID: user.ID,
|
||||
Uploader: &user,
|
||||
}
|
||||
|
||||
db.ORM.Create(&torrent)
|
||||
|
@ -142,7 +149,7 @@ func ApiUploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func ApiUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if config.UploadsDisabled == 1 {
|
||||
if config.UploadsDisabled {
|
||||
http.Error(w, "Error uploads are disabled", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
@ -152,7 +159,7 @@ func ApiUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
|||
token := r.Header.Get("Authorization")
|
||||
user := model.User{}
|
||||
db.ORM.Where("api_token = ?", token).First(&user) //i don't like this
|
||||
if user.Id == 0 {
|
||||
if user.ID == 0 {
|
||||
http.Error(w, apiService.ErrApiKey.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
@ -166,14 +173,14 @@ func ApiUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
id := update.Id
|
||||
torrent := model.Torrents{}
|
||||
id := update.ID
|
||||
torrent := model.Torrent{}
|
||||
db.ORM.Where("torrent_id = ?", id).First(&torrent)
|
||||
if torrent.Id == 0 {
|
||||
if torrent.ID == 0 {
|
||||
http.Error(w, apiService.ErrTorrentId.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if torrent.UploaderId != 0 && torrent.UploaderId != user.Id { //&& user.Status != mod
|
||||
if torrent.UploaderID != 0 && torrent.UploaderID != user.ID { //&& user.Status != mod
|
||||
http.Error(w, apiService.ErrRights.Error(), http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"html"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/service/torrent"
|
||||
"github.com/ewhal/nyaa/util"
|
||||
"github.com/ewhal/nyaa/util/languages"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"github.com/gorilla/mux"
|
||||
"html"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func HomeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -18,19 +17,27 @@ func HomeHandler(w http.ResponseWriter, r *http.Request) {
|
|||
page := vars["page"]
|
||||
|
||||
// db params url
|
||||
maxPerPage, errConv := strconv.Atoi(r.URL.Query().Get("max"))
|
||||
if errConv != nil {
|
||||
maxPerPage = 50 // default Value maxPerPage
|
||||
var err error
|
||||
maxPerPage := 50
|
||||
maxString := r.URL.Query().Get("max")
|
||||
if maxString != "" {
|
||||
maxPerPage, err = strconv.Atoi(maxString)
|
||||
if !log.CheckError(err) {
|
||||
maxPerPage = 50 // default Value maxPerPage
|
||||
}
|
||||
}
|
||||
|
||||
nbTorrents := 0
|
||||
pagenum, _ := strconv.Atoi(html.EscapeString(page))
|
||||
if pagenum == 0 {
|
||||
pagenum = 1
|
||||
pagenum := 1
|
||||
if page != "" {
|
||||
pagenum, err = strconv.Atoi(html.EscapeString(page))
|
||||
if !log.CheckError(err) {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
torrents, nbTorrents, err := torrentService.GetAllTorrents(maxPerPage, maxPerPage*(pagenum-1))
|
||||
if err != nil {
|
||||
if !log.CheckError(err) {
|
||||
util.SendError(w, err, 400)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ func init() {
|
|||
gzipAPIUploadHandler := handlers.CompressHandler(http.HandlerFunc(ApiUploadHandler))
|
||||
gzipAPIUpdateHandler := handlers.CompressHandler(http.HandlerFunc(ApiUpdateHandler))
|
||||
gzipFaqHandler := handlers.CompressHandler(http.HandlerFunc(FaqHandler))
|
||||
gzipRssHandler := handlers.CompressHandler(http.HandlerFunc(RssHandler))
|
||||
gzipRSSHandler := handlers.CompressHandler(http.HandlerFunc(RSSHandler))
|
||||
gzipViewHandler := handlers.CompressHandler(http.HandlerFunc(ViewHandler))
|
||||
gzipUploadHandler := handlers.CompressHandler(http.HandlerFunc(UploadHandler))
|
||||
gzipUserRegisterFormHandler := handlers.CompressHandler(http.HandlerFunc(UserRegisterFormHandler))
|
||||
|
@ -55,7 +55,7 @@ func init() {
|
|||
Router.Handle("/api/upload", gzipAPIUploadHandler).Methods("POST")
|
||||
Router.Handle("/api/update", gzipAPIUpdateHandler).Methods("PUT")
|
||||
Router.Handle("/faq", gzipFaqHandler).Name("faq")
|
||||
Router.Handle("/feed", gzipRssHandler).Name("feed")
|
||||
Router.Handle("/feed", gzipRSSHandler).Name("feed")
|
||||
Router.Handle("/view/{id}", gzipViewHandler).Methods("GET").Name("view_torrent")
|
||||
Router.HandleFunc("/view/{id}", PostCommentHandler).Methods("POST").Name("post_comment")
|
||||
Router.Handle("/upload", gzipUploadHandler).Name("upload")
|
||||
|
|
|
@ -1,53 +1,54 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ewhal/nyaa/config"
|
||||
"github.com/ewhal/nyaa/util"
|
||||
"github.com/ewhal/nyaa/util/search"
|
||||
"github.com/gorilla/feeds"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func RssHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func RSSHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, torrents, err := search.SearchByQueryNoCount(r, 1)
|
||||
if err != nil {
|
||||
util.SendError(w, err, 400)
|
||||
return
|
||||
}
|
||||
created_as_time := time.Now()
|
||||
createdAsTime := time.Now()
|
||||
|
||||
if len(torrents) > 0 {
|
||||
created_as_time = torrents[0].Date
|
||||
createdAsTime = torrents[0].Date
|
||||
}
|
||||
feed := &feeds.Feed{
|
||||
Title: "Nyaa Pantsu",
|
||||
Link: &feeds.Link{Href: "https://" + config.WebAddress + "/"},
|
||||
Created: created_as_time,
|
||||
Created: createdAsTime,
|
||||
}
|
||||
feed.Items = []*feeds.Item{}
|
||||
feed.Items = make([]*feeds.Item, len(torrents))
|
||||
|
||||
for i, _ := range torrents {
|
||||
torrent_json := torrents[i].ToJson()
|
||||
for i := range torrents {
|
||||
torrentJSON := torrents[i].ToJSON()
|
||||
feed.Items[i] = &feeds.Item{
|
||||
// need a torrent view first
|
||||
Id: "https://" + config.WebAddress + "/view/" + strconv.FormatUint(uint64(torrents[i].Id), 10),
|
||||
Id: "https://" + config.WebAddress + "/view/" + strconv.FormatUint(uint64(torrents[i].ID), 10),
|
||||
Title: torrents[i].Name,
|
||||
Link: &feeds.Link{Href: string(torrent_json.Magnet)},
|
||||
Link: &feeds.Link{Href: string(torrentJSON.Magnet)},
|
||||
Description: "",
|
||||
Created: torrents[0].Date,
|
||||
Updated: torrents[0].Date,
|
||||
}
|
||||
}
|
||||
|
||||
rss, err := feed.ToRss()
|
||||
if err == nil {
|
||||
w.Write([]byte(rss))
|
||||
} else {
|
||||
rss, rssErr := feed.ToRss()
|
||||
if rssErr != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
_, writeErr := w.Write([]byte(rss))
|
||||
if writeErr != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"html"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/util"
|
||||
"github.com/ewhal/nyaa/util/languages"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"github.com/ewhal/nyaa/util/search"
|
||||
"github.com/gorilla/mux"
|
||||
"html"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func SearchHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -17,12 +17,17 @@ func SearchHandler(w http.ResponseWriter, r *http.Request) {
|
|||
page := vars["page"]
|
||||
|
||||
// db params url
|
||||
pagenum, _ := strconv.Atoi(html.EscapeString(page))
|
||||
if pagenum == 0 {
|
||||
pagenum = 1
|
||||
var err error
|
||||
pagenum := 1
|
||||
if page != "" {
|
||||
pagenum, err = strconv.Atoi(html.EscapeString(page))
|
||||
if !log.CheckError(err) {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
search_param, torrents, nbTorrents, err := search.SearchByQuery(r, pagenum)
|
||||
searchParam, torrents, nbTorrents, err := search.SearchByQuery(r, pagenum)
|
||||
if err != nil {
|
||||
util.SendError(w, err, 400)
|
||||
return
|
||||
|
@ -30,11 +35,11 @@ func SearchHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
b := model.TorrentsToJSON(torrents)
|
||||
|
||||
navigationTorrents := Navigation{nbTorrents, int(search_param.Max), pagenum, "search_page"}
|
||||
navigationTorrents := Navigation{nbTorrents, int(searchParam.Max), pagenum, "search_page"}
|
||||
// Convert back to strings for now.
|
||||
searchForm := SearchForm{
|
||||
SearchParam: search_param,
|
||||
Category: search_param.Category.String(),
|
||||
SearchParam: searchParam,
|
||||
Category: searchParam.Category.String(),
|
||||
HideAdvancedSearch: false,
|
||||
}
|
||||
htv := HomeTemplateVariables{b, searchForm, navigationTorrents, GetUser(r), r.URL, mux.CurrentRoute(r)}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"github.com/ewhal/nyaa/service/user/permission"
|
||||
"github.com/nicksnyder/go-i18n/i18n"
|
||||
"html/template"
|
||||
"log"
|
||||
"math"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"github.com/nicksnyder/go-i18n/i18n"
|
||||
"github.com/ewhal/nyaa/service/user/permission"
|
||||
)
|
||||
)
|
||||
|
||||
var FuncMap = template.FuncMap{
|
||||
"min": math.Min,
|
||||
|
@ -22,7 +22,7 @@ var FuncMap = template.FuncMap{
|
|||
"genRouteWithQuery": func(name string, currentUrl *url.URL, params ...string) template.HTML {
|
||||
url, err := Router.Get(name).URL(params...)
|
||||
if err == nil {
|
||||
return template.HTML(url.String()+ "?" + currentUrl.RawQuery)
|
||||
return template.HTML(template.HTMLEscapeString(url.String() + "?" + currentUrl.RawQuery)) // TODO: Review application of character escaping
|
||||
}
|
||||
return "error"
|
||||
},
|
||||
|
@ -38,7 +38,7 @@ var FuncMap = template.FuncMap{
|
|||
if nav.CurrentPage > pagesSelectable/2 {
|
||||
startValue = (int(math.Min((float64(nav.CurrentPage)+math.Floor(float64(pagesSelectable)/2)), maxPages)) - pagesSelectable + 1)
|
||||
}
|
||||
endValue := (startValue + pagesSelectable -1)
|
||||
endValue := (startValue + pagesSelectable - 1)
|
||||
if endValue > int(maxPages) {
|
||||
endValue = int(maxPages)
|
||||
}
|
||||
|
@ -60,12 +60,12 @@ var FuncMap = template.FuncMap{
|
|||
return template.HTML(ret)
|
||||
},
|
||||
"T": i18n.IdentityTfunc,
|
||||
"getAvatar": func (hash string, size int) string {
|
||||
return "https://www.gravatar.com/avatar/"+hash+"?s="+strconv.Itoa(size)
|
||||
"getAvatar": func(hash string, size int) string {
|
||||
return "https://www.gravatar.com/avatar/" + hash + "?s=" + strconv.Itoa(size)
|
||||
},
|
||||
"CurrentOrAdmin": userPermission.CurrentOrAdmin,
|
||||
"CurrentOrAdmin": userPermission.CurrentOrAdmin,
|
||||
"CurrentUserIdentical": userPermission.CurrentUserIdentical,
|
||||
"HasAdmin": userPermission.HasAdmin,
|
||||
"GetRole": userPermission.GetRole,
|
||||
"IsFollower": userPermission.IsFollower,
|
||||
"HasAdmin": userPermission.HasAdmin,
|
||||
"GetRole": userPermission.GetRole,
|
||||
"IsFollower": userPermission.IsFollower,
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ type NotFoundTemplateVariables struct {
|
|||
}
|
||||
|
||||
type ViewTemplateVariables struct {
|
||||
Torrent model.TorrentsJson
|
||||
Torrent model.TorrentJSON
|
||||
Captcha captcha.Captcha
|
||||
Search SearchForm
|
||||
Navigation Navigation
|
||||
|
@ -55,15 +55,15 @@ type UserRegisterTemplateVariables struct {
|
|||
}
|
||||
|
||||
type UserProfileEditVariables struct {
|
||||
UserProfile *model.User
|
||||
UserForm userForms.UserForm
|
||||
FormErrors map[string][]string
|
||||
FormInfos map[string][]string
|
||||
Search SearchForm
|
||||
Navigation Navigation
|
||||
User *model.User
|
||||
URL *url.URL // For parsing Url in templates
|
||||
Route *mux.Route // For getting current route in templates
|
||||
UserProfile *model.User
|
||||
UserForm userForms.UserForm
|
||||
FormErrors map[string][]string
|
||||
FormInfos map[string][]string
|
||||
Search SearchForm
|
||||
Navigation Navigation
|
||||
User *model.User
|
||||
URL *url.URL // For parsing Url in templates
|
||||
Route *mux.Route // For getting current route in templates
|
||||
}
|
||||
|
||||
type UserVerifyTemplateVariables struct {
|
||||
|
@ -96,7 +96,7 @@ type UserProfileVariables struct {
|
|||
}
|
||||
|
||||
type HomeTemplateVariables struct {
|
||||
ListTorrents []model.TorrentsJson
|
||||
ListTorrents []model.TorrentJSON
|
||||
Search SearchForm
|
||||
Navigation Navigation
|
||||
User *model.User
|
||||
|
|
|
@ -31,8 +31,8 @@ type UploadForm struct {
|
|||
captcha.Captcha
|
||||
|
||||
Infohash string
|
||||
CategoryId int
|
||||
SubCategoryId int
|
||||
CategoryID int
|
||||
SubCategoryID int
|
||||
Filesize int64
|
||||
Filepath string
|
||||
}
|
||||
|
@ -86,11 +86,11 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
f.Captcha = captcha.Extract(r)
|
||||
|
||||
if !captcha.Authenticate(f.Captcha) {
|
||||
// TODO: Prettier passing of mistyoed captcha errors
|
||||
// TODO: Prettier passing of mistyped Captcha errors
|
||||
return errors.New(captcha.ErrInvalidCaptcha.Error())
|
||||
}
|
||||
|
||||
// trim whitespaces
|
||||
// trim whitespace
|
||||
f.Name = util.TrimWhitespaces(f.Name)
|
||||
f.Description = p.Sanitize(util.TrimWhitespaces(f.Description))
|
||||
f.Magnet = util.TrimWhitespaces(f.Magnet)
|
||||
|
@ -98,17 +98,17 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
catsSplit := strings.Split(f.Category, "_")
|
||||
// need this to prevent out of index panics
|
||||
if len(catsSplit) == 2 {
|
||||
CatId, err := strconv.Atoi(catsSplit[0])
|
||||
CatID, err := strconv.Atoi(catsSplit[0])
|
||||
if err != nil {
|
||||
return ErrInvalidTorrentCategory
|
||||
}
|
||||
SubCatId, err := strconv.Atoi(catsSplit[1])
|
||||
SubCatID, err := strconv.Atoi(catsSplit[1])
|
||||
if err != nil {
|
||||
return ErrInvalidTorrentCategory
|
||||
}
|
||||
|
||||
f.CategoryId = CatId
|
||||
f.SubCategoryId = SubCatId
|
||||
f.CategoryID = CatID
|
||||
f.SubCategoryID = SubCatID
|
||||
} else {
|
||||
return ErrInvalidTorrentCategory
|
||||
}
|
||||
|
@ -119,7 +119,10 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
var torrent metainfo.TorrentFile
|
||||
|
||||
// decode torrent
|
||||
tfile.Seek(0, io.SeekStart)
|
||||
_, seekErr := tfile.Seek(0, io.SeekStart)
|
||||
if seekErr != nil {
|
||||
return seekErr
|
||||
}
|
||||
err = bencode.NewDecoder(tfile).Decode(&torrent)
|
||||
if err != nil {
|
||||
return metainfo.ErrInvalidTorrentFile
|
||||
|
@ -143,7 +146,10 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
if len(f.Magnet) != 0 {
|
||||
return ErrTorrentPlusMagnet
|
||||
}
|
||||
binInfohash := torrent.Infohash()
|
||||
binInfohash, err := torrent.Infohash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Infohash = strings.ToUpper(hex.EncodeToString(binInfohash[:]))
|
||||
f.Magnet = util.InfoHashToMagnet(f.Infohash, f.Name, trackers...)
|
||||
|
||||
|
@ -151,11 +157,11 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
f.Filesize = int64(torrent.TotalSize())
|
||||
} else {
|
||||
// No torrent file provided
|
||||
magnetUrl, parseErr := url.Parse(f.Magnet)
|
||||
magnetURL, parseErr := url.Parse(f.Magnet)
|
||||
if parseErr != nil {
|
||||
return metainfo.ErrInvalidTorrentFile
|
||||
}
|
||||
exactTopic := magnetUrl.Query().Get("xt")
|
||||
exactTopic := magnetURL.Query().Get("xt")
|
||||
if !strings.HasPrefix(exactTopic, "urn:btih:") {
|
||||
return metainfo.ErrInvalidTorrentFile
|
||||
}
|
||||
|
@ -174,10 +180,6 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
return ErrInvalidTorrentName
|
||||
}
|
||||
|
||||
//if len(f.Description) == 0 {
|
||||
// return ErrInvalidTorrentDescription
|
||||
//}
|
||||
|
||||
// after data has been checked & extracted, write it to disk
|
||||
if len(config.TorrentFileStorage) > 0 {
|
||||
err := WriteTorrentToDisk(tfile, f.Infohash+".torrent", &f.Filepath)
|
||||
|
@ -192,7 +194,10 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
}
|
||||
|
||||
func WriteTorrentToDisk(file multipart.File, name string, fullpath *string) error {
|
||||
file.Seek(0, io.SeekStart)
|
||||
_, seekErr := file.Seek(0, io.SeekStart)
|
||||
if seekErr != nil {
|
||||
return seekErr
|
||||
}
|
||||
b, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -201,29 +206,30 @@ func WriteTorrentToDisk(file multipart.File, name string, fullpath *string) erro
|
|||
return ioutil.WriteFile(*fullpath, b, 0644)
|
||||
}
|
||||
|
||||
var dead_trackers = []string{ // substring matches!
|
||||
"://open.nyaatorrents.info:6544",
|
||||
"://tracker.openbittorrent.com:80",
|
||||
"://tracker.publicbt.com:80",
|
||||
"://stats.anisource.net:2710",
|
||||
"://exodus.desync.com",
|
||||
"://open.demonii.com:1337",
|
||||
"://tracker.istole.it:80",
|
||||
"://tracker.ccc.de:80",
|
||||
"://bt2.careland.com.cn:6969",
|
||||
"://announce.torrentsmd.com:8080"}
|
||||
|
||||
func CheckTrackers(trackers []string) bool {
|
||||
// TODO: move to runtime configuration
|
||||
var deadTrackers = []string{ // substring matches!
|
||||
"://open.nyaatorrents.info:6544",
|
||||
"://tracker.openbittorrent.com:80",
|
||||
"://tracker.publicbt.com:80",
|
||||
"://stats.anisource.net:2710",
|
||||
"://exodus.desync.com",
|
||||
"://open.demonii.com:1337",
|
||||
"://tracker.istole.it:80",
|
||||
"://tracker.ccc.de:80",
|
||||
"://bt2.careland.com.cn:6969",
|
||||
"://announce.torrentsmd.com:8080"}
|
||||
|
||||
var numGood int
|
||||
for _, t := range trackers {
|
||||
var good bool = true
|
||||
for _, check := range dead_trackers {
|
||||
good := true
|
||||
for _, check := range deadTrackers {
|
||||
if strings.Contains(t, check) {
|
||||
good = false
|
||||
}
|
||||
}
|
||||
if good {
|
||||
numGood += 1
|
||||
numGood++
|
||||
}
|
||||
}
|
||||
return numGood > 0
|
||||
|
|
|
@ -11,59 +11,58 @@ import (
|
|||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/service/captcha"
|
||||
"github.com/ewhal/nyaa/service/user"
|
||||
"github.com/ewhal/nyaa/util"
|
||||
"github.com/ewhal/nyaa/util/languages"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if config.UploadsDisabled == 1 {
|
||||
if config.UploadsDisabled {
|
||||
http.Error(w, "Error uploads are disabled", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
var err error
|
||||
var uploadForm UploadForm
|
||||
if r.Method == "POST" {
|
||||
defer r.Body.Close()
|
||||
// validation is done in ExtractInfo()
|
||||
err = uploadForm.ExtractInfo(r)
|
||||
if err == nil {
|
||||
user, _, err := userService.RetrieveCurrentUser(r)
|
||||
if err != nil {
|
||||
fmt.Printf("error %+v\n", err)
|
||||
}
|
||||
//add to db and redirect depending on result
|
||||
torrent := model.Torrents{
|
||||
Name: uploadForm.Name,
|
||||
Category: uploadForm.CategoryId,
|
||||
Sub_Category: uploadForm.SubCategoryId,
|
||||
Status: 1,
|
||||
Hash: uploadForm.Infohash,
|
||||
Date: time.Now(),
|
||||
Filesize: uploadForm.Filesize, // FIXME: should set to NULL instead of 0
|
||||
Description: uploadForm.Description,
|
||||
UploaderId: user.Id}
|
||||
err = db.ORM.Create(&torrent).Error
|
||||
if err != nil {
|
||||
util.SendError(w, err, 500)
|
||||
return
|
||||
}
|
||||
fmt.Printf("%+v\n", torrent)
|
||||
url, err := Router.Get("view_torrent").URL("id", strconv.FormatUint(uint64(torrent.Id), 10))
|
||||
if err == nil {
|
||||
http.Redirect(w, r, url.String(), 302)
|
||||
}
|
||||
err := uploadForm.ExtractInfo(r)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
user, _, err := userService.RetrieveCurrentUser(r)
|
||||
if err != nil {
|
||||
fmt.Printf("error %+v\n", err)
|
||||
}
|
||||
//add to db and redirect depending on result
|
||||
torrent := model.Torrent{
|
||||
Name: uploadForm.Name,
|
||||
Category: uploadForm.CategoryID,
|
||||
SubCategory: uploadForm.SubCategoryID,
|
||||
Status: 1,
|
||||
Hash: uploadForm.Infohash,
|
||||
Date: time.Now(),
|
||||
Filesize: uploadForm.Filesize,
|
||||
Description: uploadForm.Description,
|
||||
UploaderID: user.ID}
|
||||
db.ORM.Create(&torrent)
|
||||
fmt.Printf("%+v\n", torrent)
|
||||
url, err := Router.Get("view_torrent").URL("id", strconv.FormatUint(uint64(torrent.ID), 10))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, url.String(), 302)
|
||||
} else if r.Method == "GET" {
|
||||
uploadForm.CaptchaID = captcha.GetID()
|
||||
htv := UploadTemplateVariables{uploadForm, NewSearchForm(), Navigation{}, GetUser(r), r.URL, mux.CurrentRoute(r)}
|
||||
languages.SetTranslationFromRequest(uploadTemplate, r, "en-us")
|
||||
err = uploadTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
err := uploadTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"net/http"
|
||||
"strconv"
|
||||
|
||||
|
||||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/service/captcha"
|
||||
"github.com/ewhal/nyaa/service/user"
|
||||
|
@ -16,13 +15,10 @@ import (
|
|||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
//var viewTemplate = template.Must(template.New("view").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/view.html"))
|
||||
//var viewTemplate = template.Must(template.New("view").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/view.html"))
|
||||
|
||||
// Getting View User Registration
|
||||
func UserRegisterFormHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, errorUser := userService.CurrentUser(r)
|
||||
if (errorUser != nil) {
|
||||
if errorUser != nil {
|
||||
b := form.RegistrationForm{}
|
||||
modelHelper.BindValueForm(&b, r)
|
||||
b.CaptchaID = captcha.GetID()
|
||||
|
@ -56,15 +52,15 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
userProfile, _, errorUser := userService.RetrieveUserForAdmin(id)
|
||||
if (errorUser == nil) {
|
||||
currentUser := GetUser(r)
|
||||
view := r.URL.Query()["edit"]
|
||||
follow := r.URL.Query()["followed"]
|
||||
unfollow := r.URL.Query()["unfollowed"]
|
||||
infosForm := form.NewInfos()
|
||||
if errorUser == nil {
|
||||
currentUser := GetUser(r)
|
||||
view := r.URL.Query()["edit"]
|
||||
follow := r.URL.Query()["followed"]
|
||||
unfollow := r.URL.Query()["unfollowed"]
|
||||
infosForm := form.NewInfos()
|
||||
deleteVar := r.URL.Query()["delete"]
|
||||
|
||||
deleteVar := r.URL.Query()["delete"]
|
||||
if ((view != nil)&&(userPermission.CurrentOrAdmin(currentUser, userProfile.Id))) {
|
||||
if (view != nil) && (userPermission.CurrentOrAdmin(currentUser, userProfile.ID)) {
|
||||
b := form.UserForm{}
|
||||
modelHelper.BindValueForm(&b, r)
|
||||
languages.SetTranslationFromRequest(viewProfileEditTemplate, r, "en-us")
|
||||
|
@ -74,10 +70,10 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
} else if ((deleteVar != nil)&&(userPermission.CurrentOrAdmin(currentUser, userProfile.Id))) {
|
||||
} else if (deleteVar != nil) && (userPermission.CurrentOrAdmin(currentUser, userProfile.ID)) {
|
||||
err := form.NewErrors()
|
||||
_, errUser := userService.DeleteUser(w, currentUser, id)
|
||||
if (errUser != nil) {
|
||||
if errUser != nil {
|
||||
err["errors"] = append(err["errors"], errUser.Error())
|
||||
}
|
||||
languages.SetTranslationFromRequest(viewUserDeleteTemplate, r, "en-us")
|
||||
|
@ -86,14 +82,14 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) {
|
|||
if errorTmpl != nil {
|
||||
http.Error(w, errorTmpl.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
T := languages.SetTranslationFromRequest(viewProfileTemplate, r, "en-us")
|
||||
if (follow != nil) {
|
||||
if follow != nil {
|
||||
infosForm["infos"] = append(infosForm["infos"], fmt.Sprintf(T("user_followed_msg"), userProfile.Username))
|
||||
}
|
||||
if (unfollow != nil) {
|
||||
if unfollow != nil {
|
||||
infosForm["infos"] = append(infosForm["infos"], fmt.Sprintf(T("user_unfollowed_msg"), userProfile.Username))
|
||||
}
|
||||
}
|
||||
htv := UserProfileVariables{&userProfile, infosForm, NewSearchForm(), Navigation{}, currentUser, r.URL, mux.CurrentRoute(r)}
|
||||
|
||||
err := viewProfileTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
|
@ -119,8 +115,8 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) {
|
|||
id := vars["id"]
|
||||
currentUser := GetUser(r)
|
||||
userProfile, _, errorUser := userService.RetrieveUserForAdmin(id)
|
||||
if (errorUser == nil) {
|
||||
if (userPermission.CurrentOrAdmin(currentUser, userProfile.Id)) {
|
||||
if errorUser == nil {
|
||||
if userPermission.CurrentOrAdmin(currentUser, userProfile.ID) {
|
||||
b := form.UserForm{}
|
||||
err := form.NewErrors()
|
||||
infos := form.NewInfos()
|
||||
|
@ -129,20 +125,20 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) {
|
|||
_, err = form.EmailValidation(r.PostFormValue("email"), err)
|
||||
}
|
||||
if len(r.PostFormValue("username")) > 0 {
|
||||
_, err = form.ValidateUsername(r.PostFormValue("username"), err)
|
||||
_, err = form.ValidateUsername(r.PostFormValue("username"), err)
|
||||
}
|
||||
if (len(err) == 0) {
|
||||
if len(err) == 0 {
|
||||
modelHelper.BindValueForm(&b, r)
|
||||
err = modelHelper.ValidateForm(&b, err)
|
||||
if (len(err) == 0) {
|
||||
if len(err) == 0 {
|
||||
userProfile, _, errorUser = userService.UpdateUser(w, &b, currentUser, id)
|
||||
if (errorUser != nil) {
|
||||
if errorUser != nil {
|
||||
err["errors"] = append(err["errors"], errorUser.Error())
|
||||
}
|
||||
if (len(err) == 0) {
|
||||
if len(err) == 0 {
|
||||
infos["infos"] = append(infos["infos"], T("profile_updated"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
htv := UserProfileEditVariables{&userProfile, b, err, infos, NewSearchForm(), Navigation{}, currentUser, r.URL, mux.CurrentRoute(r)}
|
||||
errorTmpl := viewProfileEditTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
|
@ -179,20 +175,20 @@ func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||
if !captcha.Authenticate(captcha.Extract(r)) {
|
||||
err["errors"] = append(err["errors"], "Wrong captcha!")
|
||||
}
|
||||
if (len(err) == 0) {
|
||||
if len(err) == 0 {
|
||||
if len(r.PostFormValue("email")) > 0 {
|
||||
_, err = form.EmailValidation(r.PostFormValue("email"), err)
|
||||
}
|
||||
_, err = form.ValidateUsername(r.PostFormValue("username"), err)
|
||||
if (len(err) == 0) {
|
||||
if len(err) == 0 {
|
||||
modelHelper.BindValueForm(&b, r)
|
||||
err = modelHelper.ValidateForm(&b, err)
|
||||
if (len(err) == 0) {
|
||||
if len(err) == 0 {
|
||||
_, errorUser := userService.CreateUser(w, r)
|
||||
if (errorUser != nil) {
|
||||
if errorUser != nil {
|
||||
err["errors"] = append(err["errors"], errorUser.Error())
|
||||
}
|
||||
if (len(err) == 0) {
|
||||
if len(err) == 0 {
|
||||
languages.SetTranslationFromRequest(viewRegisterSuccessTemplate, r, "en-us")
|
||||
u := model.User{
|
||||
Email: r.PostFormValue("email"), // indicate whether user had email set
|
||||
|
@ -202,11 +198,11 @@ func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||
if errorTmpl != nil {
|
||||
http.Error(w, errorTmpl.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (len(err) > 0) {
|
||||
if len(err) > 0 {
|
||||
b.CaptchaID = captcha.GetID()
|
||||
languages.SetTranslationFromRequest(viewRegisterTemplate, r, "en-us")
|
||||
htv := UserRegisterTemplateVariables{b, err, NewSearchForm(), Navigation{}, GetUser(r), r.URL, mux.CurrentRoute(r)}
|
||||
|
@ -222,7 +218,7 @@ func UserVerifyEmailHandler(w http.ResponseWriter, r *http.Request) {
|
|||
token := vars["token"]
|
||||
err := form.NewErrors()
|
||||
_, errEmail := userService.EmailVerification(token, w)
|
||||
if (errEmail != nil) {
|
||||
if errEmail != nil {
|
||||
err["errors"] = append(err["errors"], errEmail.Error())
|
||||
}
|
||||
languages.SetTranslationFromRequest(viewVerifySuccessTemplate, r, "en-us")
|
||||
|
@ -239,9 +235,9 @@ func UserLoginPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||
modelHelper.BindValueForm(&b, r)
|
||||
err := form.NewErrors()
|
||||
err = modelHelper.ValidateForm(&b, err)
|
||||
if (len(err) == 0) {
|
||||
if len(err) == 0 {
|
||||
_, errorUser := userService.CreateUserAuthentication(w, r)
|
||||
if (errorUser != nil) {
|
||||
if errorUser != nil {
|
||||
err["errors"] = append(err["errors"], errorUser.Error())
|
||||
languages.SetTranslationFromRequest(viewLoginTemplate, r, "en-us")
|
||||
htv := UserLoginFormVariables{b, err, NewSearchForm(), Navigation{}, GetUser(r), r.URL, mux.CurrentRoute(r)}
|
||||
|
@ -265,15 +261,14 @@ func UserLogoutHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Redirect(w, r, url.String(), http.StatusSeeOther)
|
||||
}
|
||||
|
||||
|
||||
func UserFollowHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var followAction string
|
||||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
currentUser := GetUser(r)
|
||||
user, _, errorUser := userService.RetrieveUserForAdmin(id)
|
||||
if (errorUser == nil) {
|
||||
if (!userPermission.IsFollower(&user, currentUser)) {
|
||||
if errorUser == nil {
|
||||
if !userPermission.IsFollower(&user, currentUser) {
|
||||
followAction = "followed"
|
||||
userService.SetFollow(&user, currentUser)
|
||||
} else {
|
||||
|
@ -281,6 +276,6 @@ func UserFollowHandler(w http.ResponseWriter, r *http.Request) {
|
|||
userService.RemoveFollow(&user, currentUser)
|
||||
}
|
||||
}
|
||||
url, _ := Router.Get("user_profile").URL("id", strconv.Itoa(int(user.Id)), "username", user.Username)
|
||||
url, _ := Router.Get("user_profile").URL("id", strconv.Itoa(int(user.ID)), "username", user.Username)
|
||||
http.Redirect(w, r, url.String()+"?"+followAction, http.StatusSeeOther)
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ func ViewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
NotFoundHandler(w, r)
|
||||
return
|
||||
}
|
||||
b := torrent.ToJson()
|
||||
b := torrent.ToJSON()
|
||||
htv := ViewTemplateVariables{b, captcha.Captcha{CaptchaID: captcha.GetID()}, NewSearchForm(), Navigation{}, GetUser(r), r.URL, mux.CurrentRoute(r)}
|
||||
|
||||
languages.SetTranslationFromRequest(viewTemplate, r, "en-us")
|
||||
|
@ -45,14 +45,14 @@ func PostCommentHandler(w http.ResponseWriter, r *http.Request) {
|
|||
currentUser := GetUser(r)
|
||||
content := p.Sanitize(r.FormValue("comment"))
|
||||
|
||||
idNum_, err := strconv.Atoi(id)
|
||||
var idNum uint = uint(idNum_)
|
||||
var userId uint = 0
|
||||
if currentUser.Id > 0 {
|
||||
userId = currentUser.Id
|
||||
idNum, err := strconv.Atoi(id)
|
||||
if currentUser.ID <= 0 {
|
||||
http.Error(w, "Invalid user ID", http.StatusInternalServerError)
|
||||
}
|
||||
comment := model.Comment{TorrentId: idNum, UserId: userId, Content: content, CreatedAt: time.Now()}
|
||||
err = db.ORM.Create(&comment).Error
|
||||
userID := currentUser.ID
|
||||
comment := model.Comment{TorrentID: uint(idNum), UserID: userID, Content: content, CreatedAt: time.Now()}
|
||||
|
||||
err = db.ORM.Create(&comment).Error
|
||||
if err != nil {
|
||||
util.SendError(w, err, 500)
|
||||
return
|
||||
|
|
|
@ -36,7 +36,7 @@ type TorrentRequest struct {
|
|||
}
|
||||
|
||||
type UpdateRequest struct {
|
||||
Id int `json:"id"`
|
||||
ID int `json:"id"`
|
||||
Update TorrentRequest `json:"update"`
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ func (r *TorrentRequest) ValidateUpdate() (err error, code int) {
|
|||
}
|
||||
|
||||
//rewrite with reflect ?
|
||||
func (r *UpdateRequest) UpdateTorrent(t *model.Torrents) {
|
||||
func (r *UpdateRequest) UpdateTorrent(t *model.Torrent) {
|
||||
if r.Update.Name != "" {
|
||||
t.Name = r.Update.Name
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ func (r *UpdateRequest) UpdateTorrent(t *model.Torrents) {
|
|||
t.Category = r.Update.Category
|
||||
}
|
||||
if r.Update.SubCategory != 0 {
|
||||
t.Sub_Category = r.Update.SubCategory
|
||||
t.SubCategory = r.Update.SubCategory
|
||||
}
|
||||
if r.Update.Description != "" {
|
||||
t.Description = r.Update.Description
|
||||
|
|
|
@ -19,12 +19,12 @@ func init() {
|
|||
captcha.SetCustomStore(captcha.NewMemoryStore(1<<10, lifetime))
|
||||
}
|
||||
|
||||
// Captcha is to be embedded into any form struct requiring a captcha
|
||||
// Captcha is to be embedded into any form struct requiring a Captcha
|
||||
type Captcha struct {
|
||||
CaptchaID, Solution string
|
||||
}
|
||||
|
||||
// GetID returns a new captcha id
|
||||
// GetID returns a new Captcha ID
|
||||
func GetID() string {
|
||||
return captcha.New()
|
||||
}
|
||||
|
@ -37,12 +37,12 @@ func Extract(r *http.Request) Captcha {
|
|||
}
|
||||
}
|
||||
|
||||
// ServeFiles serves captcha images and audio
|
||||
// ServeFiles serves Captcha images and audio
|
||||
func ServeFiles(w http.ResponseWriter, r *http.Request) {
|
||||
server.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// Authenticate check's if a captcha solution is valid
|
||||
// Authenticate check's if a Captcha solution is valid
|
||||
func Authenticate(req Captcha) bool {
|
||||
return captcha.VerifyString(req.CaptchaID, req.Solution)
|
||||
}
|
||||
|
|
|
@ -2,13 +2,12 @@ package torrentService
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ewhal/nyaa/config"
|
||||
"github.com/ewhal/nyaa/db"
|
||||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/util"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type WhereParams struct {
|
||||
|
@ -36,20 +35,20 @@ func GetFeeds() (result []model.Feed, err error) {
|
|||
|
||||
for rows.Next() {
|
||||
item := model.Feed{}
|
||||
err = rows.Scan(&item.Id, &item.Name, &item.Hash, &item.Timestamp)
|
||||
err = rows.Scan(&item.ID, &item.Name, &item.Hash, &item.Timestamp)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
magnet := util.InfoHashToMagnet(strings.TrimSpace(item.Hash), item.Name, config.Trackers...)
|
||||
item.Magnet = magnet
|
||||
// memory hog
|
||||
// TODO: memory hog
|
||||
result = append(result, item)
|
||||
}
|
||||
err = rows.Err()
|
||||
return
|
||||
}
|
||||
|
||||
func GetTorrentById(id string) (torrent model.Torrents, err error) {
|
||||
func GetTorrentById(id string) (torrent model.Torrent, err error) {
|
||||
id_int, err := strconv.Atoi(id)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -60,7 +59,7 @@ func GetTorrentById(id string) (torrent model.Torrents, err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
if id_int <= config.LastOldTorrentId {
|
||||
if id_int <= config.LastOldTorrentID {
|
||||
// only preload old comments if they could actually exist
|
||||
tmp = tmp.Preload("OldComments")
|
||||
}
|
||||
|
@ -71,10 +70,10 @@ func GetTorrentById(id string) (torrent model.Torrents, err error) {
|
|||
// GORM relly likes not doing its job correctly
|
||||
// (or maybe I'm just retarded)
|
||||
torrent.Uploader = new(model.User)
|
||||
db.ORM.Where("user_id = ?", torrent.UploaderId).Find(torrent.Uploader)
|
||||
db.ORM.Where("user_id = ?", torrent.UploaderID).Find(torrent.Uploader)
|
||||
for i := range torrent.Comments {
|
||||
torrent.Comments[i].User = new(model.User)
|
||||
err = db.ORM.Where("user_id = ?", torrent.Comments[i].UserId).Find(torrent.Comments[i].User).Error
|
||||
err = db.ORM.Where("user_id = ?", torrent.Comments[i].UserID).Find(torrent.Comments[i].User).Error
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -83,22 +82,22 @@ func GetTorrentById(id string) (torrent model.Torrents, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func GetTorrentsOrderByNoCount(parameters *WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrents, err error) {
|
||||
func GetTorrentsOrderByNoCount(parameters *WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, err error) {
|
||||
torrents, _, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, false)
|
||||
return
|
||||
}
|
||||
|
||||
func GetTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrents, count int, err error) {
|
||||
func GetTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, count int, err error) {
|
||||
torrents, count, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, true)
|
||||
return
|
||||
}
|
||||
|
||||
func getTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offset int, countAll bool) (
|
||||
torrents []model.Torrents, count int, err error,
|
||||
torrents []model.Torrent, count int, err error,
|
||||
) {
|
||||
var conditionArray []string
|
||||
if strings.HasPrefix(orderBy, "filesize") {
|
||||
// torrents w/ NULL filesize fuck up the sorting on postgres
|
||||
// torrents w/ NULL filesize fuck up the sorting on Postgres
|
||||
conditionArray = append(conditionArray, "filesize IS NOT NULL")
|
||||
}
|
||||
var params []interface{}
|
||||
|
@ -137,32 +136,28 @@ func getTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offs
|
|||
return
|
||||
}
|
||||
|
||||
/* Functions to simplify the get parameters of the main function
|
||||
*
|
||||
* Get Torrents with where parameters and limits, order by default
|
||||
*/
|
||||
func GetTorrents(parameters WhereParams, limit int, offset int) ([]model.Torrents, int, error) {
|
||||
// GetTorrents obtain a list of torrents matching 'parameters' from the
|
||||
// database. The list will be of length 'limit' and in default order.
|
||||
// GetTorrents returns the first records found. Later records may be retrieved
|
||||
// by providing a positive 'offset'
|
||||
func GetTorrents(parameters WhereParams, limit int, offset int) ([]model.Torrent, int, error) {
|
||||
return GetTorrentsOrderBy(¶meters, "", limit, offset)
|
||||
}
|
||||
|
||||
/* Get Torrents with where parameters but no limit and order by default (get all the torrents corresponding in the db)
|
||||
*/
|
||||
func GetTorrentsDB(parameters WhereParams) ([]model.Torrents, int, error) {
|
||||
// Get Torrents with where parameters but no limit and order by default (get all the torrents corresponding in the db)
|
||||
func GetTorrentsDB(parameters WhereParams) ([]model.Torrent, int, error) {
|
||||
return GetTorrentsOrderBy(¶meters, "", 0, 0)
|
||||
}
|
||||
|
||||
/* Function to get all torrents
|
||||
*/
|
||||
|
||||
func GetAllTorrentsOrderBy(orderBy string, limit int, offset int) ([]model.Torrents, int, error) {
|
||||
func GetAllTorrentsOrderBy(orderBy string, limit int, offset int) ([]model.Torrent, int, error) {
|
||||
return GetTorrentsOrderBy(nil, orderBy, limit, offset)
|
||||
}
|
||||
|
||||
func GetAllTorrents(limit int, offset int) ([]model.Torrents, int, error) {
|
||||
func GetAllTorrents(limit int, offset int) ([]model.Torrent, int, error) {
|
||||
return GetTorrentsOrderBy(nil, "", limit, offset)
|
||||
}
|
||||
|
||||
func GetAllTorrentsDB() ([]model.Torrents, int, error) {
|
||||
func GetAllTorrentsDB() ([]model.Torrent, int, error) {
|
||||
return GetTorrentsOrderBy(nil, "", 0, 0)
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,6 @@ package userService
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/ewhal/nyaa/db"
|
||||
"github.com/ewhal/nyaa/model"
|
||||
formStruct "github.com/ewhal/nyaa/service/user/form"
|
||||
|
@ -11,12 +9,14 @@ import (
|
|||
"github.com/ewhal/nyaa/util/modelHelper"
|
||||
"github.com/gorilla/securecookie"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
var cookieHandler = securecookie.New(
|
||||
securecookie.GenerateRandomKey(64),
|
||||
securecookie.GenerateRandomKey(32))
|
||||
|
||||
// TODO: Figure out what this is about before I delete it
|
||||
// // UserName get username from a cookie.
|
||||
// func UserName(c *gin.Context) (string, error) {
|
||||
// var userName string
|
||||
|
@ -47,7 +47,7 @@ func Token(r *http.Request) (string, error) {
|
|||
}
|
||||
token = cookieValue["token"]
|
||||
if len(token) == 0 {
|
||||
return token, errors.New("Token is empty.")
|
||||
return token, errors.New("token is empty")
|
||||
}
|
||||
return token, nil
|
||||
}
|
||||
|
@ -91,17 +91,17 @@ func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, er
|
|||
if isValidEmail {
|
||||
log.Debug("User entered valid email.")
|
||||
if db.ORM.Where("email = ?", email).First(&user).RecordNotFound() {
|
||||
return http.StatusNotFound, errors.New("User is not found.")
|
||||
return http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
} else {
|
||||
log.Debug("User entered username.")
|
||||
if db.ORM.Where("username = ?", email).First(&user).RecordNotFound() {
|
||||
return http.StatusNotFound, errors.New("User is not found.")
|
||||
return http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
}
|
||||
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(pass))
|
||||
if err != nil {
|
||||
return http.StatusUnauthorized, errors.New("Password incorrect.")
|
||||
return http.StatusUnauthorized, errors.New("password incorrect")
|
||||
}
|
||||
status, err := SetCookie(w, user.Token)
|
||||
if err != nil {
|
||||
|
@ -109,17 +109,13 @@ func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, er
|
|||
}
|
||||
w.Header().Set("X-Auth-Token", user.Token)
|
||||
return http.StatusOK, nil
|
||||
} else {
|
||||
return http.StatusNotFound, errors.New("User is not found.")
|
||||
}
|
||||
return http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
|
||||
// RegisterHanderFromForm sets cookie from a RegistrationForm.
|
||||
func RegisterHanderFromForm(w http.ResponseWriter, registrationForm formStruct.RegistrationForm) (int, error) {
|
||||
email := registrationForm.Email
|
||||
if email == "" {
|
||||
email = registrationForm.Username
|
||||
}
|
||||
pass := registrationForm.Password
|
||||
log.Debugf("RegisterHandler UserEmail : %s", email)
|
||||
log.Debugf("RegisterHandler UserPassword : %s", pass)
|
||||
|
@ -140,16 +136,16 @@ func CurrentUser(r *http.Request) (model.User, error) {
|
|||
var err error
|
||||
token = r.Header.Get("X-Auth-Token")
|
||||
if len(token) > 0 {
|
||||
log.Debug("header token exist.")
|
||||
log.Debug("header token exists")
|
||||
} else {
|
||||
token, err = Token(r)
|
||||
log.Debug("header token not exist.")
|
||||
log.Debug("header token does not exist")
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
}
|
||||
if db.ORM.Where("api_token = ?", token).First(&user).RecordNotFound() {
|
||||
return user, errors.New("User is not found.")
|
||||
return user, errors.New("user not found")
|
||||
}
|
||||
err = db.ORM.Model(&user).Error
|
||||
return user, err
|
||||
|
|
|
@ -15,11 +15,12 @@ func EmailValidation(email string, err map[string][]string) (bool, map[string][]
|
|||
if exp.MatchString(email) {
|
||||
return true, err
|
||||
}
|
||||
}
|
||||
}
|
||||
err["email"] = append(err["email"], "Email Address is not valid")
|
||||
return false, err
|
||||
}
|
||||
func ValidateUsername(username string, err map[string][]string) (bool, map[string][]string) {
|
||||
|
||||
func ValidateUsername(username string, err map[string][]string) (bool, map[string][]string) {
|
||||
exp, errorRegex := regexp.Compile(USERNAME_REGEX)
|
||||
if regexpCompiled := log.CheckError(errorRegex); regexpCompiled {
|
||||
if exp.MatchString(username) {
|
||||
|
@ -40,38 +41,36 @@ func NewInfos() map[string][]string {
|
|||
infos := make(map[string][]string)
|
||||
return infos
|
||||
}
|
||||
func IsAgreed(t_and_c string) bool {
|
||||
if t_and_c == "1" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
func IsAgreed(termsAndConditions string) bool { // TODO: Inline function
|
||||
return termsAndConditions == "1"
|
||||
}
|
||||
|
||||
// RegistrationForm is used when creating a user.
|
||||
type RegistrationForm struct {
|
||||
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
|
||||
Email string `form:"email" needed:"true"`
|
||||
Password string `form:"password" needed:"true" len_min:"6" len_max:"25" equalInput:"Confirm_Password"`
|
||||
Confirm_Password string `form:"password_confirmation" omit:"true" needed:"true"`
|
||||
CaptchaID string `form:"captchaID" omit:"true" needed:"true"`
|
||||
T_and_C bool `form:"t_and_c" omit:"true" needed:"true" equal:"true" hum_name:"Terms and Conditions"`
|
||||
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
|
||||
Email string `form:"email" needed:"true"`
|
||||
Password string `form:"password" needed:"true" len_min:"6" len_max:"25" equalInput:"ConfirmPassword"`
|
||||
ConfirmPassword string `form:"password_confirmation" omit:"true" needed:"true"`
|
||||
CaptchaID string `form:"captchaID" omit:"true" needed:"true"`
|
||||
TermsAndConditions bool `form:"t_and_c" omit:"true" needed:"true" equal:"true" hum_name:"Terms and Conditions"`
|
||||
}
|
||||
|
||||
// LoginForm is used when a user logs in.
|
||||
type LoginForm struct {
|
||||
Username string `form:"username" needed="true"`
|
||||
Password string `form:"password" needed="true"`
|
||||
Username string `form:"username" needed:"true"`
|
||||
Password string `form:"password" needed:"true"`
|
||||
}
|
||||
|
||||
// UserForm is used when updating a user.
|
||||
type UserForm struct {
|
||||
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
|
||||
Email string `form:"email" needed:"true"`
|
||||
Language string `form:"language" default:"en-us"`
|
||||
CurrentPassword string `form:"password" len_min:"6" len_max:"25" omit:"true"`
|
||||
Password string `form:"password" len_min:"6" len_max:"25" equalInput:"Confirm_Password"`
|
||||
Confirm_Password string `form:"password_confirmation" omit:"true"`
|
||||
Status int `form:"language" default:"0"`
|
||||
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
|
||||
Email string `form:"email" needed:"true"`
|
||||
Language string `form:"language" default:"en-us"`
|
||||
CurrentPassword string `form:"password" len_min:"6" len_max:"25" omit:"true"`
|
||||
Password string `form:"password" len_min:"6" len_max:"25" equalInput:"ConfirmPassword"`
|
||||
ConfirmPassword string `form:"password_confirmation" omit:"true"`
|
||||
Status int `form:"language" default:"0"`
|
||||
}
|
||||
|
||||
// PasswordForm is used when updating a user password.
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package userPermission
|
||||
|
||||
import (
|
||||
"github.com/ewhal/nyaa/db"
|
||||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"github.com/ewhal/nyaa/db"
|
||||
)
|
||||
|
||||
// HasAdmin checks that user has an admin permission.
|
||||
|
@ -12,29 +12,26 @@ func HasAdmin(user *model.User) bool {
|
|||
}
|
||||
|
||||
// CurrentOrAdmin check that user has admin permission or user is the current user.
|
||||
func CurrentOrAdmin(user *model.User, userId uint) bool {
|
||||
log.Debugf("user.Id == userId %d %d %s", user.Id, userId, user.Id == userId)
|
||||
return (HasAdmin(user) || user.Id == userId)
|
||||
func CurrentOrAdmin(user *model.User, userID uint) bool {
|
||||
log.Debugf("user.ID == userID %d %d %s", user.ID, userID, user.ID == userID)
|
||||
return (HasAdmin(user) || user.ID == userID)
|
||||
}
|
||||
|
||||
// CurrentUserIdentical check that userId is same as current user's Id.
|
||||
func CurrentUserIdentical(user *model.User, userId uint) (bool) {
|
||||
if user.Id != userId {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
// CurrentUserIdentical check that userID is same as current user's ID.
|
||||
// TODO: Inline this
|
||||
func CurrentUserIdentical(user *model.User, userID uint) bool {
|
||||
return user.ID != userID
|
||||
}
|
||||
|
||||
func GetRole(user *model.User) string {
|
||||
switch user.Status {
|
||||
case -1 :
|
||||
case -1:
|
||||
return "Banned"
|
||||
case 0 :
|
||||
case 0:
|
||||
return "Member"
|
||||
case 1 :
|
||||
case 1:
|
||||
return "Trusted Member"
|
||||
case 2 :
|
||||
case 2:
|
||||
return "Moderator"
|
||||
}
|
||||
return "Member"
|
||||
|
@ -42,9 +39,9 @@ func GetRole(user *model.User) string {
|
|||
|
||||
func IsFollower(user *model.User, currentUser *model.User) bool {
|
||||
var likingUserCount int
|
||||
db.ORM.Model(&model.UserFollows{}).Where("user_id = ? and following = ?", user.Id, currentUser.Id).Count(&likingUserCount)
|
||||
db.ORM.Model(&model.UserFollows{}).Where("user_id = ? and following = ?", user.ID, currentUser.ID).Count(&likingUserCount)
|
||||
if likingUserCount != 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,6 @@ import (
|
|||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
var userFields []string = []string{"name", "email", "createdAt", "updatedAt"}
|
||||
|
||||
// SuggestUsername suggest user's name if user's name already occupied.
|
||||
func SuggestUsername(username string) string {
|
||||
var count int
|
||||
|
@ -29,17 +27,16 @@ func SuggestUsername(username string) string {
|
|||
log.Debugf("count Before : %d", count)
|
||||
if count == 0 {
|
||||
return username
|
||||
} else {
|
||||
var postfix int
|
||||
for {
|
||||
usernameCandidate = username + strconv.Itoa(postfix)
|
||||
log.Debugf("usernameCandidate: %s\n", usernameCandidate)
|
||||
db.ORM.Model(model.User{}).Where(&model.User{Username: usernameCandidate}).Count(&count)
|
||||
log.Debugf("count after : %d\n", count)
|
||||
postfix = postfix + 1
|
||||
if count == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
var postfix int
|
||||
for {
|
||||
usernameCandidate = username + strconv.Itoa(postfix)
|
||||
log.Debugf("usernameCandidate: %s\n", usernameCandidate)
|
||||
db.ORM.Model(model.User{}).Where(&model.User{Username: usernameCandidate}).Count(&count)
|
||||
log.Debugf("count after : %d\n", count)
|
||||
postfix = postfix + 1
|
||||
if count == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
return usernameCandidate
|
||||
|
@ -63,20 +60,24 @@ func CreateUserFromForm(registrationForm formStruct.RegistrationForm) (model.Use
|
|||
log.Debugf("registrationForm %+v\n", registrationForm)
|
||||
modelHelper.AssignValue(&user, ®istrationForm)
|
||||
if user.Email == "" {
|
||||
user.Md5 = ""
|
||||
user.MD5 = ""
|
||||
} else {
|
||||
user.Md5 = crypto.GenerateMD5Hash(user.Email)
|
||||
var err error
|
||||
user.MD5, err = crypto.GenerateMD5Hash(user.Email)
|
||||
if err != nil {
|
||||
return user, err
|
||||
}
|
||||
}
|
||||
token, err := crypto.GenerateRandomToken32()
|
||||
if err != nil {
|
||||
return user, errors.New("Token not generated.")
|
||||
return user, errors.New("token not generated")
|
||||
}
|
||||
|
||||
user.Token = token
|
||||
user.TokenExpiration = timeHelper.FewDaysLater(config.AuthTokenExpirationDay)
|
||||
log.Debugf("user %+v\n", user)
|
||||
if db.ORM.Create(&user).Error != nil {
|
||||
return user, errors.New("User is not created.")
|
||||
return user, errors.New("user not created")
|
||||
}
|
||||
|
||||
user.CreatedAt = time.Now()
|
||||
|
@ -96,7 +97,7 @@ func CreateUser(w http.ResponseWriter, r *http.Request) (int, error) {
|
|||
return http.StatusInternalServerError, fmt.Errorf("Username already taken, you can choose: %s", usernameCandidate)
|
||||
}
|
||||
if CheckEmail(registrationForm.Email) {
|
||||
return http.StatusInternalServerError, errors.New("Email Address already in our database!")
|
||||
return http.StatusInternalServerError, errors.New("email address already in database")
|
||||
}
|
||||
password, err := bcrypt.GenerateFromPassword([]byte(registrationForm.Password), 10)
|
||||
if err != nil {
|
||||
|
@ -115,20 +116,19 @@ func CreateUser(w http.ResponseWriter, r *http.Request) (int, error) {
|
|||
// RetrieveUser retrieves a user.
|
||||
func RetrieveUser(r *http.Request, id string) (*model.PublicUser, bool, uint, int, error) {
|
||||
var user model.User
|
||||
var currentUserId uint
|
||||
var currentUserID uint
|
||||
var isAuthor bool
|
||||
// var publicUser *model.PublicUser
|
||||
// publicUser.User = &user
|
||||
|
||||
if db.ORM.First(&user, id).RecordNotFound() {
|
||||
return nil, isAuthor, currentUserId, http.StatusNotFound, errors.New("User is not found.")
|
||||
return nil, isAuthor, currentUserID, http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
currentUser, err := CurrentUser(r)
|
||||
if err == nil {
|
||||
currentUserId = currentUser.Id
|
||||
isAuthor = currentUser.Id == user.Id
|
||||
currentUserID = currentUser.ID
|
||||
isAuthor = currentUser.ID == user.ID
|
||||
}
|
||||
|
||||
return &model.PublicUser{User: &user}, isAuthor, currentUserId, http.StatusOK, nil
|
||||
return &model.PublicUser{User: &user}, isAuthor, currentUserID, http.StatusOK, nil
|
||||
}
|
||||
|
||||
// RetrieveUsers retrieves users.
|
||||
|
@ -144,19 +144,23 @@ func RetrieveUsers() []*model.PublicUser {
|
|||
// UpdateUserCore updates a user. (Applying the modifed data of user).
|
||||
func UpdateUserCore(user *model.User) (int, error) {
|
||||
if user.Email == "" {
|
||||
user.Md5 = ""
|
||||
user.MD5 = ""
|
||||
} else {
|
||||
user.Md5 = crypto.GenerateMD5Hash(user.Email)
|
||||
var err error
|
||||
user.MD5, err = crypto.GenerateMD5Hash(user.Email)
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
}
|
||||
|
||||
token, err := crypto.GenerateRandomToken32()
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, errors.New("Token not generated.")
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
user.Token = token
|
||||
user.TokenExpiration = timeHelper.FewDaysLater(config.AuthTokenExpirationDay)
|
||||
if db.ORM.Save(user).Error != nil {
|
||||
return http.StatusInternalServerError, errors.New("User is not updated.")
|
||||
return http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
user.UpdatedAt = time.Now()
|
||||
|
@ -167,22 +171,20 @@ func UpdateUserCore(user *model.User) (int, error) {
|
|||
func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *model.User, id string) (model.User, int, error) {
|
||||
var user model.User
|
||||
if db.ORM.First(&user, id).RecordNotFound() {
|
||||
return user, http.StatusNotFound, errors.New("User is not found.")
|
||||
return user, http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
|
||||
if form.Password != "" {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(form.CurrentPassword))
|
||||
if err != nil && !userPermission.HasAdmin(currentUser) {
|
||||
log.Error("Password Incorrect.")
|
||||
return user, http.StatusInternalServerError, errors.New("User is not updated. Password Incorrect.")
|
||||
} else {
|
||||
newPassword, err := bcrypt.GenerateFromPassword([]byte(form.Password), 10)
|
||||
if err != nil {
|
||||
return user, http.StatusInternalServerError, errors.New("User is not updated. Password not Generated.")
|
||||
} else {
|
||||
form.Password = string(newPassword)
|
||||
}
|
||||
return user, http.StatusInternalServerError, errors.New("password incorrect")
|
||||
}
|
||||
newPassword, err := bcrypt.GenerateFromPassword([]byte(form.Password), 10)
|
||||
if err != nil {
|
||||
return user, http.StatusInternalServerError, errors.New("password not generated")
|
||||
}
|
||||
form.Password = string(newPassword)
|
||||
} else { // Then no change of password
|
||||
form.Password = user.Password
|
||||
}
|
||||
|
@ -197,7 +199,7 @@ func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *m
|
|||
if err != nil {
|
||||
return user, status, err
|
||||
}
|
||||
if userPermission.CurrentUserIdentical(currentUser, user.Id) {
|
||||
if userPermission.CurrentUserIdentical(currentUser, user.ID) {
|
||||
status, err = SetCookie(w, user.Token)
|
||||
}
|
||||
return user, status, err
|
||||
|
@ -207,12 +209,12 @@ func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *m
|
|||
func DeleteUser(w http.ResponseWriter, currentUser *model.User, id string) (int, error) {
|
||||
var user model.User
|
||||
if db.ORM.First(&user, id).RecordNotFound() {
|
||||
return http.StatusNotFound, errors.New("User is not found.")
|
||||
return http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
if db.ORM.Delete(&user).Error != nil {
|
||||
return http.StatusInternalServerError, errors.New("User is not deleted.")
|
||||
return http.StatusInternalServerError, errors.New("user not deleted")
|
||||
}
|
||||
if userPermission.CurrentUserIdentical(currentUser, user.Id) {
|
||||
if userPermission.CurrentUserIdentical(currentUser, user.ID) {
|
||||
return ClearCookie(w)
|
||||
}
|
||||
return http.StatusOK, nil
|
||||
|
@ -231,7 +233,7 @@ func RetrieveCurrentUser(r *http.Request) (model.User, int, error) {
|
|||
func RetrieveUserByEmail(email string) (*model.PublicUser, string, int, error) {
|
||||
var user model.User
|
||||
if db.ORM.Unscoped().Where("email = ?", email).First(&user).RecordNotFound() {
|
||||
return &model.PublicUser{User: &user}, email, http.StatusNotFound, errors.New("User is not found.")
|
||||
return &model.PublicUser{User: &user}, email, http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
return &model.PublicUser{User: &user}, email, http.StatusOK, nil
|
||||
}
|
||||
|
@ -251,7 +253,7 @@ func RetrieveUsersByEmail(email string) []*model.PublicUser {
|
|||
func RetrieveUserByUsername(username string) (*model.PublicUser, string, int, error) {
|
||||
var user model.User
|
||||
if db.ORM.Where("username = ?", username).First(&user).RecordNotFound() {
|
||||
return &model.PublicUser{User: &user}, username, http.StatusNotFound, errors.New("User is not found.")
|
||||
return &model.PublicUser{User: &user}, username, http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
return &model.PublicUser{User: &user}, username, http.StatusOK, nil
|
||||
}
|
||||
|
@ -260,11 +262,11 @@ func RetrieveUserByUsername(username string) (*model.PublicUser, string, int, er
|
|||
func RetrieveUserForAdmin(id string) (model.User, int, error) {
|
||||
var user model.User
|
||||
if db.ORM.Preload("Torrents").First(&user, id).RecordNotFound() {
|
||||
return user, http.StatusNotFound, errors.New("User is not found.")
|
||||
return user, http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
var liked,likings []model.User
|
||||
db.ORM.Joins("JOIN user_follows on user_follows.user_id=?", user.Id).Where("users.user_id = user_follows.following").Group("users.user_id").Find(&likings)
|
||||
db.ORM.Joins("JOIN user_follows on user_follows.following=?", user.Id).Where("users.user_id = user_follows.user_id").Group("users.user_id").Find(&liked)
|
||||
var liked, likings []model.User
|
||||
db.ORM.Joins("JOIN user_follows on user_follows.user_id=?", user.ID).Where("users.user_id = user_follows.following").Group("users.user_id").Find(&likings)
|
||||
db.ORM.Joins("JOIN user_follows on user_follows.following=?", user.ID).Where("users.user_id = user_follows.user_id").Group("users.user_id").Find(&liked)
|
||||
user.Likings = likings
|
||||
user.Liked = liked
|
||||
return user, http.StatusOK, nil
|
||||
|
@ -277,7 +279,7 @@ func RetrieveUsersForAdmin() []model.User {
|
|||
db.ORM.Find(&users)
|
||||
for _, user := range users {
|
||||
db.ORM.Model(&user)
|
||||
db.ORM.Model(&user).Related("Torrents").Related("Likings").Related("Liked").Find(&model.Torrents{})
|
||||
db.ORM.Model(&user).Related("Torrents").Related("Likings").Related("Liked").Find(&model.Torrent{})
|
||||
userArr = append(userArr, user)
|
||||
}
|
||||
return userArr
|
||||
|
@ -294,15 +296,15 @@ func CreateUserAuthentication(w http.ResponseWriter, r *http.Request) (int, erro
|
|||
}
|
||||
|
||||
func SetFollow(user *model.User, follower *model.User) {
|
||||
if (follower.Id > 0 && user.Id > 0) {
|
||||
var userFollows = model.UserFollows{UserID: user.Id, FollowerID: follower.Id}
|
||||
if follower.ID > 0 && user.ID > 0 {
|
||||
var userFollows = model.UserFollows{UserID: user.ID, FollowerID: follower.ID}
|
||||
db.ORM.Create(&userFollows)
|
||||
}
|
||||
}
|
||||
|
||||
func RemoveFollow(user *model.User, follower *model.User) {
|
||||
if (follower.Id > 0 && user.Id > 0) {
|
||||
var userFollows = model.UserFollows{UserID: user.Id, FollowerID: follower.Id}
|
||||
if follower.ID > 0 && user.ID > 0 {
|
||||
var userFollows = model.UserFollows{UserID: user.ID, FollowerID: follower.ID}
|
||||
db.ORM.Delete(&userFollows)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package userService
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/ewhal/nyaa/db"
|
||||
"github.com/ewhal/nyaa/model"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
|
@ -23,14 +23,14 @@ func FindUserByUserName(userName string) (model.User, int, error) {
|
|||
func FindOrCreateUser(username string) (model.User, int, error) {
|
||||
var user model.User
|
||||
if db.ORM.Where("username=?", username).First(&user).RecordNotFound() {
|
||||
var user model.User
|
||||
user.Username = username
|
||||
log.Debugf("user %+v\n", user)
|
||||
if db.ORM.Create(&user).Error != nil {
|
||||
return user, http.StatusBadRequest, errors.New("User is not created.")
|
||||
var newUser model.User
|
||||
newUser.Username = username
|
||||
log.Debugf("user %+v\n", newUser)
|
||||
if db.ORM.Create(&newUser).Error != nil {
|
||||
return newUser, http.StatusBadRequest, errors.New("user not created")
|
||||
}
|
||||
log.Debugf("retrived User %v\n", user)
|
||||
return user, http.StatusOK, nil
|
||||
log.Debugf("retrieved User %v\n", newUser)
|
||||
return newUser, http.StatusOK, nil
|
||||
}
|
||||
return user, http.StatusBadRequest, nil
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/ewhal/nyaa/config"
|
||||
"github.com/ewhal/nyaa/db"
|
||||
"github.com/ewhal/nyaa/model"
|
||||
// "github.com/ewhal/nyaa/util/crypto"
|
||||
"github.com/ewhal/nyaa/util/email"
|
||||
"github.com/ewhal/nyaa/util/timeHelper"
|
||||
"github.com/gorilla/securecookie"
|
||||
|
@ -20,9 +21,12 @@ var verificationHandler = securecookie.New(config.EmailTokenHashKey, nil)
|
|||
|
||||
// SendEmailVerfication sends an email verification token via email.
|
||||
func SendEmailVerification(to string, token string, locale string) error {
|
||||
T, _ := i18n.Tfunc(locale)
|
||||
content := T("link")+" : https://"+config.WebAddress+"/verify/email/"+token
|
||||
content_html := T("verify_email_content")+"<br/>"+"<a href=\"https://"+config.WebAddress+"/verify/email/"+token+"\" target=\"_blank\">"+config.WebAddress+"/verify/email/"+token+"</a>"
|
||||
T, err := i18n.Tfunc(locale)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
content := T("link") + " : https://" + config.WebAddress + "/verify/email/" + token
|
||||
content_html := T("verify_email_content") + "<br/>" + "<a href=\"https://" + config.WebAddress + "/verify/email/" + token + "\" target=\"_blank\">" + config.WebAddress + "/verify/email/" + token + "</a>"
|
||||
return email.SendEmailFromAdmin(to, T("verify_email_title"), content, content_html)
|
||||
return nil
|
||||
}
|
||||
|
@ -31,8 +35,8 @@ func SendEmailVerification(to string, token string, locale string) error {
|
|||
func SendVerificationToUser(user model.User) (int, error) {
|
||||
validUntil := timeHelper.TwentyFourHoursLater() // TODO: longer duration?
|
||||
value := map[string]string{
|
||||
"t": strconv.FormatInt(validUntil.Unix(), 10),
|
||||
"u": strconv.FormatUint(uint64(user.Id), 10),
|
||||
"t": strconv.FormatInt(validUntil.Unix(), 10),
|
||||
"u": strconv.FormatUint(uint64(user.ID), 10),
|
||||
"e": user.Email,
|
||||
}
|
||||
encoded, err := verificationHandler.Encode("", value)
|
||||
|
@ -51,10 +55,10 @@ func SendVerification(r *http.Request) (int, error) {
|
|||
var user model.User
|
||||
currentUser, err := CurrentUser(r)
|
||||
if err != nil {
|
||||
return http.StatusUnauthorized, errors.New("Unauthorized.")
|
||||
return http.StatusUnauthorized, errors.New("unauthorized")
|
||||
}
|
||||
if db.ORM.First(&user, currentUser.Id).RecordNotFound() {
|
||||
return http.StatusNotFound, errors.New("User is not found.")
|
||||
if db.ORM.First(&user, currentUser.ID).RecordNotFound() {
|
||||
return http.StatusNotFound, errors.New("user not found")
|
||||
}
|
||||
status, err := SendVerificationToUser(user)
|
||||
return status, err
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
{{with .User}}
|
||||
<ul class="nav navbar-nav navbar-right badgemenu">
|
||||
<li class="dropdown">
|
||||
{{if gt .Id 0}}
|
||||
<a href="{{ genRoute "user_profile" "id" (print .Id) "username" .Username }}" class="dropdown-toggle profile-image" data-toggle="dropdown">
|
||||
<img src="https://www.gravatar.com/avatar/{{ .Md5 }}?s=50" class="img-circle special-img"> {{ .Username }} <b class="caret"></b></a>
|
||||
{{if gt .ID 0}}
|
||||
<a href="{{ genRoute "user_profile" "id" (print .ID) "username" .Username }}" class="dropdown-toggle profile-image" data-toggle="dropdown">
|
||||
<img src="https://www.gravatar.com/avatar/{{ .MD5 }}?s=50" class="img-circle special-img"> {{ .Username }} <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{ genRoute "user_profile" "id" (print .Id) "username" .Username }}"><i class="fa fa-cog"></i> Profile</a></li>
|
||||
<li><a href="{{ genRoute "user_profile" "id" (print .ID) "username" .Username }}"><i class="fa fa-cog"></i> Profile</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="{{ genRoute "user_logout" }}"><i class="fa fa-sign-out"></i> {{ T "sign_out"}}</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -97,9 +97,9 @@
|
|||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{{ if CurrentOrAdmin $.User .Id }}
|
||||
{{ if CurrentOrAdmin $.User .ID }}
|
||||
<hr>
|
||||
<a href="?delete" onclick="if (!confirm('{{ T "delete_account_confirm" }}')) return false;" class="btn btn-danger btn-lg"><i class="glyphicon glyphicon-trash"></i> {{ T "delete_account"}}</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
{{if eq .Status 4}}aplus{{end}}">
|
||||
<!-- forced width because the <td> gets bigger randomly otherwise -->
|
||||
<td style="width:80px">
|
||||
<a href="{{$.URL.Parse (printf "/search?c=%s_%s" .Category .Sub_Category) }}">
|
||||
<img src="{{$.URL.Parse (printf "/img/torrents/%s.png" .Sub_Category) }}">
|
||||
<a href="{{$.URL.Parse (printf "/search?c=%s_%s" .Category .SubCategory) }}">
|
||||
<img src="{{$.URL.Parse (printf "/img/torrents/%s.png" .SubCategory) }}">
|
||||
</a>
|
||||
</td>
|
||||
<td class="name">
|
||||
<a href="{{genRoute "view_torrent" "id" .Id }}">
|
||||
<a href="{{genRoute "view_torrent" "id" .ID }}">
|
||||
{{.Name}}
|
||||
</a>
|
||||
</td>
|
||||
|
@ -45,7 +45,7 @@
|
|||
</table>
|
||||
<nav class="torrentNav" aria-label="Page navigation">
|
||||
<ul class="pagination">
|
||||
<li><a href="{{ genRoute "search" }}?userId={{ .Id }}" aria-label="Next"><span class="glyphicon glyphicon-add"></span> {{ T "see_more_torrents_from" .Username }}</a></li>
|
||||
<li><a href="{{ genRoute "search" }}?userID={{ .ID }}" aria-label="Next"><span class="glyphicon glyphicon-add"></span> {{ T "see_more_torrents_from" .Username }}</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
|
@ -25,12 +25,12 @@
|
|||
{{if eq .Status 4}}aplus{{end}}">
|
||||
<!-- forced width because the <td> gets bigger randomly otherwise -->
|
||||
<td class="hidden-xs" style="width:80px">
|
||||
<a href="{{$.URL.Parse (printf "/search?c=%s_%s" .Category .Sub_Category) }}">
|
||||
<img src="{{$.URL.Parse (printf "/img/torrents/%s.png" .Sub_Category) }}">
|
||||
<a href="{{$.URL.Parse (printf "/search?c=%s_%s" .Category .SubCategory) }}">
|
||||
<img src="{{$.URL.Parse (printf "/img/torrents/%s.png" .SubCategory) }}">
|
||||
</a>
|
||||
</td>
|
||||
<td class="name">
|
||||
<a href="{{genRoute "view_torrent" "id" .Id }}">
|
||||
<a href="{{genRoute "view_torrent" "id" .ID }}">
|
||||
{{.Name}}
|
||||
</a>
|
||||
</td>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<div class="profile-sidebar">
|
||||
<!-- SIDEBAR USERPIC -->
|
||||
<div class="profile-userpic">
|
||||
<img src="{{ getAvatar .Md5 130 }}" class="img-responsive" alt="{{.Username}}">
|
||||
<img src="{{ getAvatar .MD5 130 }}" class="img-responsive" alt="{{.Username}}">
|
||||
</div>
|
||||
<!-- END SIDEBAR USERPIC -->
|
||||
<!-- SIDEBAR USER TITLE -->
|
||||
|
@ -25,12 +25,12 @@
|
|||
<!-- END SIDEBAR USER TITLE -->
|
||||
<!-- SIDEBAR BUTTONS -->
|
||||
<div class="profile-userbuttons">
|
||||
{{if gt $.User.Id 0 }}
|
||||
{{if not (CurrentUserIdentical $.User .Id) }}
|
||||
{{if gt $.User.ID 0 }}
|
||||
{{if not (CurrentUserIdentical $.User .ID) }}
|
||||
{{if not (IsFollower . $.User)}}
|
||||
<a href="{{ genRoute "user_follow" "id" ( print .Id ) "username" .Username }}" class="btn btn-success btn-sm">{{ T "follow"}}</a>
|
||||
<a href="{{ genRoute "user_follow" "id" ( print .ID ) "username" .Username }}" class="btn btn-success btn-sm">{{ T "follow"}}</a>
|
||||
{{else}}
|
||||
<a href="{{ genRoute "user_follow" "id" ( print .Id ) "username" .Username }}" class="btn btn-danger btn-sm">{{ T "unfollow"}}</a>
|
||||
<a href="{{ genRoute "user_follow" "id" ( print .ID ) "username" .Username }}" class="btn btn-danger btn-sm">{{ T "unfollow"}}</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
@ -45,8 +45,8 @@
|
|||
<i class="glyphicon glyphicon-home"></i>
|
||||
{{T "torrents"}} </a>
|
||||
</li>
|
||||
{{if gt $.User.Id 0 }}
|
||||
{{if CurrentOrAdmin $.User .Id }}
|
||||
{{if gt $.User.ID 0 }}
|
||||
{{if CurrentOrAdmin $.User .ID }}
|
||||
<li>
|
||||
<a href="?edit">
|
||||
<i class="glyphicon glyphicon-user"></i>
|
||||
|
@ -66,4 +66,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -22,12 +22,12 @@
|
|||
<!-- END SIDEBAR USER TITLE -->
|
||||
<!-- SIDEBAR BUTTONS -->
|
||||
<div class="profile-userbuttons">
|
||||
{{if gt $.User.Id 0 }}
|
||||
{{if not (CurrentUserIdentical $.User .Id) }}
|
||||
{{if gt $.User.ID 0 }}
|
||||
{{if not (CurrentUserIdentical $.User .ID) }}
|
||||
{{if not (IsFollower . $.User)}}
|
||||
<a href="{{ genRoute "user_follow" "id" .Id }}" class="btn btn-success btn-sm">{{ T "follow"}}</a>
|
||||
<a href="{{ genRoute "user_follow" "id" .ID }}" class="btn btn-success btn-sm">{{ T "follow"}}</a>
|
||||
{{else}}
|
||||
<a href="{{ genRoute "user_follow" "id" .Id }}" class="btn btn-danger btn-sm">{{ T "unfollow"}}</a>
|
||||
<a href="{{ genRoute "user_follow" "id" .ID }}" class="btn btn-danger btn-sm">{{ T "unfollow"}}</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
@ -42,8 +42,8 @@
|
|||
<i class="glyphicon glyphicon-home"></i>
|
||||
{{T "torrents"}} </a>
|
||||
</li>
|
||||
{{if gt $.User.Id 0 }}
|
||||
{{if CurrentOrAdmin $.User .Id }}
|
||||
{{if gt $.User.ID 0 }}
|
||||
{{if CurrentOrAdmin $.User .ID }}
|
||||
<li class="active">
|
||||
<a href="?edit">
|
||||
<i class="glyphicon glyphicon-user"></i>
|
||||
|
@ -63,4 +63,4 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -1,35 +1,38 @@
|
|||
{{define "title"}}{{.Torrent.Name}}{{end}} {{define "contclass"}}cont-view{{end}} {{define "content"}}
|
||||
<div class="blockBody">
|
||||
{{with .Torrent}}
|
||||
<hr>
|
||||
<table class="table table-borderless">
|
||||
<tr {{if eq .Status 2}}class="remake" {{end}} {{if eq .Status 3}}class="trusted" {{end}} {{if eq .Status 4}}class="aplus"
|
||||
{{end}}>
|
||||
<td>{{T "name"}}</td>
|
||||
<td>
|
||||
{{.Name}}
|
||||
<img style="float:right" src="{{$.URL.Parse (printf " /img/torrents/%s.png " .Sub_Category) }}">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{T "hash"}}</td>
|
||||
<td class="torrent-hash">{{.Hash}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{T "date"}}</td>
|
||||
<td class="date-full">{{.Date}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{T "size"}}</td>
|
||||
<td>{{.Filesize}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Uploader</td>
|
||||
<td><a href="{{$.URL.Parse (printf " /user/%d/- " .UploaderId) }}">{{.UploaderName}}</a></td>
|
||||
{{if ne .WebsiteLink ""}}
|
||||
<tr>
|
||||
<td>{{T "Link"}}</td>
|
||||
<td><a href="{{.WebsiteLink}}">{{.WebsiteLink}}</td>
|
||||
{{define "title"}}{{.Torrent.Name}}{{end}}
|
||||
{{define "contclass"}}cont-view{{end}}
|
||||
{{define "content"}}
|
||||
<div class="blockBody">
|
||||
{{with .Torrent}}
|
||||
<hr>
|
||||
<table class="table table-borderless">
|
||||
<tr {{if eq .Status 2}}class="remake"{{end}}
|
||||
{{if eq .Status 3}}class="trusted"{{end}}
|
||||
{{if eq .Status 4}}class="aplus"{{end}}>
|
||||
<td>{{T "name"}}</td>
|
||||
<td>
|
||||
{{.Name}}
|
||||
<img style="float:right" src="{{$.URL.Parse (printf "/img/torrents/%s.png" .SubCategory) }}">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{T "hash"}}</td>
|
||||
<td class="torrent-hash">{{.Hash}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{T "date"}}</td>
|
||||
<td class="date-full">{{.Date}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{T "size"}}</td>
|
||||
<td>{{.Filesize}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Uploader</td>
|
||||
<td><a href="{{$.URL.Parse (printf "/user/%d/-" .UploaderID) }}">{{.UploaderName}}</a></td>
|
||||
{{if ne .WebsiteLink ""}}
|
||||
<tr>
|
||||
<td>{{T "Link"}}</td>
|
||||
<td><a href="{{.WebsiteLink}}">{{.WebsiteLink}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
<tr>
|
||||
|
@ -72,7 +75,7 @@
|
|||
<form method="post">
|
||||
<div class="form-group">
|
||||
{{/* There should be a better way to use translation on this... */}}
|
||||
<label for="comment">{{ if gt .User.Id 0}} {{T "submit_a_comment_as_username" .User.Username}} {{else}} {{T "submit_a_comment_as_anonymous"}} {{end}}</label>
|
||||
<label for="comment">{{ if gt .User.ID 0}} {{T "submit_a_comment_as_username" .User.Username}} {{else}} {{T "submit_a_comment_as_anonymous"}} {{end}}</label>
|
||||
<textarea name="comment" class="form-control" rows="5"></textarea>
|
||||
</div>
|
||||
{{with .Captcha}} {{block "captcha" .}}{{end}} {{end}}
|
||||
|
@ -87,7 +90,7 @@
|
|||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="modal-title">Report Torrent #{{.Id}}</h4>
|
||||
<h4 class="modal-title">Report Torrent #{{.ID}}</h4>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="modal-body">
|
||||
|
@ -105,4 +108,4 @@
|
|||
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
|
|
@ -7,12 +7,16 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func GenerateMD5Hash(email string) string {
|
||||
email = strings.ToLower(strings.TrimSpace(email))
|
||||
func GenerateMD5Hash(str string) (string, error) {
|
||||
str = strings.ToLower(strings.TrimSpace(str))
|
||||
hash := md5.New()
|
||||
hash.Write([]byte(email))
|
||||
return fmt.Sprintf("%x", hash.Sum(nil))
|
||||
_, err := hash.Write([]byte(str))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%x", hash.Sum(nil)), nil
|
||||
}
|
||||
|
||||
func GenerateRandomToken16() (string, error) {
|
||||
return GenerateRandomToken(16)
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ var (
|
|||
)
|
||||
|
||||
func InitGomail() *gomail.Dialer {
|
||||
mailer := gomail.NewDialer(config.EmailHost, config.EmailPort, config.EmailUsername, config.EmailPassword)
|
||||
return mailer
|
||||
newMailer := gomail.NewDialer(config.EmailHost, config.EmailPort, config.EmailUsername, config.EmailPassword)
|
||||
return newMailer
|
||||
}
|
||||
|
||||
func SendEmailFromAdmin(to string, subject string, body string, bodyHTML string) error {
|
||||
|
@ -33,7 +33,7 @@ func SendEmailFromAdmin(to string, subject string, body string, bodyHTML string)
|
|||
if config.SendEmail {
|
||||
log.Debug("SendEmail performed.")
|
||||
|
||||
err := mailer.DialAndSend(msg);
|
||||
err := mailer.DialAndSend(msg)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
@ -52,7 +52,6 @@ func SendTestEmail() error {
|
|||
panic(err)
|
||||
}
|
||||
msg.Attach(path)
|
||||
// SendEmail(msg)
|
||||
|
||||
err = mailer.DialAndSend(msg)
|
||||
return err
|
||||
|
|
|
@ -1,35 +1,34 @@
|
|||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func FormatFilesize(bytes int64) string {
|
||||
var unit string
|
||||
var value float64
|
||||
if bytes >= 1024*1024*1024*1024 {
|
||||
unit = "TiB"
|
||||
value = float64(bytes) / (1024*1024*1024*1024)
|
||||
} else if bytes >= 1024*1024*1024 {
|
||||
unit = "GiB"
|
||||
value = float64(bytes) / (1024*1024*1024)
|
||||
} else if bytes >= 1024*1024 {
|
||||
unit = "MiB"
|
||||
value = float64(bytes) / (1024*1024)
|
||||
} else if bytes >= 1024 {
|
||||
unit = "KiB"
|
||||
value = float64(bytes) / (1024)
|
||||
} else {
|
||||
unit = "B"
|
||||
value = float64(bytes)
|
||||
}
|
||||
return fmt.Sprintf("%.1f %s", value, unit)
|
||||
var unit string
|
||||
var value float64
|
||||
if bytes >= 1024*1024*1024*1024 {
|
||||
unit = "TiB"
|
||||
value = float64(bytes) / (1024 * 1024 * 1024 * 1024)
|
||||
} else if bytes >= 1024*1024*1024 {
|
||||
unit = "GiB"
|
||||
value = float64(bytes) / (1024 * 1024 * 1024)
|
||||
} else if bytes >= 1024*1024 {
|
||||
unit = "MiB"
|
||||
value = float64(bytes) / (1024 * 1024)
|
||||
} else if bytes >= 1024 {
|
||||
unit = "KiB"
|
||||
value = float64(bytes) / (1024)
|
||||
} else {
|
||||
unit = "B"
|
||||
value = float64(bytes)
|
||||
}
|
||||
return fmt.Sprintf("%.1f %s", value, unit)
|
||||
}
|
||||
|
||||
func FormatFilesize2(bytes int64) string {
|
||||
if bytes == 0 { // this is what gorm returns for NULL
|
||||
return "Unknown"
|
||||
} else {
|
||||
return FormatFilesize(bytes)
|
||||
}
|
||||
return FormatFilesize(bytes)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package languages
|
||||
|
||||
import (
|
||||
"github.com/nicksnyder/go-i18n/i18n"
|
||||
"fmt"
|
||||
"github.com/nicksnyder/go-i18n/i18n"
|
||||
"html/template"
|
||||
"net/http"
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"fmt"
|
||||
"github.com/Sirupsen/logrus"
|
||||
"runtime"
|
||||
)
|
||||
)
|
||||
|
||||
// CheckError check error and return true if error is nil and return false if error is not nil.
|
||||
func CheckError(err error) bool {
|
||||
|
@ -16,14 +16,12 @@ func CheckErrorWithMessage(err error, msg string, args ...interface{}) bool {
|
|||
if err != nil {
|
||||
var stack [4096]byte
|
||||
runtime.Stack(stack[:], false)
|
||||
// logrus.Errorf(msg, args)
|
||||
if len(args) == 0 {
|
||||
logrus.Error(msg + fmt.Sprintf("%q\n%s\n", err, stack[:]))
|
||||
} else {
|
||||
logrus.Error(fmt.Sprintf(msg, args...) + fmt.Sprintf("%q\n%s\n", err, stack[:]))
|
||||
}
|
||||
// logrus.Printf(msg+"\n%q\n%s\n",args, err, stack[:])
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,13 +35,10 @@ func InitLogToFile() {
|
|||
|
||||
out := LumberJackLogger(config.ErrorLogFilePath+config.ErrorLogFileExtension, config.ErrorLogMaxSize, config.ErrorLogMaxBackups, config.ErrorLogMaxAge)
|
||||
|
||||
|
||||
logrus.SetOutput(out)
|
||||
logrus.SetLevel(logrus.WarnLevel)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Init logrus
|
||||
func Init(environment string) {
|
||||
switch environment {
|
||||
|
@ -120,8 +117,14 @@ func DebugResponse(response *http.Response) string {
|
|||
bodyBuffer := make([]byte, 5000)
|
||||
var str string
|
||||
count, err := response.Body.Read(bodyBuffer)
|
||||
if err != nil {
|
||||
Debug(err.Error())
|
||||
return ""
|
||||
}
|
||||
for ; count > 0; count, err = response.Body.Read(bodyBuffer) {
|
||||
if err != nil {
|
||||
Debug(err.Error())
|
||||
continue
|
||||
}
|
||||
str += string(bodyBuffer[:count])
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"html/template"
|
||||
)
|
||||
|
||||
// TODO restrict certain types of markdown
|
||||
// TODO: restrict certain types of markdown
|
||||
func MarkdownToHTML(markdown string) template.HTML {
|
||||
unsafe := blackfriday.MarkdownCommon([]byte(markdown))
|
||||
html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
|
||||
|
|
|
@ -107,7 +107,7 @@ func (tf *TorrentFile) GetAllAnnounceURLS() (l []string) {
|
|||
}
|
||||
|
||||
func (tf *TorrentFile) TorrentName() string {
|
||||
return string(tf.Info.Path)
|
||||
return tf.Info.Path
|
||||
}
|
||||
|
||||
// return true if this torrent is private otherwise return false
|
||||
|
@ -116,10 +116,13 @@ func (tf *TorrentFile) IsPrivate() bool {
|
|||
}
|
||||
|
||||
// calculate infohash
|
||||
func (tf *TorrentFile) Infohash() (ih [20]byte) {
|
||||
func (tf *TorrentFile) Infohash() (ih [20]byte, err error) {
|
||||
s := sha1.New()
|
||||
enc := bencode.NewEncoder(s)
|
||||
enc.Encode(&tf.Info)
|
||||
err = enc.Encode(&tf.Info)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
d := s.Sum(nil)
|
||||
copy(ih[:], d[:])
|
||||
return
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
package modelHelper
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"net/http"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"strconv"
|
||||
"fmt"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// TODO: Rewrite module
|
||||
// Functions are highly complex and require a lot of additional error handling
|
||||
|
||||
func IsZeroOfUnderlyingType(x interface{}) bool {
|
||||
return x == reflect.Zero(reflect.TypeOf(x)).Interface()
|
||||
}
|
||||
|
@ -39,101 +42,99 @@ func BindValueForm(form interface{}, r *http.Request) {
|
|||
typeField := formElem.Type().Field(i)
|
||||
tag := typeField.Tag
|
||||
switch typeField.Type.Name() {
|
||||
case "string" :
|
||||
formElem.Field(i).SetString(r.PostFormValue(tag.Get("form")))
|
||||
case "int" :
|
||||
nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form")))
|
||||
formElem.Field(i).SetInt(int64(nbr))
|
||||
case "float" :
|
||||
nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form")))
|
||||
formElem.Field(i).SetFloat(float64(nbr))
|
||||
case "bool" :
|
||||
nbr, _ := strconv.ParseBool(r.PostFormValue(tag.Get("form")))
|
||||
formElem.Field(i).SetBool(nbr)
|
||||
case "string":
|
||||
formElem.Field(i).SetString(r.PostFormValue(tag.Get("form")))
|
||||
case "int":
|
||||
nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form")))
|
||||
formElem.Field(i).SetInt(int64(nbr))
|
||||
case "float":
|
||||
nbr, _ := strconv.Atoi(r.PostFormValue(tag.Get("form")))
|
||||
formElem.Field(i).SetFloat(float64(nbr))
|
||||
case "bool":
|
||||
nbr, _ := strconv.ParseBool(r.PostFormValue(tag.Get("form")))
|
||||
formElem.Field(i).SetBool(nbr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
func ValidateForm(form interface{}, errorForm map[string][]string) (map[string][]string) {
|
||||
func ValidateForm(form interface{}, errorForm map[string][]string) map[string][]string {
|
||||
formElem := reflect.ValueOf(form).Elem()
|
||||
for i := 0; i < formElem.NumField(); i++ {
|
||||
typeField := formElem.Type().Field(i)
|
||||
tag := typeField.Tag
|
||||
inputName := typeField.Name
|
||||
if (tag.Get("hum_name") != "") { // For more human input name than gibberish
|
||||
if tag.Get("hum_name") != "" { // For more human input name than gibberish
|
||||
inputName = tag.Get("hum_name")
|
||||
}
|
||||
if tag.Get("len_min") != "" && (tag.Get("needed") != ""||formElem.Field(i).Len()>0) { // Check minimum length
|
||||
if tag.Get("len_min") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) { // Check minimum length
|
||||
lenMin, _ := strconv.Atoi(tag.Get("len_min"))
|
||||
if formElem.Field(i).Len() < lenMin {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Minimal length of %s required for the input: %s", strconv.Itoa(lenMin), inputName))
|
||||
}
|
||||
}
|
||||
if tag.Get("len_max") != "" && (tag.Get("needed") != ""||formElem.Field(i).Len()>0) { // Check maximum length
|
||||
if tag.Get("len_max") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) { // Check maximum length
|
||||
lenMax, _ := strconv.Atoi(tag.Get("len_max"))
|
||||
if formElem.Field(i).Len() > lenMax {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Maximal length of %s required for the input: %s", strconv.Itoa(lenMax), inputName))
|
||||
}
|
||||
}
|
||||
if tag.Get("equalInput") != "" && (tag.Get("needed") != ""||formElem.Field(i).Len()>0) {
|
||||
if tag.Get("equalInput") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) {
|
||||
otherInput := formElem.FieldByName(tag.Get("equalInput"))
|
||||
if formElem.Field(i).Interface() != otherInput.Interface() {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Must be same %s", inputName))
|
||||
}
|
||||
}
|
||||
switch typeField.Type.Name() {
|
||||
case "string" :
|
||||
if tag.Get("equal") != "" && formElem.Field(i).String() != tag.Get("equal") {
|
||||
case "string":
|
||||
if tag.Get("equal") != "" && formElem.Field(i).String() != tag.Get("equal") {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
if tag.Get("needed") != "" && formElem.Field(i).String() == "" {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
|
||||
}
|
||||
if tag.Get("default") != "" {
|
||||
formElem.Field(i).SetString(tag.Get("default"))
|
||||
}
|
||||
case "int":
|
||||
if tag.Get("equal") != "" { // Check minimum length
|
||||
equal, _ := strconv.Atoi(tag.Get("equal"))
|
||||
if formElem.Field(i).Int() > int64(equal) {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
if tag.Get("needed") != "" && formElem.Field(i).String() == "" {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
|
||||
}
|
||||
if tag.Get("needed") != "" && formElem.Field(i).Int() == 0 {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
|
||||
}
|
||||
if tag.Get("default") != "" {
|
||||
defaultValue, _ := strconv.Atoi(tag.Get("default"))
|
||||
formElem.Field(i).SetInt(int64(defaultValue))
|
||||
}
|
||||
case "float":
|
||||
if tag.Get("equal") != "" { // Check minimum length
|
||||
equal, _ := strconv.Atoi(tag.Get("equal"))
|
||||
if formElem.Field(i).Float() != float64(equal) {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
if tag.Get("default") != "" {
|
||||
formElem.Field(i).SetString(tag.Get("default"))
|
||||
}
|
||||
case "int" :
|
||||
if tag.Get("equal") != "" { // Check minimum length
|
||||
equal, _ := strconv.Atoi(tag.Get("equal"))
|
||||
if formElem.Field(i).Int() > int64(equal) {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
}
|
||||
if tag.Get("needed") != "" && formElem.Field(i).Int() == 0 {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
|
||||
}
|
||||
if tag.Get("default") != "" {
|
||||
defaultValue, _ := strconv.Atoi(tag.Get("default"))
|
||||
formElem.Field(i).SetInt(int64(defaultValue))
|
||||
}
|
||||
case "float" :
|
||||
if tag.Get("equal") != "" { // Check minimum length
|
||||
equal, _ := strconv.Atoi(tag.Get("equal"))
|
||||
if formElem.Field(i).Float() != float64(equal) {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
}
|
||||
if tag.Get("needed") != "" && formElem.Field(i).Float() == 0 {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
|
||||
}
|
||||
if tag.Get("default") != "" {
|
||||
defaultValue, _ := strconv.Atoi(tag.Get("default"))
|
||||
formElem.Field(i).SetFloat(float64(defaultValue))
|
||||
}
|
||||
case "bool" :
|
||||
if tag.Get("equal") != "" { // Check minimum length
|
||||
equal, _ := strconv.ParseBool(tag.Get("equal"))
|
||||
if formElem.Field(i).Bool() != equal {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
}
|
||||
if tag.Get("default") != "" {
|
||||
defaultValue, _ := strconv.ParseBool(tag.Get("default"))
|
||||
formElem.Field(i).SetBool(defaultValue)
|
||||
}
|
||||
if tag.Get("needed") != "" && formElem.Field(i).Float() == 0 {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName))
|
||||
}
|
||||
if tag.Get("default") != "" {
|
||||
defaultValue, _ := strconv.Atoi(tag.Get("default"))
|
||||
formElem.Field(i).SetFloat(float64(defaultValue))
|
||||
}
|
||||
case "bool":
|
||||
if tag.Get("equal") != "" { // Check minimum length
|
||||
equal, _ := strconv.ParseBool(tag.Get("equal"))
|
||||
if formElem.Field(i).Bool() != equal {
|
||||
errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName))
|
||||
}
|
||||
}
|
||||
if tag.Get("default") != "" {
|
||||
defaultValue, _ := strconv.ParseBool(tag.Get("default"))
|
||||
formElem.Field(i).SetBool(defaultValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return errorForm
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
func Safe(s string) template.URL {
|
||||
return template.URL(s)
|
||||
return template.URL(html.EscapeString(s))
|
||||
}
|
||||
|
||||
func SafeText(s string) template.HTML {
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
package search
|
||||
|
||||
import (
|
||||
"github.com/ewhal/nyaa/db"
|
||||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/service/torrent"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/ewhal/nyaa/db"
|
||||
"github.com/ewhal/nyaa/model"
|
||||
"github.com/ewhal/nyaa/service/torrent"
|
||||
"github.com/ewhal/nyaa/util/log"
|
||||
)
|
||||
|
||||
type Status uint8
|
||||
|
@ -56,20 +55,19 @@ type SearchParam struct {
|
|||
Query string
|
||||
}
|
||||
|
||||
func SearchByQuery(r *http.Request, pagenum int) (search SearchParam, tor []model.Torrents, count int, err error) {
|
||||
func SearchByQuery(r *http.Request, pagenum int) (search SearchParam, tor []model.Torrent, count int, err error) {
|
||||
search, tor, count, err = searchByQuery(r, pagenum, true)
|
||||
return
|
||||
}
|
||||
|
||||
func SearchByQueryNoCount(r *http.Request, pagenum int) (search SearchParam, tor []model.Torrents, err error) {
|
||||
func SearchByQueryNoCount(r *http.Request, pagenum int) (search SearchParam, tor []model.Torrent, err error) {
|
||||
search, tor, _, err = searchByQuery(r, pagenum, false)
|
||||
return
|
||||
}
|
||||
|
||||
func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchParam, tor []model.Torrents, count int, err error) {
|
||||
func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchParam, tor []model.Torrent, count int, err error) {
|
||||
max, err := strconv.ParseUint(r.URL.Query().Get("max"), 10, 32)
|
||||
if err != nil {
|
||||
err = nil
|
||||
max = 50 // default Value maxPerPage
|
||||
} else if max > 300 {
|
||||
max = 300
|
||||
|
@ -105,36 +103,36 @@ func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchPa
|
|||
}
|
||||
}
|
||||
|
||||
order_by := ""
|
||||
orderBy := ""
|
||||
|
||||
switch s := r.URL.Query().Get("sort"); s {
|
||||
case "1":
|
||||
search.Sort = Name
|
||||
order_by += "torrent_name"
|
||||
orderBy += "torrent_name"
|
||||
case "2":
|
||||
search.Sort = Date
|
||||
order_by += "date"
|
||||
orderBy += "date"
|
||||
case "3":
|
||||
search.Sort = Downloads
|
||||
order_by += "downloads"
|
||||
orderBy += "downloads"
|
||||
case "4":
|
||||
search.Sort = Size
|
||||
order_by += "filesize"
|
||||
orderBy += "filesize"
|
||||
default:
|
||||
order_by += "torrent_id"
|
||||
orderBy += "torrent_id"
|
||||
}
|
||||
|
||||
order_by += " "
|
||||
orderBy += " "
|
||||
|
||||
switch s := r.URL.Query().Get("order"); s {
|
||||
case "true":
|
||||
search.Order = true
|
||||
order_by += "asc"
|
||||
orderBy += "asc"
|
||||
default:
|
||||
order_by += "desc"
|
||||
orderBy += "desc"
|
||||
}
|
||||
|
||||
userId := r.URL.Query().Get("userId")
|
||||
userID := r.URL.Query().Get("userID")
|
||||
|
||||
parameters := torrentService.WhereParams{
|
||||
Params: make([]interface{}, 0, 64),
|
||||
|
@ -148,9 +146,9 @@ func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchPa
|
|||
conditions = append(conditions, "sub_category = ?")
|
||||
parameters.Params = append(parameters.Params, string(catString[2]))
|
||||
}
|
||||
if userId != "" {
|
||||
if userID != "" {
|
||||
conditions = append(conditions, "uploader = ?")
|
||||
parameters.Params = append(parameters.Params, userId)
|
||||
parameters.Params = append(parameters.Params, userID)
|
||||
}
|
||||
if search.Status != 0 {
|
||||
if search.Status == 3 {
|
||||
|
@ -191,9 +189,9 @@ func searchByQuery(r *http.Request, pagenum int, countAll bool) (search SearchPa
|
|||
parameters.Conditions = strings.Join(conditions[:], " AND ")
|
||||
log.Infof("SQL query is :: %s\n", parameters.Conditions)
|
||||
if countAll {
|
||||
tor, count, err = torrentService.GetTorrentsOrderBy(¶meters, order_by, int(search.Max), int(search.Max)*(pagenum-1))
|
||||
tor, count, err = torrentService.GetTorrentsOrderBy(¶meters, orderBy, int(search.Max), int(search.Max)*(pagenum-1))
|
||||
} else {
|
||||
tor, err = torrentService.GetTorrentsOrderByNoCount(¶meters, order_by, int(search.Max), int(search.Max)*(pagenum-1))
|
||||
tor, err = torrentService.GetTorrentsOrderByNoCount(¶meters, orderBy, int(search.Max), int(search.Max)*(pagenum-1))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,4 +4,5 @@ package signals
|
|||
|
||||
func Handle() {
|
||||
// windows has no sighup LOOOOL, this does nothing
|
||||
// TODO: Something about SIGHUP for Windows
|
||||
}
|
||||
|
|
|
@ -30,8 +30,6 @@ func InTimeSpanNow(start, end time.Time) bool {
|
|||
|
||||
func FewDurationLater(duration time.Duration) time.Time {
|
||||
// When Save time should considering UTC
|
||||
// baseTime := time.Now()
|
||||
// log.Debugf("basetime : %s", baseTime)
|
||||
fewDurationLater := time.Now().Add(duration)
|
||||
log.Debugf("time : %s", fewDurationLater)
|
||||
return fewDurationLater
|
||||
|
@ -42,11 +40,7 @@ func FewDurationLaterMillisecond(duration time.Duration) int64 {
|
|||
}
|
||||
|
||||
func IsExpired(expirationTime time.Time) bool {
|
||||
// baseTime := time.Now()
|
||||
// log.Debugf("basetime : %s", baseTime)
|
||||
log.Debugf("expirationTime : %s", expirationTime)
|
||||
// elapsed := time.Since(expirationTime)
|
||||
// log.Debugf("elapsed : %s", elapsed)
|
||||
after := time.Now().After(expirationTime)
|
||||
log.Debugf("after : %t", after)
|
||||
return after
|
||||
|
|
|
@ -8,15 +8,19 @@ import (
|
|||
"io/ioutil"
|
||||
)
|
||||
|
||||
func UnZlib(description []byte) string {
|
||||
func UnZlib(description []byte) (string, error) {
|
||||
if len(description) > 0 {
|
||||
b := bytes.NewReader(description)
|
||||
z, err := zlib.NewReader(b)
|
||||
log.CheckError(err)
|
||||
if !log.CheckError(err) {
|
||||
return "", err
|
||||
}
|
||||
defer z.Close()
|
||||
p, err := ioutil.ReadAll(z)
|
||||
log.CheckError(err)
|
||||
return string(p)
|
||||
if !log.CheckError(err) {
|
||||
return "", err
|
||||
}
|
||||
return string(p), nil
|
||||
}
|
||||
return ""
|
||||
}
|
||||
return "", nil
|
||||
}
|
||||
|
|
Référencer dans un nouveau ticket