Albirew/nyaa-pantsu
Albirew
/
nyaa-pantsu
Archivé
1
0
Bifurcation 0

Golint friendly next (#756)

* Gofmt friendly

Keeping Go source code in line with what they preconize

* Golint Friendly Next

So I have made some variables unexported
Added comments in every function that I know what it does
Removed some deprecated stuff that I was sure of
Added a comment on possible deprecated methods "Is it deprecated?"
Changed some variable/method name according to golint recommendations

* Update filelist.go
Cette révision appartient à :
akuma06 2017-05-26 12:12:52 +02:00 révisé par GitHub
Parent 8fbdeed9f5
révision 6481e90a0c
83 fichiers modifiés avec 617 ajouts et 309 suppressions

Voir le fichier

@ -4,7 +4,7 @@ type UserParam struct {
Full bool // if true populate Uploads, UsersWeLiked and UsersLikingMe
Email string
Name string
ApiToken string
APIToken string
ID uint32
Max uint32
Offset uint32

Voir le fichier

@ -7,8 +7,10 @@ type CacheConfig struct {
Size float64
}
// DefaultCacheSize : Size by default for the cache
const DefaultCacheSize = 1 << 10
// DefaultCacheConfig : Config by default for the cache
var DefaultCacheConfig = CacheConfig{
Dialect: "nop",
}

Voir le fichier

@ -12,12 +12,18 @@ import (
const (
// LastOldTorrentID is the highest torrent ID
// that was copied from the original Nyaa
LastOldTorrentID = 923000
TorrentsTableName = "torrents"
ReportsTableName = "torrent_reports"
CommentsTableName = "comments"
UploadsOldTableName = "user_uploads_old"
FilesTableName = "files"
LastOldTorrentID = 923000
// TorrentsTableName : Name of torrent table in DB
TorrentsTableName = "torrents"
// ReportsTableName : Name of torrent report table in DB
ReportsTableName = "torrent_reports"
// CommentsTableName : Name of comments table in DB
CommentsTableName = "comments"
// UploadsOldTableName : Name of uploads table in DB
UploadsOldTableName = "user_uploads_old"
// FilesTableName : Name of files table in DB
FilesTableName = "files"
// NotificationTableName : Name of notifications table in DB
NotificationTableName = "notifications"
// for sukebei:
@ -29,10 +35,12 @@ const (
//FilesTableName = "sukebei_files"
)
// IsSukebei : Tells if we are on the sukebei website
func IsSukebei() bool {
return TorrentsTableName == "sukebei_torrents"
}
// Config : Configuration for DB, I2P, Fetcher, Go Server and Translation
type Config struct {
Host string `json:"host"`
Port int `json:"port"`
@ -55,6 +63,7 @@ type Config struct {
I18n I18nConfig `json:"i18n"`
}
// Defaults : Configuration by default
var Defaults = Config{"localhost", 9999, "sqlite3", "./nyaa.db?cache_size=50", "default", DefaultScraperConfig, DefaultCacheConfig, DefaultSearchConfig, nil, DefaultMetainfoFetcherConfig, DefaultI18nConfig}
var allowedDatabaseTypes = map[string]bool{
@ -70,6 +79,7 @@ var allowedDBLogModes = map[string]bool{
"silent": true,
}
// New : Construct a new config variable
func New() *Config {
var config Config
config.Host = Defaults.Host
@ -112,6 +122,7 @@ func (config *Config) BindFlags() func() error {
}
}
// HandleConfFileFlag : Read the config from a file
func (config *Config) HandleConfFileFlag(path string) error {
if path != "" {
file, err := os.Open(path)
@ -127,30 +138,35 @@ func (config *Config) HandleConfFileFlag(path string) error {
return nil
}
func (config *Config) SetDBType(db_type string) error {
if !allowedDatabaseTypes[db_type] {
return fmt.Errorf("unknown database backend '%s'", db_type)
// SetDBType : Set the DataBase type in config
func (config *Config) SetDBType(dbType string) error {
if !allowedDatabaseTypes[dbType] {
return fmt.Errorf("unknown database backend '%s'", dbType)
}
config.DBType = db_type
config.DBType = dbType
return nil
}
func (config *Config) SetDBLogMode(db_logmode string) error {
if !allowedDBLogModes[db_logmode] {
return fmt.Errorf("unknown database log mode '%s'", db_logmode)
// SetDBLogMode : Set the log mode in config
func (config *Config) SetDBLogMode(dbLogmode string) error {
if !allowedDBLogModes[dbLogmode] {
return fmt.Errorf("unknown database log mode '%s'", dbLogmode)
}
config.DBLogMode = db_logmode
config.DBLogMode = dbLogmode
return nil
}
// Read : Decode config from json to config
func (config *Config) Read(input io.Reader) error {
return json.NewDecoder(input).Decode(config)
}
// Write : Encode config from json to config
func (config *Config) Write(output io.Writer) error {
return json.NewEncoder(output).Encode(config)
}
// Pretty : Write config json in a file
func (config *Config) Pretty(output io.Writer) error {
data, err := json.MarshalIndent(config, "", "\t")
if err != nil {

Voir le fichier

@ -6,14 +6,23 @@ import "time"
// Future hosts shouldn't have to rebuild the binary to update a setting
const (
SendEmail = true
EmailFrom = "donotrespond@nyaa.pantsu.cat"
EmailTestTo = ""
EmailHost = "localhost"
// SendEmail : Enable Email
SendEmail = true
// EmailFrom : email address by default
EmailFrom = "donotrespond@nyaa.pantsu.cat"
// EmailTestTo : when testing to who send email
EmailTestTo = ""
// EmailHost : Host of mail server
EmailHost = "localhost"
// EmailUsername : Username needed for the connection
EmailUsername = ""
// EmailPassword : Password needed for the connection
EmailPassword = ""
EmailPort = 465
EmailTimeout = 10 * time.Second
// EmailPort : Mail Server port
EmailPort = 465
// EmailTimeout : Timeout for waiting server response
EmailTimeout = 10 * time.Second
)
// EmailTokenHashKey : /!\ Email hash for generating email activation token /!\
var EmailTokenHashKey = []byte("CHANGE_THIS_BEFORE_DEPLOYING_YOU_GIT")

Voir le fichier

@ -5,7 +5,9 @@ package config
const (
// Environment should be one of: DEVELOPMENT, TEST, PRODUCTION
Environment = "DEVELOPMENT"
WebAddress = "nyaa.pantsu.cat"
Environment = "DEVELOPMENT"
// WebAddress : url of the website
WebAddress = "nyaa.pantsu.cat"
// AuthTokenExpirationDay : Number of Days for token expiration when logged in
AuthTokenExpirationDay = 1000
)

Voir le fichier

@ -1,10 +1,12 @@
package config
// I18nConfig : Config struct for translation
type I18nConfig struct {
TranslationsDirectory string `json:"translations_directory"`
DefaultLanguage string `json:"default_language"`
}
// DefaultI18nConfig : Default configuration for translation
var DefaultI18nConfig = I18nConfig{
TranslationsDirectory: "translations",
DefaultLanguage: "en-us",

Voir le fichier

@ -1,5 +1,6 @@
package config
// I2PConfig : Config struct for I2P
type I2PConfig struct {
Name string `json:"name"`
Addr string `json:"samaddr"`

Voir le fichier

@ -1,14 +1,24 @@
package config
const (
AccessLogFilePath = "log/access"
// AccessLogFilePath : Path to logs access
AccessLogFilePath = "log/access"
// AccessLogFileExtension : Extension for log file
AccessLogFileExtension = ".txt"
AccessLogMaxSize = 5 // megabytes
AccessLogMaxBackups = 7
AccessLogMaxAge = 30 //days
ErrorLogFilePath = "log/error"
ErrorLogFileExtension = ".json"
ErrorLogMaxSize = 10 // megabytes
ErrorLogMaxBackups = 7
ErrorLogMaxAge = 30 //days
// AccessLogMaxSize : Size max for a log file in megabytes
AccessLogMaxSize = 5
// AccessLogMaxBackups : Number of file for logs
AccessLogMaxBackups = 7
// AccessLogMaxAge : Number of days that we keep logs
AccessLogMaxAge = 30
// ErrorLogFilePath : Path to log errors
ErrorLogFilePath = "log/error"
// ErrorLogFileExtension : Extension for log file
ErrorLogFileExtension = ".json"
// ErrorLogMaxSize : Size max for a log file in megabytes
ErrorLogMaxSize = 10
// ErrorLogMaxBackups : Number of file for logs
ErrorLogMaxBackups = 7
// ErrorLogMaxAge : Number of days that we keep logs
ErrorLogMaxAge = 30
)

Voir le fichier

@ -1,5 +1,6 @@
package config
// MetainfoFetcherConfig : Config struct for metainfo fetcher
type MetainfoFetcherConfig struct {
QueueSize int `json:"queue_size"`
Timeout int `json:"timeout"`
@ -14,6 +15,7 @@ type MetainfoFetcherConfig struct {
FetchNewTorrentsOnly bool `json:"fetch_new_torrents_only"`
}
// DefaultMetainfoFetcherConfig : Default configuration for metainfofetcher
var DefaultMetainfoFetcherConfig = MetainfoFetcherConfig{
QueueSize: 10,
Timeout: 120, // 2 min

Voir le fichier

@ -4,6 +4,7 @@ package config
// Future hosts shouldn't have to rebuild the binary to update a setting
const (
// TorrentsPerPage : Number of torrents per page
TorrentsPerPage = 50
MaxTorrentsPerPage = 300
)

Voir le fichier

@ -1,11 +1,13 @@
package config
// ScrapeConfig : Config struct for Scraping
type ScrapeConfig struct {
URL string `json:"scrape_url"`
Name string `json:"name"`
IntervalSeconds int64 `json:"interval"`
}
// ScraperConfig : Config struct for Scraper
type ScraperConfig struct {
Addr string `json:"bind"`
NumWorkers int `json:"workers"`

Voir le fichier

@ -1,8 +1,11 @@
package config
// SearchConfig : Config struct for search
// Is it deprecated?
type SearchConfig struct {
}
// DefaultSearchConfig : Default config for search
var DefaultSearchConfig = SearchConfig{}
const (

Voir le fichier

@ -4,6 +4,8 @@ package config
// Future hosts shouldn't have to rebuild the binary to update a setting
const (
// TorrentOrder : Default sorting field for torrents
TorrentOrder = "torrent_id"
TorrentSort = "DESC"
// TorrentSort : Default sorting order for torrents
TorrentSort = "DESC"
)

Voir le fichier

@ -1,6 +1,6 @@
package config
/* Config of different status id for torrents */
// TorrentStatus : Config of different status id for torrents
var TorrentStatus = map[int]bool{
0: true,
1: true,
@ -9,7 +9,7 @@ var TorrentStatus = map[int]bool{
4: true,
}
/* Config for Sukebei categories */
// TorrentSukebeiCategories : Config for Sukebei categories
var TorrentSukebeiCategories = map[string]string{
"1_": "art",
"1_1": "art_anime",
@ -22,7 +22,7 @@ var TorrentSukebeiCategories = map[string]string{
"2_2": "real_life_videos",
}
/* Config for Site categories */
// TorrentCleanCategories : Config for Site categories
var TorrentCleanCategories = map[string]string{
"3_": "anime",
"3_12": "anime_amv",

Voir le fichier

@ -2,6 +2,7 @@ package config
// TODO: Update FAQ template to use this variable
// Trackers : Default trackers supported
var Trackers = []string{
"udp://tracker.doko.moe:6969",
"udp://tracker.coppersurfer.tk:6969",

Voir le fichier

@ -3,12 +3,20 @@ package config
const (
// TorrentFileStorage = "/var/www/wherever/you/want"
// TorrentStorageLink = "https://your.site/somewhere/%s.torrent"
// TorrentFileStorage : Path to default torrent storage location
TorrentFileStorage = ""
// TorrentStorageLink : Url of torrent file download location
TorrentStorageLink = ""
// TODO: deprecate this and move all files to the same server
TorrentCacheLink = "http://anicache.com/torrent/%s.torrent"
UploadsDisabled = false
AdminsAreStillAllowedTo = true
// TorrentCacheLink : Url of torrent site cache
TorrentCacheLink = "http://anicache.com/torrent/%s.torrent"
// UploadsDisabled : Disable uploads for everyone except below
UploadsDisabled = false
// AdminsAreStillAllowedTo : Enable admin torrent upload even if UploadsDisabled is true
AdminsAreStillAllowedTo = true
// TrustedUsersAreStillAllowedTo : Enable trusted users torrent upload even if UploadsDisabled is true
TrustedUsersAreStillAllowedTo = true
)

Voir le fichier

@ -1,12 +1,11 @@
package config
/*
* Here we config the notifications options
// DefaultUserSettings :
/* Here we config the notifications options
* Uses in user model for default setting
* Be aware, default values in user update form are
* in service/user/form/form_validator.go
*/
var DefaultUserSettings = map[string]bool{
"new_torrent": true,
"new_torrent_email": false,

Voir le fichier

@ -72,22 +72,24 @@ type Database interface {
// XXX: add more as needed
}
var ErrInvalidDatabaseDialect = errors.New("invalid database dialect")
var ErrSqliteSucksAss = errors.New("sqlite3 sucks ass so it's not supported yet")
var errInvalidDatabaseDialect = errors.New("invalid database dialect")
var errSqliteSucksAss = errors.New("sqlite3 sucks ass so it's not supported yet")
// Impl : Database variable
var Impl Database
// Configure : Configure Database
func Configure(conf *config.Config) (err error) {
switch conf.DBType {
case "postgres":
Impl, err = postgres.New(conf.DBParams)
break
case "sqlite3":
err = ErrSqliteSucksAss
err = errSqliteSucksAss
// Impl, err = sqlite.New(conf.DBParams)
break
default:
err = ErrInvalidDatabaseDialect
err = errInvalidDatabaseDialect
}
if err == nil {
log.Infof("Init %s database", conf.DBType)

Voir le fichier

@ -5,16 +5,19 @@ import (
"github.com/NyaaPantsu/nyaa/model"
)
// InsertComment : Insert a comment
func (db *Database) InsertComment(comment *model.Comment) (err error) {
_, err = db.getPrepared(queryInsertComment).Exec(comment.ID, comment.TorrentID, comment.Content, comment.CreatedAt)
return
}
// GetCommentsWhere : Get comments on condition
func (db *Database) GetCommentsWhere(param *common.CommentParam) (comments []model.Comment, err error) {
return
}
// DeleteCommentsWhere : Delete comments on condition
func (db *Database) DeleteCommentsWhere(param *common.CommentParam) (deleted uint32, err error) {
return

Voir le fichier

@ -47,7 +47,7 @@ func scanTorrentReportColumnsFull(rows *sql.Rows, r *model.TorrentReport) {
const userSelectColumnsFull = `user_id, username, password, email, status, created_at, updated_at, api_token, api_token_expiry, language, md5`
func scanUserColumnsFull(rows *sql.Rows, u *model.User) {
rows.Scan(&u.ID, &u.Username, &u.Password, &u.Email, &u.Status, &u.CreatedAt, &u.UpdatedAt, &u.ApiToken, &u.ApiTokenExpiry, &u.Language, &u.MD5)
rows.Scan(&u.ID, &u.Username, &u.Password, &u.Email, &u.Status, &u.CreatedAt, &u.UpdatedAt, &u.APIToken, &u.APITokenExpiry, &u.Language, &u.MD5)
}

Voir le fichier

@ -82,12 +82,12 @@ func (db *Database) GetUserByID(id uint32) (user model.User, has bool, err error
}
func (db *Database) InsertUser(u *model.User) (err error) {
_, err = db.getPrepared(queryInsertUser).Exec(u.Username, u.Password, u.Email, u.Status, u.CreatedAt, u.UpdatedAt, u.ApiToken, u.ApiTokenExpiry, u.Language, u.MD5)
_, err = db.getPrepared(queryInsertUser).Exec(u.Username, u.Password, u.Email, u.Status, u.CreatedAt, u.UpdatedAt, u.APIToken, u.APITokenExpiry, u.Language, u.MD5)
return
}
func (db *Database) UpdateUser(u *model.User) (err error) {
_, err = db.getPrepared(queryUpdateUser).Exec(u.ID, u.Username, u.Password, u.Email, u.Status, u.UpdatedAt, u.ApiToken, u.ApiTokenExpiry, u.Language, u.MD5)
_, err = db.getPrepared(queryUpdateUser).Exec(u.ID, u.Username, u.Password, u.Email, u.Status, u.UpdatedAt, u.APIToken, u.APITokenExpiry, u.Language, u.MD5)
return
}
@ -101,8 +101,8 @@ func (db *Database) GetUsersWhere(param *common.UserParam) (users []model.User,
if has {
users = append(users, user)
}
} else if len(param.ApiToken) > 0 {
user, has, err = db.GetUserByAPIToken(param.ApiToken)
} else if len(param.APIToken) > 0 {
user, has, err = db.GetUserByAPIToken(param.APIToken)
if has {
users = append(users, user)
}
@ -141,9 +141,9 @@ func (db *Database) DeleteUsersWhere(param *common.UserParam) (deleted uint32, e
} else if len(param.Email) > 0 {
queryName = queryDeleteUserByEmail
p = param.Email
} else if len(param.ApiToken) > 0 {
} else if len(param.APIToken) > 0 {
queryName = queryDeleteUserByToken
p = param.ApiToken
p = param.APIToken
} else {
// delete nothing
return

Voir le fichier

@ -2,7 +2,8 @@ package sqlite
import (
"database/sql"
_ "github.com/mattn/go-sqlite3"
_ "github.com/mattn/go-sqlite3" // Need for sqlite
)
// queryEvent is a queued event to be executed in a pipeline to ensure that sqlite access is done from 1 goroutine
@ -12,6 +13,7 @@ type queryEvent struct {
handleResult func(*sql.Rows, error)
}
// New : Create a new database
func New(param string) (db *Database, err error) {
db = new(Database)
db.conn, err = sql.Open("sqlite3", param)
@ -23,6 +25,7 @@ func New(param string) (db *Database, err error) {
return
}
// Database structure
type Database struct {
conn *sql.DB
query chan *queryEvent

Voir le fichier

@ -5,19 +5,22 @@ import (
"github.com/NyaaPantsu/nyaa/model"
"github.com/NyaaPantsu/nyaa/util/log"
"github.com/azhao12345/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
_ "github.com/jinzhu/gorm/dialects/sqlite"
_ "github.com/jinzhu/gorm/dialects/postgres" // Need for postgres support
_ "github.com/jinzhu/gorm/dialects/sqlite" // Need for sqlite
)
// Logger interface
type Logger interface {
Print(v ...interface{})
}
// use the default gorm logger that prints to stdout
// DefaultLogger : use the default gorm logger that prints to stdout
var DefaultLogger Logger = nil
// ORM : Variable for interacting with database
var ORM *gorm.DB
// IsSqlite : Variable to know if we are in sqlite or postgres
var IsSqlite bool
// GormInit init gorm ORM.

Voir le fichier

@ -8,44 +8,49 @@ import (
"time"
)
// Generates Atom feed as XML
// ns : Generates Atom feed as XML
const ns = "http://www.w3.org/2005/Atom"
// AtomPerson struct
type AtomPerson struct {
Name string `xml:"name,omitempty"`
Uri string `xml:"uri,omitempty"`
URI string `xml:"uri,omitempty"`
Email string `xml:"email,omitempty"`
}
// AtomSummary struct
type AtomSummary struct {
XMLName xml.Name `xml:"summary"`
Content string `xml:",chardata"`
Type string `xml:"type,attr"`
}
// AtomContent struct
type AtomContent struct {
XMLName xml.Name `xml:"content"`
Content string `xml:",chardata"`
Type string `xml:"type,attr"`
}
// AtomAuthor struct
type AtomAuthor struct {
XMLName xml.Name `xml:"author"`
AtomPerson
}
// AtomContributor struct
type AtomContributor struct {
XMLName xml.Name `xml:"contributor"`
AtomPerson
}
// AtomEntry struct
type AtomEntry struct {
XMLName xml.Name `xml:"entry"`
Xmlns string `xml:"xmlns,attr,omitempty"`
Title string `xml:"title"` // required
Updated string `xml:"updated"` // required
Id string `xml:"id"` // required
ID string `xml:"id"` // required
Category string `xml:"category,omitempty"`
Content *AtomContent
Rights string `xml:"rights,omitempty"`
@ -57,6 +62,7 @@ type AtomEntry struct {
Author *AtomAuthor // required if feed lacks an author
}
// AtomLink struct
type AtomLink struct {
//Atom 1.0 <link rel="enclosure" type="audio/mpeg" title="MP3" href="http://www.example.org/myaudiofile.mp3" length="1234" />
XMLName xml.Name `xml:"link"`
@ -66,11 +72,12 @@ type AtomLink struct {
Length string `xml:"length,attr,omitempty"`
}
// AtomFeed struct
type AtomFeed struct {
XMLName xml.Name `xml:"feed"`
Xmlns string `xml:"xmlns,attr"`
Title string `xml:"title"` // required
Id string `xml:"id"` // required
ID string `xml:"id"` // required
Updated string `xml:"updated"` // required
Category string `xml:"category,omitempty"`
Icon string `xml:"icon,omitempty"`
@ -83,12 +90,13 @@ type AtomFeed struct {
Entries []*AtomEntry
}
// Atom struct
type Atom struct {
*Feed
}
func newAtomEntry(i *Item) *AtomEntry {
id := i.Id
id := i.ID
// assume the description is html
c := &AtomContent{Content: i.Description, Type: "html"}
@ -114,7 +122,7 @@ func newAtomEntry(i *Item) *AtomEntry {
Title: i.Title,
Link: &AtomLink{Href: i.Link.Href, Rel: i.Link.Rel, Type: i.Link.Type},
Content: c,
Id: id,
ID: id,
Updated: anyTimeFormat(time.RFC3339, i.Updated, i.Created),
}
@ -131,7 +139,7 @@ func newAtomEntry(i *Item) *AtomEntry {
return x
}
// create a new AtomFeed with a generic Feed struct's data
// AtomFeed : create a new AtomFeed with a generic Feed struct's data
func (a *Atom) AtomFeed() *AtomFeed {
updated := anyTimeFormat(time.RFC3339, a.Updated, a.Created)
feed := &AtomFeed{
@ -139,7 +147,7 @@ func (a *Atom) AtomFeed() *AtomFeed {
Title: a.Title,
Link: &AtomLink{Href: a.Link.Href, Rel: a.Link.Rel},
Subtitle: a.Description,
Id: a.Link.Href,
ID: a.Link.Href,
Updated: updated,
Rights: a.Copyright,
}
@ -152,12 +160,12 @@ func (a *Atom) AtomFeed() *AtomFeed {
return feed
}
// return an XML-Ready object for an Atom object
func (a *Atom) FeedXml() interface{} {
// FeedXML : return an XML-Ready object for an Atom object
func (a *Atom) FeedXML() interface{} {
return a.AtomFeed()
}
// return an XML-ready object for an AtomFeed object
func (a *AtomFeed) FeedXml() interface{} {
// FeedXML : return an XML-ready object for an AtomFeed object
func (a *AtomFeed) FeedXML() interface{} {
return a
}

Voir le fichier

@ -1,5 +1,7 @@
/*
Syndication (feed) generator library for golang.
// Package feeds :
package feeds
/* Syndication (feed) generator library for golang.
Installing
@ -67,4 +69,3 @@ From here, you can modify or add each syndication's specific fields before outpu
rss, err := ToXML(rssFeed)
*/
package feeds

Voir le fichier

@ -6,15 +6,17 @@ import (
"time"
)
// Link Struct
type Link struct {
Href, Rel, Type, Length string
}
// Author Struct
type Author struct {
Name, Email string
}
// modified for Nyaa
// Torrent Struct modified for Nyaa
type Torrent struct {
FileName string
Seeds uint32
@ -24,18 +26,20 @@ type Torrent struct {
MagnetURI string
}
// Item Struct
type Item struct {
Title string
Link *Link
Author *Author
Description string // used as description in rss, summary in atom
Id string // used as guid in rss, id in atom
ID string // used as guid in rss, id in atom
Updated time.Time
Created time.Time
Torrent *Torrent // modified for Nyaa
}
// Feed Struct
type Feed struct {
Title string
Link *Link
@ -43,13 +47,13 @@ type Feed struct {
Author *Author
Updated time.Time
Created time.Time
Id string
ID string
Subtitle string
Items []*Item
Copyright string
}
// add a new Item to a Feed
// Add a new Item to a Feed
func (f *Feed) Add(item *Item) {
f.Items = append(f.Items, item)
}
@ -64,15 +68,15 @@ func anyTimeFormat(format string, times ...time.Time) string {
return ""
}
// interface used by ToXML to get a object suitable for exporting XML.
type XmlFeed interface {
FeedXml() interface{}
// XMLFeed : interface used by ToXML to get a object suitable for exporting XML.
type XMLFeed interface {
FeedXML() interface{}
}
// turn a feed object (either a Feed, AtomFeed, or RssFeed) into xml
// ToXML : turn a feed object (either a Feed, AtomFeed, or RssFeed) into xml
// returns an error if xml marshaling fails
func ToXML(feed XmlFeed) (string, error) {
x := feed.FeedXml()
func ToXML(feed XMLFeed) (string, error) {
x := feed.FeedXML()
data, err := xml.MarshalIndent(x, "", " ")
if err != nil {
return "", err
@ -82,10 +86,10 @@ func ToXML(feed XmlFeed) (string, error) {
return s, nil
}
// Write a feed object (either a Feed, AtomFeed, or RssFeed) as XML into
// WriteXML : Write a feed object (either a Feed, AtomFeed, or RssFeed) as XML into
// the writer. Returns an error if XML marshaling fails.
func WriteXML(feed XmlFeed, w io.Writer) error {
x := feed.FeedXml()
func WriteXML(feed XMLFeed, w io.Writer) error {
x := feed.FeedXML()
// write default xml header, without the newline
if _, err := w.Write([]byte(xml.Header[:len(xml.Header)-1])); err != nil {
return err
@ -95,24 +99,24 @@ func WriteXML(feed XmlFeed, w io.Writer) error {
return e.Encode(x)
}
// creates an Atom representation of this feed
// ToAtom : creates an Atom representation of this feed
func (f *Feed) ToAtom() (string, error) {
a := &Atom{f}
return ToXML(a)
}
// Writes an Atom representation of this feed to the writer.
// WriteAtom : Writes an Atom representation of this feed to the writer.
func (f *Feed) WriteAtom(w io.Writer) error {
return WriteXML(&Atom{f}, w)
}
// creates an Rss representation of this feed
// ToRss : creates an Rss representation of this feed
func (f *Feed) ToRss() (string, error) {
r := &Rss{f}
return ToXML(r)
}
// Writes an RSS representation of this feed to the writer.
// WriteRss : Writes an RSS representation of this feed to the writer.
func (f *Feed) WriteRss(w io.Writer) error {
return WriteXML(&Rss{f}, w)
}

Voir le fichier

@ -12,22 +12,24 @@ import (
)
// private wrapper around the RssFeed which gives us the <rss>..</rss> xml
type rssFeedXml struct {
type rssFeedXML struct {
XMLName xml.Name `xml:"rss"`
Version string `xml:"version,attr"`
Channel *RssFeed
XMLNSTorrent string `xml:"xmlns:torrent,attr"` // modified for Nyaa
}
// RssImage Struct
type RssImage struct {
XMLName xml.Name `xml:"image"`
Url string `xml:"url"`
URL string `xml:"url"`
Title string `xml:"title"`
Link string `xml:"link"`
Width int `xml:"width,omitempty"`
Height int `xml:"height,omitempty"`
}
// RssTextInput Struct
type RssTextInput struct {
XMLName xml.Name `xml:"textInput"`
Title string `xml:"title"`
@ -36,6 +38,7 @@ type RssTextInput struct {
Link string `xml:"link"`
}
// RssFeed Struct
type RssFeed struct {
XMLName xml.Name `xml:"channel"`
Title string `xml:"title"` // required
@ -51,7 +54,7 @@ type RssFeed struct {
Generator string `xml:"generator,omitempty"`
Docs string `xml:"docs,omitempty"`
Cloud string `xml:"cloud,omitempty"`
Ttl int `xml:"ttl,omitempty"`
TTL int `xml:"ttl,omitempty"`
Rating string `xml:"rating,omitempty"`
SkipHours string `xml:"skipHours,omitempty"`
SkipDays string `xml:"skipDays,omitempty"`
@ -60,6 +63,7 @@ type RssFeed struct {
Items []*RssItem
}
// RssItem Struct
type RssItem struct {
XMLName xml.Name `xml:"item"`
Title string `xml:"title"` // required
@ -69,7 +73,7 @@ type RssItem struct {
Category string `xml:"category,omitempty"`
Comments string `xml:"comments,omitempty"`
Enclosure *RssEnclosure
Guid string `xml:"guid,omitempty"` // Id used
GUID string `xml:"guid,omitempty"` // Id used
PubDate string `xml:"pubDate,omitempty"` // created or updated
Source string `xml:"source,omitempty"`
@ -82,14 +86,16 @@ type RssItem struct {
MagnetURI string `xml:"torrent:magnetURI"`
}
// RssEnclosure Struct
type RssEnclosure struct {
//RSS 2.0 <enclosure url="http://example.com/file.mp3" length="123456789" type="audio/mpeg" />
XMLName xml.Name `xml:"enclosure"`
Url string `xml:"url,attr"`
URL string `xml:"url,attr"`
Length string `xml:"length,attr"`
Type string `xml:"type,attr"`
}
// Rss Struct
type Rss struct {
*Feed
}
@ -100,7 +106,7 @@ func newRssItem(i *Item) *RssItem {
Title: i.Title,
Link: i.Link.Href,
Description: i.Description,
Guid: i.Id,
GUID: i.ID,
PubDate: anyTimeFormat(time.RFC1123Z, i.Created, i.Updated),
// modified for Nyaa
FileName: i.Torrent.FileName,
@ -114,7 +120,7 @@ func newRssItem(i *Item) *RssItem {
intLength, err := strconv.ParseInt(i.Link.Length, 10, 64)
if err == nil && (intLength > 0 || i.Link.Type != "") {
item.Enclosure = &RssEnclosure{Url: i.Link.Href, Type: i.Link.Type, Length: i.Link.Length}
item.Enclosure = &RssEnclosure{URL: i.Link.Href, Type: i.Link.Type, Length: i.Link.Length}
}
if i.Author != nil {
item.Author = i.Author.Name
@ -122,7 +128,7 @@ func newRssItem(i *Item) *RssItem {
return item
}
// create a new RssFeed with a generic Feed struct's data
// RssFeed : create a new RssFeed with a generic Feed struct's data
func (r *Rss) RssFeed() *RssFeed {
pub := anyTimeFormat(time.RFC1123Z, r.Created, r.Updated)
build := anyTimeFormat(time.RFC1123Z, r.Updated)
@ -149,15 +155,15 @@ func (r *Rss) RssFeed() *RssFeed {
return channel
}
// return an XML-Ready object for an Rss object
func (r *Rss) FeedXml() interface{} {
// FeedXML : return an XML-Ready object for an Rss object
func (r *Rss) FeedXML() interface{} {
// only generate version 2.0 feeds for now
return r.RssFeed().FeedXml()
return r.RssFeed().FeedXML()
}
// return an XML-ready object for an RssFeed object
func (r *RssFeed) FeedXml() interface{} {
// FeedXML : return an XML-ready object for an RssFeed object
func (r *RssFeed) FeedXML() interface{} {
// modified for Nyaa
return &rssFeedXml{Version: "2.0", Channel: r, XMLNSTorrent: "http://xmlns.nyaa.pantsu.cat/torrent/"}
return &rssFeedXML{Version: "2.0", Channel: r, XMLNSTorrent: "http://xmlns.nyaa.pantsu.cat/torrent/"}
}

Voir le fichier

@ -7,9 +7,10 @@ import (
"fmt"
)
// UUID type
type UUID [16]byte
// create a new uuid v4
// NewUUID : create a new uuid v4
func NewUUID() *UUID {
u := &UUID{}
_, err := rand.Read(u[:16])

Voir le fichier

@ -6,6 +6,7 @@ import (
"github.com/NyaaPantsu/nyaa/config"
)
// Comment model
type Comment struct {
ID uint `gorm:"column:comment_id;primary_key"`
TorrentID uint `gorm:"column:torrent_id"`
@ -19,19 +20,22 @@ type Comment struct {
User *User `gorm:"AssociationForeignKey:UserID;ForeignKey:user_id"`
}
// Returns the total size of memory recursively allocated for this struct
// Size : Returns the total size of memory recursively allocated for this struct
func (c Comment) Size() int {
return (3 + 3*3 + 2 + 2 + len(c.Content)) * 8
}
// TableName : Return the name of comment table
func (c Comment) TableName() string {
return config.CommentsTableName
}
// Identifier : Return the identifier of the comment
func (c *Comment) Identifier() string { // We Can personalize the identifier but we would have to handle toggle read in that case
return c.Torrent.Identifier()
}
// OldComment model from old nyaa
type OldComment struct {
TorrentID uint `gorm:"column:torrent_id"`
Username string `gorm:"column:username"`
@ -41,11 +45,12 @@ type OldComment struct {
Torrent *Torrent `gorm:"ForeignKey:torrent_id"`
}
// Returns the total size of memory recursively allocated for this struct
// Size : Returns the total size of memory recursively allocated for this struct
func (c OldComment) Size() int {
return (1 + 2*2 + len(c.Username) + len(c.Content) + 3 + 1) * 8
}
// TableName : Return the name of OldComment table
func (c OldComment) TableName() string {
// cba to rename this in the db
// TODO: Update database schema to fix this hack

Voir le fichier

@ -7,6 +7,7 @@ import (
"github.com/NyaaPantsu/nyaa/util"
)
// DatabaseDump model
type DatabaseDump struct {
Date time.Time
Filesize int64
@ -14,6 +15,7 @@ type DatabaseDump struct {
TorrentLink string
}
// DatabaseDumpJSON : Json format of DatabaseDump model
type DatabaseDumpJSON struct {
Date string `json:"date"`
Filesize string `json:"filesize"`
@ -22,6 +24,7 @@ type DatabaseDumpJSON struct {
TorrentLink template.URL `json:"torrent"`
}
// ToJSON : convert to JSON DatabaseDump model
func (dump *DatabaseDump) ToJSON() DatabaseDumpJSON {
json := DatabaseDumpJSON{
Date: dump.Date.Format(time.RFC3339),

Voir le fichier

@ -5,6 +5,7 @@ import (
"github.com/zeebo/bencode"
)
// File model
type File struct {
ID uint `gorm:"column:file_id;primary_key"`
TorrentID uint `gorm:"column:torrent_id;unique_index:idx_tid_path"`
@ -13,20 +14,23 @@ type File struct {
Filesize int64 `gorm:"column:filesize"`
}
// TableName : Return the name of files table
func (f File) TableName() string {
return config.FilesTableName
}
// Returns the total size of memory allocated for this struct
// Size : Returns the total size of memory allocated for this struct
func (f File) Size() int {
return (2 + len(f.BencodedPath) + 1) * 8
}
// Path : Returns the path to the file
func (f *File) Path() (out []string) {
bencode.DecodeString(f.BencodedPath, &out)
return
}
// SetPath : Set the path of the file
func (f *File) SetPath(path []string) error {
encoded, err := bencode.EncodeString(path)
if err != nil {
@ -37,6 +41,7 @@ func (f *File) SetPath(path []string) error {
return nil
}
// Filename : Returns the filename of the file
func (f *File) Filename() string {
path := f.Path()
return path[len(path)-1]

Voir le fichier

@ -1,5 +1,7 @@
package model
// Language model
// Is it deprecated?
type Language struct {
ID uint `json:"id"`
Name string `json:"name"`

Voir le fichier

@ -4,20 +4,23 @@ import (
"github.com/NyaaPantsu/nyaa/config"
)
// Notification model
type Notification struct {
ID uint
Content string
Read bool
Identifier string
Url string
URL string
UserID uint
// User *User `gorm:"AssociationForeignKey:UserID;ForeignKey:user_id"` // Don't think that we need it here
}
// NewNotification : Create a new notification
func NewNotification(identifier string, c string, url string) Notification {
return Notification{Identifier: identifier, Content: c, Url: url}
return Notification{Identifier: identifier, Content: c, URL: url}
}
// TableName : Return the name of notification table
func (n *Notification) TableName() string {
return config.NotificationTableName
}

Voir le fichier

@ -6,6 +6,7 @@ import (
"github.com/NyaaPantsu/nyaa/config"
)
// TorrentReport model
// User can be null (anonymous reports)
// FIXME can't preload field Torrents for model.TorrentReport
type TorrentReport struct {
@ -20,11 +21,13 @@ type TorrentReport struct {
User *User `gorm:"AssociationForeignKey:UserID;ForeignKey:user_id"`
}
func (r TorrentReport) TableName() string {
// TableName : Return the name of torrent report table
func (report TorrentReport) TableName() string {
return config.ReportsTableName
}
type TorrentReportJson struct {
// TorrentReportJSON : Json struct of torrent report model
type TorrentReportJSON struct {
ID uint `json:"id"`
Description string `json:"description"`
Torrent TorrentJSON `json:"torrent"`
@ -46,23 +49,25 @@ func getReportDescription(d string) string {
return "???"
}
func (report *TorrentReport) ToJson() TorrentReportJson {
var t TorrentJSON = TorrentJSON{}
// ToJSON : conversion to json of a torrent report
func (report *TorrentReport) ToJSON() TorrentReportJSON {
t := TorrentJSON{}
if report.Torrent != nil { // FIXME: report.Torrent should never be nil
t = report.Torrent.ToJSON()
}
var u UserJSON = UserJSON{}
u := UserJSON{}
if report.User != nil {
u = report.User.ToJSON()
}
json := TorrentReportJson{report.ID, getReportDescription(report.Description), t, u}
json := TorrentReportJSON{report.ID, getReportDescription(report.Description), t, u}
return json
}
func TorrentReportsToJSON(reports []TorrentReport) []TorrentReportJson {
json := make([]TorrentReportJson, len(reports))
// TorrentReportsToJSON : Conversion of multiple reports to json
func TorrentReportsToJSON(reports []TorrentReport) []TorrentReportJSON {
json := make([]TorrentReportJSON, len(reports))
for i := range reports {
json[i] = reports[i].ToJson()
json[i] = reports[i].ToJSON()
}
return json
}

Voir le fichier

@ -16,13 +16,19 @@ import (
)
const (
TorrentStatusNormal = 1
TorrentStatusRemake = 2
// TorrentStatusNormal Int for Torrent status normal
TorrentStatusNormal = 1
// TorrentStatusRemake Int for Torrent status remake
TorrentStatusRemake = 2
// TorrentStatusTrusted Int for Torrent status trusted
TorrentStatusTrusted = 3
TorrentStatusAPlus = 4
// TorrentStatusAPlus Int for Torrent status a+
TorrentStatusAPlus = 4
// TorrentStatusBlocked Int for Torrent status locked
TorrentStatusBlocked = 5
)
// Feed struct
type Feed struct {
ID int
Name string
@ -31,6 +37,7 @@ type Feed struct {
Timestamp string
}
// Torrent model
type Torrent struct {
ID uint `gorm:"column:torrent_id;primary_key"`
Name string `gorm:"column:torrent_name"`
@ -59,7 +66,7 @@ type Torrent struct {
FileList []File `gorm:"ForeignKey:torrent_id"`
}
// Returns the total size of memory recursively allocated for this struct
// Size : Returns the total size of memory recursively allocated for this struct
// FIXME: doesn't go have sizeof or something nicer for this?
func (t Torrent) Size() (s int) {
s += 8 + // ints
@ -85,34 +92,42 @@ func (t Torrent) Size() (s int) {
}
// TableName : Return the name of torrents table
func (t Torrent) TableName() string {
return config.TorrentsTableName
}
// Identifier : Return the identifier of a torrent
func (t *Torrent) Identifier() string {
return "torrent_" + strconv.Itoa(int(t.ID))
}
// IsNormal : Return if a torrent status is normal
func (t Torrent) IsNormal() bool {
return t.Status == TorrentStatusNormal
}
// IsRemake : Return if a torrent status is normal
func (t Torrent) IsRemake() bool {
return t.Status == TorrentStatusRemake
}
// IsTrusted : Return if a torrent status is trusted
func (t Torrent) IsTrusted() bool {
return t.Status == TorrentStatusTrusted
}
// IsAPlus : Return if a torrent status is a+
func (t Torrent) IsAPlus() bool {
return t.Status == TorrentStatusAPlus
}
// IsBlocked : Return if a torrent status is locked
func (t *Torrent) IsBlocked() bool {
return t.Status == TorrentStatusBlocked
}
// IsDeleted : Return if a torrent status is deleted
func (t *Torrent) IsDeleted() bool {
return t.DeletedAt != nil
}
@ -143,12 +158,14 @@ func (t Torrent) DeleteFromESIndex(client *elastic.Client) error {
/* 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 {
// APIResultJSON for torrents in json for api
type APIResultJSON struct {
Torrents []TorrentJSON `json:"torrents"`
QueryRecordCount int `json:"queryRecordCount"`
TotalRecordCount int `json:"totalRecordCount"`
}
// CommentJSON for comment model in json
type CommentJSON struct {
Username string `json:"username"`
UserID int `json:"user_id"`
@ -157,11 +174,13 @@ type CommentJSON struct {
Date time.Time `json:"date"`
}
// FileJSON for file model in json
type FileJSON struct {
Path string `json:"path"`
Filesize int64 `json:"filesize"`
}
// TorrentJSON for torrent model in json for api
type TorrentJSON struct {
ID string `json:"id"`
Name string `json:"name"`
@ -264,7 +283,7 @@ func (t *Torrent) ToJSON() TorrentJSON {
/* Complete the functions when necessary... */
// Map Torrents to TorrentsToJSON without reallocations
// TorrentsToJSON : Map Torrents to TorrentsToJSON without reallocations
func TorrentsToJSON(t []Torrent) []TorrentJSON {
json := make([]TorrentJSON, len(t))
for i := range t {

Voir le fichier

@ -9,12 +9,17 @@ import (
)
const (
UserStatusBanned = -1
UserStatusMember = 0
UserStatusTrusted = 1
// UserStatusBanned : Int for User status banned
UserStatusBanned = -1
// UserStatusMember : Int for User status member
UserStatusMember = 0
// UserStatusTrusted : Int for User status trusted
UserStatusTrusted = 1
// UserStatusModerator : Int for User status moderator
UserStatusModerator = 2
)
// User model
type User struct {
ID uint `gorm:"column:user_id;primary_key"`
Username string `gorm:"column:username"`
@ -23,8 +28,8 @@ type User struct {
Status int `gorm:"column:status"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
ApiToken string `gorm:"column:api_token"`
ApiTokenExpiry time.Time `gorm:"column:api_token_expiry"`
APIToken string `gorm:"column:api_token"`
APITokenExpiry time.Time `gorm:"column:api_token_expiry"`
Language string `gorm:"column:language"`
UserSettings string `gorm:"column:settings"`
@ -40,6 +45,7 @@ type User struct {
Settings UserSettings `gorm:"-"` // We don't want to load settings everytime, stock it as a string, parse it when needed
}
// UserJSON : User model conversion in JSON
type UserJSON struct {
ID uint `json:"user_id"`
Username string `json:"username"`
@ -49,14 +55,14 @@ type UserJSON struct {
LikedCount int `json:"liked_count"`
}
// Returns the total size of memory recursively allocated for this struct
// Size : Returns the total size of memory recursively allocated for this struct
func (u User) Size() (s int) {
s += 4 + // ints
6*2 + // string pointers
4*3 + //time.Time
3*2 + // arrays
// string arrays
len(u.Username) + len(u.Password) + len(u.Email) + len(u.ApiToken) + len(u.MD5) + len(u.Language)
len(u.Username) + len(u.Password) + len(u.Email) + len(u.APIToken) + len(u.MD5) + len(u.Language)
s *= 8
// Ignoring foreign key users. Fuck them.
@ -64,20 +70,28 @@ func (u User) Size() (s int) {
return
}
func (u User) IsBanned() bool {
// IsBanned : Return true if user is banned
func (u *User) IsBanned() bool {
return u.Status == UserStatusBanned
}
func (u User) IsMember() bool {
// IsMember : Return true if user is member
func (u *User) IsMember() bool {
return u.Status == UserStatusMember
}
func (u User) IsTrusted() bool {
// IsTrusted : Return true if user is tusted
func (u *User) IsTrusted() bool {
return u.Status == UserStatusTrusted
}
func (u User) IsModerator() bool {
// IsModerator : Return true if user is moderator
func (u *User) IsModerator() bool {
return u.Status == UserStatusModerator
}
func (u User) GetUnreadNotifications() int {
// GetUnreadNotifications : Get unread notifications from a user
func (u *User) GetUnreadNotifications() int {
if u.UnreadNotifications == 0 {
for _, notif := range u.Notifications {
if !notif.Read {
@ -88,30 +102,35 @@ func (u User) GetUnreadNotifications() int {
return u.UnreadNotifications
}
// PublicUser : Is it Deprecated?
type PublicUser struct {
User *User
}
// different users following eachother
// UserFollows association table : different users following eachother
type UserFollows struct {
UserID uint `gorm:"column:user_id"`
FollowerID uint `gorm:"column:following"`
}
// UserUploadsOld model : Is it deprecated?
type UserUploadsOld struct {
Username string `gorm:"column:username"`
TorrentId uint `gorm:"column:torrent_id"`
TorrentID uint `gorm:"column:torrent_id"`
}
// UserSettings : Struct for user settings, not a model
type UserSettings struct {
Settings map[string]bool `json:"settings"`
}
// TableName : Return the name of OldComment table
func (c UserUploadsOld) TableName() string {
// is this needed here?
return config.UploadsOldTableName
}
// ToJSON : Conversion of a user model to json
func (u *User) ToJSON() UserJSON {
json := UserJSON{
ID: u.ID,
@ -126,18 +145,20 @@ func (u *User) ToJSON() UserJSON {
/* User Settings */
// Get a user setting by keyname
func (s *UserSettings) Get(key string) bool {
if val, ok := s.Settings[key]; ok {
return val
} else {
return config.DefaultUserSettings[key]
}
return config.DefaultUserSettings[key]
}
// GetSettings : get all user settings
func (s *UserSettings) GetSettings() map[string]bool {
return s.Settings
}
// Set a user setting by keyname
func (s *UserSettings) Set(key string, val bool) {
if s.Settings == nil {
s.Settings = make(map[string]bool)
@ -145,14 +166,16 @@ func (s *UserSettings) Set(key string, val bool) {
s.Settings[key] = val
}
// ToDefault : Set user settings to default
func (s *UserSettings) ToDefault() {
s.Settings = config.DefaultUserSettings
}
func (s *UserSettings) Initialize() {
func (s *UserSettings) initialize() {
s.Settings = make(map[string]bool)
}
// SaveSettings : Format settings into a json string for preparing before user insertion
func (u *User) SaveSettings() {
byteArray, err := json.Marshal(u.Settings)
@ -162,12 +185,13 @@ func (u *User) SaveSettings() {
u.UserSettings = string(byteArray)
}
// ParseSettings : Function to parse json string into usersettings struct, only parse if necessary
func (u *User) ParseSettings() {
if len(u.Settings.GetSettings()) == 0 && u.UserSettings != "" {
u.Settings.Initialize()
u.Settings.initialize()
json.Unmarshal([]byte(u.UserSettings), &u.Settings)
} else if len(u.Settings.GetSettings()) == 0 && u.UserSettings != "" {
u.Settings.Initialize()
u.Settings.initialize()
u.Settings.ToDefault()
}
}

Voir le fichier

@ -5,12 +5,13 @@ import (
"net/http"
)
// implements io.Closer that gracefully closes an http server
// GracefulHttpCloser : implements io.Closer that gracefully closes an http server
type GracefulHttpCloser struct {
Server *http.Server
Listener net.Listener
}
// Close method
func (c *GracefulHttpCloser) Close() error {
c.Listener.Close()
return c.Server.Shutdown(nil)

Voir le fichier

@ -13,6 +13,7 @@ type GracefulListener struct {
stop chan int
}
// Accept method
func (l *GracefulListener) Accept() (net.Conn, error) {
for {
c, err := l.listener.Accept()
@ -37,6 +38,7 @@ func (l *GracefulListener) Accept() (net.Conn, error) {
}
}
// Close method
func (l *GracefulListener) Close() (err error) {
l.listener.Close()
if l.stop != nil {
@ -45,6 +47,7 @@ func (l *GracefulListener) Close() (err error) {
return
}
// Addr method
func (l *GracefulListener) Addr() net.Addr {
return l.listener.Addr()
}

Voir le fichier

@ -77,7 +77,7 @@ func APIHandler(w http.ResponseWriter, r *http.Request) {
return
}
b := model.ApiResultJSON{
b := model.APIResultJSON{
Torrents: model.TorrentsToJSON(torrents),
}
b.QueryRecordCount = req.MaxPerPage
@ -95,7 +95,7 @@ func APIViewHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
torrent, err := torrentService.GetTorrentById(id)
torrent, err := torrentService.GetTorrentByID(id)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
@ -120,7 +120,7 @@ func APIViewHeadHandler(w http.ResponseWriter, r *http.Request) {
return
}
_, err = torrentService.GetRawTorrentById(uint(id))
_, err = torrentService.GetRawTorrentByID(uint(id))
if err != nil {
NotFoundHandler(w, r)
@ -142,7 +142,7 @@ func APIUploadHandler(w http.ResponseWriter, r *http.Request) {
}
if user.ID == 0 {
http.Error(w, apiService.ErrApiKey.Error(), http.StatusUnauthorized)
http.Error(w, apiService.ErrAPIKey.Error(), http.StatusUnauthorized)
return
}
@ -241,7 +241,7 @@ func APIUpdateHandler(w http.ResponseWriter, r *http.Request) {
contentType := r.Header.Get("Content-Type")
if contentType == "application/json" {
if user.ID == 0 {
http.Error(w, apiService.ErrApiKey.Error(), http.StatusForbidden)
http.Error(w, apiService.ErrAPIKey.Error(), http.StatusForbidden)
return
}
@ -258,7 +258,7 @@ func APIUpdateHandler(w http.ResponseWriter, r *http.Request) {
torrent := model.Torrent{}
db.ORM.Where("torrent_id = ?", id).First(&torrent)
if torrent.ID == 0 {
http.Error(w, apiService.ErrTorrentId.Error(), http.StatusBadRequest)
http.Error(w, apiService.ErrTorrentID.Error(), http.StatusBadRequest)
return
}
if torrent.UploaderID != 0 && torrent.UploaderID != user.ID { //&& user.Status != mod

Voir le fichier

@ -91,7 +91,7 @@ func (f *ReassignForm) ExecuteAction() (int, error) {
num := 0
for _, torrentID := range toBeChanged {
torrent, err2 := torrentService.GetRawTorrentById(torrentID)
torrent, err2 := torrentService.GetRawTorrentByID(torrentID)
if err2 == nil {
torrent.UploaderID = f.AssignTo
db.ORM.Model(&torrent).UpdateColumn(&torrent)
@ -261,7 +261,7 @@ func CommentsListPanel(w http.ResponseWriter, r *http.Request) {
// TorrentEditModPanel : Controller for editing a torrent after GET request
func TorrentEditModPanel(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
torrent, _ := torrentService.GetTorrentById(id)
torrent, _ := torrentService.GetTorrentByID(id)
messages := msg.GetMessages(r)
torrentJSON := torrent.ToJSON()
@ -281,7 +281,7 @@ func TorrentPostEditModPanel(w http.ResponseWriter, r *http.Request) {
var uploadForm uploadForm
id := r.URL.Query().Get("id")
messages := msg.GetMessages(r)
torrent, _ := torrentService.GetTorrentById(id)
torrent, _ := torrentService.GetTorrentByID(id)
if torrent.ID > 0 {
errUp := uploadForm.ExtractEditInfo(r)
if errUp != nil {
@ -309,7 +309,7 @@ func TorrentPostEditModPanel(w http.ResponseWriter, r *http.Request) {
func CommentDeleteModPanel(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
_, _ = userService.DeleteComment(id)
_, _ = commentService.DeleteComment(id)
url, _ := Router.Get("mod_clist").URL()
http.Redirect(w, r, url.String()+"?deleted", http.StatusSeeOther)
}
@ -567,7 +567,7 @@ func torrentManyAction(r *http.Request) {
if !messages.HasErrors() {
for _, torrentID := range torrentsSelected {
torrent, _ := torrentService.GetTorrentById(torrentID)
torrent, _ := torrentService.GetTorrentByID(torrentID)
if torrent.ID > 0 && userPermission.CurrentOrAdmin(currentUser, torrent.UploaderID) {
if action == "status" || action == "multiple" || action == "category" || action == "owner" {

Voir le fichier

@ -74,7 +74,7 @@ func RSSHandler(w http.ResponseWriter, r *http.Request) {
for i, torrent := range torrents {
torrentJSON := torrent.ToJSON()
feed.Items[i] = &feeds.Item{
Id: "https://" + config.WebAddress + "/view/" + torrentJSON.ID,
ID: "https://" + config.WebAddress + "/view/" + torrentJSON.ID,
Title: torrent.Name,
Link: &feeds.Link{Href: string(torrentJSON.Magnet)},
Description: string(torrentJSON.Description),

Voir le fichier

@ -84,7 +84,7 @@ type changeLanguageVariables struct {
type panelIndexVbs struct {
commonTemplateVariables
Torrents []model.Torrent
TorrentReports []model.TorrentReportJson
TorrentReports []model.TorrentReportJSON
Users []model.User
Comments []model.Comment
}

Voir le fichier

@ -343,8 +343,8 @@ func UserAPIKeyResetHandler(w http.ResponseWriter, r *http.Request) {
NotFoundHandler(w, r)
return
}
userProfile.ApiToken, _ = crypto.GenerateRandomToken32()
userProfile.ApiTokenExpiry = time.Unix(0, 0)
userProfile.APIToken, _ = crypto.GenerateRandomToken32()
userProfile.APITokenExpiry = time.Unix(0, 0)
_, errorUser = userService.UpdateUserCore(&userProfile)
if errorUser != nil {
messages.ImportFromError("errors", errorUser)

Voir le fichier

@ -34,7 +34,7 @@ func ViewHandler(w http.ResponseWriter, r *http.Request) {
messages.AddInfo("infos", "Torrent uploaded successfully!")
}
torrent, err := torrentService.GetTorrentById(id)
torrent, err := torrentService.GetTorrentByID(id)
if r.URL.Query()["notif"] != nil {
notifierService.ToggleReadNotification(torrent.Identifier(), user.ID)
@ -66,7 +66,7 @@ func ViewHeadHandler(w http.ResponseWriter, r *http.Request) {
return
}
_, err = torrentService.GetRawTorrentById(uint(id))
_, err = torrentService.GetRawTorrentByID(uint(id))
if err != nil {
NotFoundHandler(w, r)
@ -81,7 +81,7 @@ func PostCommentHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
torrent, err := torrentService.GetTorrentById(id)
torrent, err := torrentService.GetTorrentByID(id)
if err != nil {
NotFoundHandler(w, r)
return
@ -155,7 +155,7 @@ func ReportTorrentHandler(w http.ResponseWriter, r *http.Request) {
// TorrentEditUserPanel : Controller for editing a user torrent by a user, after GET request
func TorrentEditUserPanel(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
torrent, _ := torrentService.GetTorrentById(id)
torrent, _ := torrentService.GetTorrentByID(id)
messages := msg.GetMessages(r)
currentUser := getUser(r)
if userPermission.CurrentOrAdmin(currentUser, torrent.UploaderID) {
@ -178,7 +178,7 @@ func TorrentPostEditUserPanel(w http.ResponseWriter, r *http.Request) {
var uploadForm uploadForm
id := r.URL.Query().Get("id")
messages := msg.GetMessages(r)
torrent, _ := torrentService.GetTorrentById(id)
torrent, _ := torrentService.GetTorrentByID(id)
currentUser := getUser(r)
if torrent.ID > 0 && userPermission.CurrentOrAdmin(currentUser, torrent.UploaderID) {
errUp := uploadForm.ExtractEditInfo(r)
@ -216,7 +216,7 @@ func TorrentPostEditUserPanel(w http.ResponseWriter, r *http.Request) {
func TorrentDeleteUserPanel(w http.ResponseWriter, r *http.Request) {
id := r.URL.Query().Get("id")
currentUser := getUser(r)
torrent, _ := torrentService.GetTorrentById(id)
torrent, _ := torrentService.GetTorrentByID(id)
if userPermission.CurrentOrAdmin(currentUser, torrent.UploaderID) {
_, err := torrentService.DeleteTorrent(id)
if err == nil {

Voir le fichier

@ -27,12 +27,14 @@ type torrentsQuery struct {
Downloads int `json:"downloads"`
}
// TorrentsRequest struct
type TorrentsRequest struct {
Query torrentsQuery `json:"search"`
Page int `json:"page"`
MaxPerPage int `json:"limit"`
}
// TorrentRequest struct
//accept torrent files?
type TorrentRequest struct {
Name string `json:"name"`
@ -43,11 +45,13 @@ type TorrentRequest struct {
Description string `json:"description"`
}
// UpdateRequest struct
type UpdateRequest struct {
ID int `json:"id"`
Update TorrentRequest `json:"update"`
}
// ToParams : Convert a torrentsrequest to searchparams
func (r *TorrentsRequest) ToParams() serviceBase.WhereParams {
res := serviceBase.WhereParams{}
conditions := ""
@ -91,11 +95,11 @@ func validateSubCategory(r *TorrentRequest) (error, int) {
}
func validateMagnet(r *TorrentRequest) (error, int) {
magnetUrl, err := url.Parse(string(r.Magnet)) //?
magnetURL, err := url.Parse(string(r.Magnet)) //?
if err != nil {
return err, http.StatusInternalServerError
}
xt := magnetUrl.Query().Get("xt")
xt := magnetURL.Query().Get("xt")
if !strings.HasPrefix(xt, "urn:btih:") {
return ErrMagnet, http.StatusNotAcceptable
}
@ -132,6 +136,7 @@ func validateHash(r *TorrentRequest) (error, int) {
return nil, http.StatusOK
}
// ValidateUpload : Check if an upload is valid
func (r *TorrentRequest) ValidateUpload() (err error, code int) {
validators := []func(r *TorrentRequest) (error, int){
validateName,
@ -153,6 +158,7 @@ func (r *TorrentRequest) ValidateUpload() (err error, code int) {
return err, code
}
// ValidateMultipartUpload : Check if multipart upload is valid
func (r *TorrentRequest) ValidateMultipartUpload(req *http.Request) (int64, error, int) {
tfile, _, err := req.FormFile("torrent")
if err == nil {
@ -191,6 +197,7 @@ func (r *TorrentRequest) ValidateMultipartUpload(req *http.Request) (int64, erro
return 0, err, http.StatusInternalServerError
}
// ValidateUpdate : Check if an update is valid
func (r *TorrentRequest) ValidateUpdate() (err error, code int) {
validators := []func(r *TorrentRequest) (error, int){
validateName,
@ -217,6 +224,7 @@ func (r *TorrentRequest) ValidateUpdate() (err error, code int) {
return err, code
}
// UpdateTorrent : Update torrent model
//rewrite with reflect ?
func (r *UpdateRequest) UpdateTorrent(t *model.Torrent) {
if r.Update.Name != "" {

Voir le fichier

@ -2,11 +2,26 @@ package apiService
import "errors"
// ErrShortName : Error for invalid file name used by api
var ErrShortName = errors.New("file name should be at least 100 characters long")
// ErrCategory : Error for not found category used by api
var ErrCategory = errors.New("this category doesn't exist")
// ErrSubCategory : Error for not found sub category used by api
var ErrSubCategory = errors.New("this sub category doesn't exist")
// ErrMagnet : Error for incorrect magnet used by api
var ErrMagnet = errors.New("incorrect magnet")
// ErrHash : Error for incorrect hash used by api
var ErrHash = errors.New("incorrect hash")
var ErrApiKey = errors.New("incorrect api key")
var ErrTorrentId = errors.New("torrent with requested id doesn't exist")
// ErrAPIKey : Error for incorrect api key used by api
var ErrAPIKey = errors.New("incorrect api key")
// ErrTorrentID : Error for torrent id used by api
var ErrTorrentID = errors.New("torrent with requested id doesn't exist")
// ErrRights : Error for rights used by api
var ErrRights = errors.New("not enough rights for this request")

Voir le fichier

@ -11,7 +11,8 @@ import (
const lifetime = time.Minute * 20
var (
server = captcha.Server(captcha.StdWidth, captcha.StdHeight)
server = captcha.Server(captcha.StdWidth, captcha.StdHeight)
// ErrInvalidCaptcha : Error when captcha is invalid
ErrInvalidCaptcha = errors.New("invalid captcha")
)

Voir le fichier

@ -1,10 +1,14 @@
package commentService
import (
"errors"
"net/http"
"github.com/NyaaPantsu/nyaa/db"
"github.com/NyaaPantsu/nyaa/model"
)
// GetAllComments : Get all comments based on conditions
func GetAllComments(limit int, offset int, conditions string, values ...interface{}) ([]model.Comment, int) {
var comments []model.Comment
var nbComments int
@ -12,3 +16,16 @@ func GetAllComments(limit int, offset int, conditions string, values ...interfac
db.ORM.Preload("User").Limit(limit).Offset(offset).Where(conditions, values...).Find(&comments)
return comments, nbComments
}
// DeleteComment : Delete a comment
// FIXME : move this to comment service
func DeleteComment(id string) (int, error) {
var comment model.Comment
if db.ORM.First(&comment, id).RecordNotFound() {
return http.StatusNotFound, errors.New("Comment is not found")
}
if db.ORM.Delete(&comment).Error != nil {
return http.StatusInternalServerError, errors.New("Comment is not deleted")
}
return http.StatusOK, nil
}

Voir le fichier

@ -5,6 +5,7 @@ import (
"github.com/NyaaPantsu/nyaa/model"
)
// NotifyUser : Notify a user with a notification according to his settings
func NotifyUser(user *model.User, name string, msg string, url string, email bool) {
if user.ID > 0 {
notification := model.NewNotification(name, msg, url)
@ -17,10 +18,12 @@ func NotifyUser(user *model.User, name string, msg string, url string, email boo
}
}
// ToggleReadNotification : Make a notification as read according to its identifier
func ToggleReadNotification(identifier string, id uint) { //
db.ORM.Model(&model.Notification{}).Where("identifier = ? AND user_id = ?", identifier, id).Updates(model.Notification{Read: true})
}
// DeleteAllNotifications : Erase notifications from a user
func DeleteAllNotifications(id uint) { //
db.ORM.Where("user_id = ?", id).Delete(&model.Notification{})
}

Voir le fichier

@ -11,7 +11,7 @@ import (
"github.com/NyaaPantsu/nyaa/service"
)
// Return torrentReport in case we did modified it (ie: CreatedAt field)
// CreateTorrentReport : Return torrentReport in case we did modified it (ie: CreatedAt field)
func CreateTorrentReport(torrentReport model.TorrentReport) error {
if db.ORM.Create(&torrentReport).Error != nil {
return errors.New("TorrentReport was not created")
@ -19,10 +19,11 @@ func CreateTorrentReport(torrentReport model.TorrentReport) error {
return nil
}
// DeleteTorrentReport : Delete a torrent report by id
func DeleteTorrentReport(id uint) (error, int) {
var torrentReport model.TorrentReport
if db.ORM.First(&torrentReport, id).RecordNotFound() {
return errors.New("Trying to delete a torrent report that does not exists."), http.StatusNotFound
return errors.New("Trying to delete a torrent report that does not exists"), http.StatusNotFound
}
if err := db.ORM.Delete(&torrentReport).Error; err != nil {
return err, http.StatusInternalServerError
@ -30,10 +31,11 @@ func DeleteTorrentReport(id uint) (error, int) {
return nil, http.StatusOK
}
// DeleteDefinitelyTorrentReport : Delete definitely a torrent report by id
func DeleteDefinitelyTorrentReport(id uint) (error, int) {
var torrentReport model.TorrentReport
if db.ORM.Unscoped().First(&torrentReport, id).RecordNotFound() {
return errors.New("Trying to delete a torrent report that does not exists."), http.StatusNotFound
return errors.New("Trying to delete a torrent report that does not exists"), http.StatusNotFound
}
if err := db.ORM.Unscoped().Delete(&torrentReport).Error; err != nil {
return err, http.StatusInternalServerError
@ -77,10 +79,12 @@ func getTorrentReportsOrderBy(parameters *serviceBase.WhereParams, orderBy strin
return
}
// GetTorrentReportsOrderBy : Get torrents based on search parameters with order
func GetTorrentReportsOrderBy(parameters *serviceBase.WhereParams, orderBy string, limit int, offset int) ([]model.TorrentReport, int, error) {
return getTorrentReportsOrderBy(parameters, orderBy, limit, offset, true)
}
// GetAllTorrentReports : Get all torrents
func GetAllTorrentReports(limit int, offset int) ([]model.TorrentReport, int, error) {
return GetTorrentReportsOrderBy(nil, "", limit, offset)
}

Voir le fichier

@ -1,10 +1,12 @@
package serviceBase
// WhereParams struct for search
type WhereParams struct {
Conditions string // Ex : name LIKE ? AND category_id LIKE ?
Params []interface{}
}
// CreateWhereParams : function to create WhereParams struct for search
func CreateWhereParams(conditions string, params ...interface{}) WhereParams {
whereParams := WhereParams{
Conditions: conditions,

Voir le fichier

@ -1,11 +0,0 @@
package torrentform
type PanelPost struct {
Name string `form:"name" needed:"true" len_min:"3" len_max:"20"`
Hash string `form:"hash" needed:"true"`
Category int `form:"cat" needed:"true"`
Sub_Category int `form:"subcat"`
Status string `form:"status" needed:"true"`
Description string `form:"desc"`
WebsiteLink string `form:"website"`
}

Voir le fichier

@ -1,6 +1,10 @@
package metainfoFetcher
import (
"math"
"sync"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/db"
"github.com/NyaaPantsu/nyaa/model"
@ -10,11 +14,9 @@ import (
"github.com/anacrolix/torrent"
"github.com/anacrolix/torrent/metainfo"
"golang.org/x/time/rate"
"math"
"sync"
"time"
)
// MetainfoFetcher Struct
type MetainfoFetcher struct {
torrentClient *torrent.Client
results chan Result
@ -34,6 +36,7 @@ type MetainfoFetcher struct {
wg sync.WaitGroup
}
// New : Creates a MetainfoFetcher struct
func New(fetcherConfig *config.MetainfoFetcherConfig) (fetcher *MetainfoFetcher, err error) {
clientConfig := torrent.Config{}
// Well, it seems this is the right way to convert speed -> rate.Limiter
@ -306,12 +309,14 @@ func (fetcher *MetainfoFetcher) run() {
}
}
// RunAsync method
func (fetcher *MetainfoFetcher) RunAsync() {
fetcher.wg.Add(1)
go fetcher.run()
}
// Close method
func (fetcher *MetainfoFetcher) Close() error {
fetcher.queueMutex.Lock()
defer fetcher.queueMutex.Unlock()
@ -328,6 +333,7 @@ func (fetcher *MetainfoFetcher) Close() error {
return nil
}
// Wait method
func (fetcher *MetainfoFetcher) Wait() {
fetcher.wg.Wait()
}

Voir le fichier

@ -2,26 +2,30 @@ package metainfoFetcher
import (
"errors"
"strings"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/model"
"github.com/NyaaPantsu/nyaa/util"
"github.com/anacrolix/torrent/metainfo"
"strings"
"time"
)
// FetchOperation struct
type FetchOperation struct {
fetcher *MetainfoFetcher
torrent model.Torrent
done chan int
}
// Result struct
type Result struct {
operation *FetchOperation
err error
info *metainfo.Info
}
// NewFetchOperation : Creates a new fetchoperation
func NewFetchOperation(fetcher *MetainfoFetcher, dbEntry model.Torrent) (op *FetchOperation) {
op = &FetchOperation{
fetcher: fetcher,
@ -31,7 +35,7 @@ func NewFetchOperation(fetcher *MetainfoFetcher, dbEntry model.Torrent) (op *Fet
return
}
// Should be started from a goroutine somewhere
// Start : Should be started from a goroutine somewhere
func (op *FetchOperation) Start(out chan Result) {
defer op.fetcher.wg.Done()

Voir le fichier

@ -21,7 +21,7 @@ import (
*
*/
// don't need raw SQL once we get MySQL
// GetFeeds : don't need raw SQL once we get MySQL
func GetFeeds() (result []model.Feed, err error) {
result = make([]model.Feed, 0, 50)
rows, err := db.ORM.DB().
@ -48,18 +48,19 @@ func GetFeeds() (result []model.Feed, err error) {
return
}
func GetTorrentById(id string) (torrent model.Torrent, err error) {
// GetTorrentByID : get a torrent with its id
func GetTorrentByID(id string) (torrent model.Torrent, err error) {
// Postgres DB integer size is 32-bit
id_int, err := strconv.ParseInt(id, 10, 32)
idInt, err := strconv.ParseInt(id, 10, 32)
if err != nil {
return
}
tmp := db.ORM.Where("torrent_id = ?", id).Preload("Comments")
if id_int > config.LastOldTorrentID {
if idInt > config.LastOldTorrentID {
tmp = tmp.Preload("FileList")
}
if id_int <= config.LastOldTorrentID && !config.IsSukebei() {
if idInt <= config.LastOldTorrentID && !config.IsSukebei() {
// only preload old comments if they could actually exist
tmp = tmp.Preload("OldComments")
}
@ -68,7 +69,7 @@ func GetTorrentById(id string) (torrent model.Torrent, err error) {
return
}
if tmp.Find(&torrent).RecordNotFound() {
err = errors.New("Article is not found.")
err = errors.New("Article is not found")
return
}
// GORM relly likes not doing its job correctly
@ -93,25 +94,29 @@ func GetTorrentById(id string) (torrent model.Torrent, err error) {
return
}
// GetRawTorrentByID : Get torrent with id without user or comments
// won't fetch user or comments
func GetRawTorrentById(id uint) (torrent model.Torrent, err error) {
func GetRawTorrentByID(id uint) (torrent model.Torrent, err error) {
err = nil
if db.ORM.Where("torrent_id = ?", id).Find(&torrent).RecordNotFound() {
err = errors.New("Article is not found.")
err = errors.New("Article is not found")
}
return
}
// GetTorrentsOrderByNoCount : Get torrents based on search without counting and user
func GetTorrentsOrderByNoCount(parameters *serviceBase.WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, err error) {
torrents, _, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, false, false, false)
return
}
// GetTorrentsOrderBy : Get torrents based on search without user
func GetTorrentsOrderBy(parameters *serviceBase.WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, count int, err error) {
torrents, count, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, true, false, false)
return
}
// GetTorrentsWithUserOrderBy : Get torrents based on search with user
func GetTorrentsWithUserOrderBy(parameters *serviceBase.WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, count int, err error) {
torrents, count, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, true, true, false)
return
@ -179,30 +184,34 @@ func GetTorrents(parameters serviceBase.WhereParams, limit int, offset int) ([]m
return GetTorrentsOrderBy(&parameters, "", limit, offset)
}
// Get Torrents with where parameters but no limit and order by default (get all the torrents corresponding in the db)
// GetTorrentsDB : Get Torrents with where parameters but no limit and order by default (get all the torrents corresponding in the db)
func GetTorrentsDB(parameters serviceBase.WhereParams) ([]model.Torrent, int, error) {
return GetTorrentsOrderBy(&parameters, "", 0, 0)
}
// GetAllTorrentsOrderBy : Get all torrents ordered by parameters
func GetAllTorrentsOrderBy(orderBy string, limit int, offset int) ([]model.Torrent, int, error) {
return GetTorrentsOrderBy(nil, orderBy, limit, offset)
}
// GetAllTorrents : Get all torrents without order
func GetAllTorrents(limit int, offset int) ([]model.Torrent, int, error) {
return GetTorrentsOrderBy(nil, "", limit, offset)
}
// GetAllTorrentsDB : Get all torrents
func GetAllTorrentsDB() ([]model.Torrent, int, error) {
return GetTorrentsOrderBy(nil, "", 0, 0)
}
// DeleteTorrent : delete a torrent based on id
func DeleteTorrent(id string) (int, error) {
var torrent model.Torrent
if db.ORM.First(&torrent, id).RecordNotFound() {
return http.StatusNotFound, errors.New("Torrent is not found.")
return http.StatusNotFound, errors.New("Torrent is not found")
}
if db.ORM.Delete(&torrent).Error != nil {
return http.StatusInternalServerError, errors.New("Torrent was not deleted.")
return http.StatusInternalServerError, errors.New("Torrent was not deleted")
}
// TODO Don't create a new client for each request
@ -220,13 +229,14 @@ func DeleteTorrent(id string) (int, error) {
return http.StatusOK, nil
}
// DefinitelyDeleteTorrent : deletes definitely a torrent based on id
func DefinitelyDeleteTorrent(id string) (int, error) {
var torrent model.Torrent
if db.ORM.Unscoped().Model(&torrent).First(&torrent, id).RecordNotFound() {
return http.StatusNotFound, errors.New("Torrent is not found.")
return http.StatusNotFound, errors.New("Torrent is not found")
}
if db.ORM.Unscoped().Model(&torrent).Delete(&torrent).Error != nil {
return http.StatusInternalServerError, errors.New("Torrent was not deleted.")
return http.StatusInternalServerError, errors.New("Torrent was not deleted")
}
// TODO Don't create a new client for each request
@ -244,10 +254,11 @@ func DefinitelyDeleteTorrent(id string) (int, error) {
return http.StatusOK, nil
}
// ToggleBlockTorrent ; Lock/Unlock a torrent based on id
func ToggleBlockTorrent(id string) (model.Torrent, int, error) {
var torrent model.Torrent
if db.ORM.Unscoped().Model(&torrent).First(&torrent, id).RecordNotFound() {
return torrent, http.StatusNotFound, errors.New("Torrent is not found.")
return torrent, http.StatusNotFound, errors.New("Torrent is not found")
}
if torrent.Status == model.TorrentStatusBlocked {
torrent.Status = model.TorrentStatusNormal
@ -255,14 +266,15 @@ func ToggleBlockTorrent(id string) (model.Torrent, int, error) {
torrent.Status = model.TorrentStatusBlocked
}
if db.ORM.Unscoped().Model(&torrent).UpdateColumn(&torrent).Error != nil {
return torrent, http.StatusInternalServerError, errors.New("Torrent was not updated.")
return torrent, http.StatusInternalServerError, errors.New("Torrent was not updated")
}
return torrent, http.StatusOK, nil
}
// UpdateTorrent : Update a torrent based on model
func UpdateTorrent(torrent model.Torrent) (int, error) {
if db.ORM.Model(&torrent).UpdateColumn(&torrent).Error != nil {
return http.StatusInternalServerError, errors.New("Torrent was not updated.")
return http.StatusInternalServerError, errors.New("Torrent was not updated")
}
// TODO Don't create a new client for each request
@ -281,6 +293,7 @@ func UpdateTorrent(torrent model.Torrent) (int, error) {
return http.StatusOK, nil
}
// GetDeletedTorrents : Gets deleted torrents based on search params
func GetDeletedTorrents(parameters *serviceBase.WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, count int, err error) {
torrents, count, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, true, true, true)
return

Voir le fichier

@ -7,6 +7,7 @@ import (
"github.com/NyaaPantsu/nyaa/model"
)
// CheckTrackers : Check if there is good trackers in torrent
func CheckTrackers(trackers []string) bool {
// TODO: move to runtime configuration
var deadTrackers = []string{ // substring matches!
@ -40,6 +41,7 @@ func CheckTrackers(trackers []string) bool {
return numGood > 0
}
// IsUploadEnabled : Check if upload is enabled in config
func IsUploadEnabled(u model.User) bool {
if config.UploadsDisabled {
if config.AdminsAreStillAllowedTo && u.IsModerator() {

Voir le fichier

@ -2,6 +2,10 @@ package userService
import (
"errors"
"net/http"
"strconv"
"time"
"github.com/NyaaPantsu/nyaa/db"
"github.com/NyaaPantsu/nyaa/model"
formStruct "github.com/NyaaPantsu/nyaa/service/user/form"
@ -11,13 +15,12 @@ import (
"github.com/gorilla/context"
"github.com/gorilla/securecookie"
"golang.org/x/crypto/bcrypt"
"net/http"
"strconv"
"time"
)
const (
CookieName = "session"
// CookieName : Name of cookie
CookieName = "session"
// UserContextKey : key for user context
UserContextKey = "user"
)
@ -26,30 +29,32 @@ var cookieHandler = securecookie.New(
securecookie.GenerateRandomKey(64),
securecookie.GenerateRandomKey(32))
// Encoding & Decoding of the cookie value
func DecodeCookie(cookie_value string) (uint, error) {
// DecodeCookie : Encoding & Decoding of the cookie value
func DecodeCookie(cookieValue string) (uint, error) {
value := make(map[string]string)
err := cookieHandler.Decode(CookieName, cookie_value, &value)
err := cookieHandler.Decode(CookieName, cookieValue, &value)
if err != nil {
return 0, err
}
time_int, _ := strconv.ParseInt(value["t"], 10, 0)
if timeHelper.IsExpired(time.Unix(time_int, 0)) {
timeInt, _ := strconv.ParseInt(value["t"], 10, 0)
if timeHelper.IsExpired(time.Unix(timeInt, 0)) {
return 0, errors.New("Cookie is expired")
}
ret, err := strconv.ParseUint(value["u"], 10, 0)
return uint(ret), err
}
func EncodeCookie(user_id uint) (string, error) {
// EncodeCookie : Encoding of the cookie value
func EncodeCookie(userID uint) (string, error) {
validUntil := timeHelper.FewDaysLater(7) // 1 week
value := map[string]string{
"u": strconv.FormatUint(uint64(user_id), 10),
"u": strconv.FormatUint(uint64(userID), 10),
"t": strconv.FormatInt(validUntil.Unix(), 10),
}
return cookieHandler.Encode(CookieName, value)
}
// ClearCookie : Erase cookie session
func ClearCookie(w http.ResponseWriter) (int, error) {
cookie := &http.Cookie{
Name: CookieName,
@ -133,21 +138,20 @@ func CurrentUser(r *http.Request) (model.User, error) {
}
encoded = cookie.Value
}
user_id, err := DecodeCookie(encoded)
userID, err := DecodeCookie(encoded)
if err != nil {
return user, err
}
userFromContext := getUserFromContext(r)
if userFromContext.ID > 0 && user_id == userFromContext.ID {
if userFromContext.ID > 0 && userID == userFromContext.ID {
user = userFromContext
} else {
if db.ORM.Preload("Notifications").Where("user_id = ?", user_id).First(&user).RecordNotFound() { // We only load unread notifications
if db.ORM.Preload("Notifications").Where("user_id = ?", userID).First(&user).RecordNotFound() { // We only load unread notifications
return user, errors.New("User not found")
} else {
setUserToContext(r, user)
}
setUserToContext(r, user)
}
if user.IsBanned() {

Voir le fichier

@ -7,11 +7,12 @@ import (
msg "github.com/NyaaPantsu/nyaa/util/messages"
)
const EMAIL_REGEX = `(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})`
const USERNAME_REGEX = `(\W)`
const emailRegex = `(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})`
const usernameRegex = `(\W)`
// EmailValidation : Check if an email is valid
func EmailValidation(email string, mes *msg.Messages) bool {
exp, errorRegex := regexp.Compile(EMAIL_REGEX)
exp, errorRegex := regexp.Compile(emailRegex)
if regexpCompiled := log.CheckError(errorRegex); regexpCompiled {
if exp.MatchString(email) {
return true
@ -21,8 +22,9 @@ func EmailValidation(email string, mes *msg.Messages) bool {
return false
}
// ValidateUsername : Check if a username is valid
func ValidateUsername(username string, mes *msg.Messages) bool {
exp, errorRegex := regexp.Compile(USERNAME_REGEX)
exp, errorRegex := regexp.Compile(usernameRegex)
if regexpCompiled := log.CheckError(errorRegex); regexpCompiled {
if exp.MatchString(username) {
mes.AddError("username", "Username contains illegal characters")
@ -34,15 +36,7 @@ func ValidateUsername(username string, mes *msg.Messages) bool {
return true
}
func NewErrors() map[string][]string {
err := make(map[string][]string)
return err
}
func NewInfos() map[string][]string {
infos := make(map[string][]string)
return infos
}
// IsAgreed : Check if terms and conditions are valid
func IsAgreed(termsAndConditions string) bool { // TODO: Inline function
return termsAndConditions == "1"
}
@ -65,13 +59,13 @@ type LoginForm struct {
// 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"`
Language string `form:"language" default:"en-us"`
CurrentPassword string `form:"current_password" len_min:"6" len_max:"72" omit:"true"`
Password string `form:"password" len_min:"6" len_max:"72" equalInput:"Confirm_Password"`
Confirm_Password string `form:"password_confirmation" omit:"true"`
Status int `form:"status" default:"0"`
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
Email string `form:"email"`
Language string `form:"language" default:"en-us"`
CurrentPassword string `form:"current_password" len_min:"6" len_max:"72" omit:"true"`
Password string `form:"password" len_min:"6" len_max:"72" equalInput:"ConfirmPassword"`
ConfirmPassword string `form:"password_confirmation" omit:"true"`
Status int `form:"status" default:"0"`
}
// UserSettingsForm is used when updating a user.

Voir le fichier

@ -23,11 +23,13 @@ func CurrentUserIdentical(user *model.User, userID uint) bool {
return user.ID == userID
}
// NeedsCaptcha : Check if a user needs captcha
func NeedsCaptcha(user *model.User) bool {
// Trusted members & Moderators don't
return !(user.IsTrusted() || user.IsModerator())
}
// GetRole : Get the status/role of a user
func GetRole(user *model.User) string {
switch user.Status {
case model.UserStatusBanned:
@ -42,6 +44,7 @@ func GetRole(user *model.User) string {
return "Member"
}
// IsFollower : Check if a user is following another
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)

Voir le fichier

@ -17,12 +17,15 @@ import (
"golang.org/x/crypto/bcrypt"
)
// NewCurrentUserRetriever create CurrentUserRetriever Struct for languages
func NewCurrentUserRetriever() *CurrentUserRetriever {
return &CurrentUserRetriever{}
}
// CurrentUserRetriever struct for languages
type CurrentUserRetriever struct{}
// RetrieveCurrentUser retrieve current user for languages
func (*CurrentUserRetriever) RetrieveCurrentUser(r *http.Request) (model.User, error) {
user, _, err := RetrieveCurrentUser(r)
return user, err
@ -51,6 +54,7 @@ func SuggestUsername(username string) string {
return usernameCandidate
}
// CheckEmail : check if email is in database
func CheckEmail(email string) bool {
if len(email) == 0 {
return false
@ -84,8 +88,8 @@ func CreateUserFromForm(registrationForm formStruct.RegistrationForm) (model.Use
user.Settings.ToDefault()
user.SaveSettings()
// currently unused but needs to be set:
user.ApiToken, _ = crypto.GenerateRandomToken32()
user.ApiTokenExpiry = time.Unix(0, 0)
user.APIToken, _ = crypto.GenerateRandomToken32()
user.APITokenExpiry = time.Unix(0, 0)
if db.ORM.Create(&user).Error != nil {
return user, errors.New("user not created")
@ -232,7 +236,7 @@ func DeleteUser(w http.ResponseWriter, currentUser *model.User, id string) (int,
return http.StatusNotFound, errors.New("user not found")
}
if user.ID == 0 {
return http.StatusInternalServerError, errors.New("You can't delete that!")
return http.StatusInternalServerError, errors.New("You can't delete that")
}
if db.ORM.Delete(&user).Error != nil {
return http.StatusInternalServerError, errors.New("user not deleted")
@ -282,6 +286,7 @@ func RetrieveUserByUsername(username string) (*model.PublicUser, string, int, er
return &model.PublicUser{User: &user}, username, http.StatusOK, nil
}
// RetrieveOldUploadsByUsername retrieves olduploads by username
func RetrieveOldUploadsByUsername(username string) ([]uint, error) {
var ret []uint
var tmp []*model.UserUploadsOld
@ -290,7 +295,7 @@ func RetrieveOldUploadsByUsername(username string) ([]uint, error) {
return ret, err
}
for _, tmp2 := range tmp {
ret = append(ret, tmp2.TorrentId)
ret = append(ret, tmp2.TorrentID)
}
return ret, nil
}
@ -318,12 +323,15 @@ func RetrieveUsersForAdmin(limit int, offset int) ([]model.User, int) {
return users, nbUsers
}
// GetLiked : Gets who is following the user
func GetLiked(user *model.User) *model.User {
var liked []model.User
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.Liked = liked
return user
}
// GetLikings : Gets who is followed by the user
func GetLikings(user *model.User) *model.User {
var 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)
@ -341,6 +349,7 @@ func CreateUserAuthentication(w http.ResponseWriter, r *http.Request) (int, erro
return status, err
}
// SetFollow : Makes a user follow another
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}
@ -348,20 +357,10 @@ func SetFollow(user *model.User, follower *model.User) {
}
}
// RemoveFollow : Remove a user following another
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}
db.ORM.Delete(&userFollows)
}
}
func DeleteComment(id string) (int, error) {
var comment model.Comment
if db.ORM.First(&comment, id).RecordNotFound() {
return http.StatusNotFound, errors.New("Comment is not found.")
}
if db.ORM.Delete(&comment).Error != nil {
return http.StatusInternalServerError, errors.New("Comment is not deleted.")
}
return http.StatusOK, nil
}

Voir le fichier

@ -18,15 +18,15 @@ import (
var verificationHandler = securecookie.New(config.EmailTokenHashKey, nil)
// SendEmailVerfication sends an email verification token via email.
// SendEmailVerification sends an email verification token via email.
func SendEmailVerification(to string, token string) error {
T, err := languages.GetDefaultTfunc()
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)
contentHTML := 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, contentHTML)
}
// SendVerificationToUser sends an email verification token to user.
@ -54,15 +54,15 @@ func EmailVerification(token string, w http.ResponseWriter) (int, error) {
err := verificationHandler.Decode("", token, &value)
if err != nil {
fmt.Printf("%+v\n", err)
return http.StatusForbidden, errors.New("Token is not valid.")
return http.StatusForbidden, errors.New("Token is not valid")
}
time_int, _ := strconv.ParseInt(value["t"], 10, 0)
if timeHelper.IsExpired(time.Unix(time_int, 0)) {
return http.StatusForbidden, errors.New("Token has expired.")
timeInt, _ := strconv.ParseInt(value["t"], 10, 0)
if timeHelper.IsExpired(time.Unix(timeInt, 0)) {
return http.StatusForbidden, errors.New("Token has expired")
}
var user model.User
if db.ORM.Where("user_id = ?", value["u"]).First(&user).RecordNotFound() {
return http.StatusNotFound, errors.New("User is not found.")
return http.StatusNotFound, errors.New("User is not found")
}
user.Email = value["e"]
return UpdateUserCore(&user)

Voir le fichier

@ -10,7 +10,7 @@
<div class="user-edit">
<form role="form" method="POST">
<label class="input-label">{{call $.T "api_token" }}:</label>
<p style="font-family: monospace;">{{.ApiToken}}</p>
<p style="font-family: monospace;">{{.APIToken}}</p>
<button class="btn btn-default" href="{{ genRoute "user_profile_apireset" "id" (print .ID) "username" .Username }}" value="Reset Api key"></button>
<label class="input-label">{{ call $.T "email_address" }}:</label> <br>
<input class="form-input" type="text" name="email" id="email" value="{{.Email}}"> <br>

Voir le fichier

@ -6,6 +6,7 @@ import (
var categories map[string]string
// GetCategories : function to get all categories depending on the actual website from config/categories.go
func GetCategories() map[string]string {
if categories != nil {
return categories
@ -20,11 +21,13 @@ func GetCategories() map[string]string {
return categories
}
// CategoryExists : Check if a category exist in config
func CategoryExists(category string) bool {
_, exists := GetCategories()[category]
return exists
}
// GetCategoriesSelect : Format categories in map ordered alphabetically
func GetCategoriesSelect(keepParent bool) map[string]string {
categories := GetCategories()
catSelect := make(map[string]string, len(categories))

Voir le fichier

@ -7,6 +7,7 @@ import (
"strings"
)
// GenerateMD5Hash : Generate a md5 hash from a string
func GenerateMD5Hash(str string) (string, error) {
str = strings.ToLower(strings.TrimSpace(str))
hash := md5.New()
@ -17,14 +18,17 @@ func GenerateMD5Hash(str string) (string, error) {
return fmt.Sprintf("%x", hash.Sum(nil)), nil
}
// GenerateRandomToken16 : Generates a random token 16bits long
func GenerateRandomToken16() (string, error) {
return GenerateRandomToken(16)
}
// GenerateRandomToken32 : Generates a random token 32bits long
func GenerateRandomToken32() (string, error) {
return GenerateRandomToken(32)
}
// GenerateRandomToken : Generates a random token int n long
func GenerateRandomToken(n int) (string, error) {
token := make([]byte, n)
_, err := rand.Read(token)

Voir le fichier

@ -8,17 +8,20 @@ import (
gomail "gopkg.in/gomail.v2"
)
type EmailError error
// Error type
type Error error
var (
mailer = InitGomail()
)
// InitGomail : init the gomail dialer
func InitGomail() *gomail.Dialer {
newMailer := gomail.NewDialer(config.EmailHost, config.EmailPort, config.EmailUsername, config.EmailPassword)
return newMailer
}
// SendEmailFromAdmin : send an email from system with email address in config/email.go
func SendEmailFromAdmin(to string, subject string, body string, bodyHTML string) error {
msg := gomail.NewMessage()
msg.SetHeader("From", config.EmailFrom)
@ -39,6 +42,7 @@ func SendEmailFromAdmin(to string, subject string, body string, bodyHTML string)
return nil
}
// SendTestEmail : function to send a test email to email address in config/email.go
func SendTestEmail() error {
msg := gomail.NewMessage()
msg.SetHeader("From", config.EmailFrom)

Voir le fichier

@ -1,17 +1,20 @@
package filelist
import (
"strings"
"github.com/NyaaPantsu/nyaa/model"
"github.com/bradfitz/slice"
"strings"
)
// FileListFolder struct
type FileListFolder struct {
Folders []*FileListFolder
Files []model.File
FolderName string
}
// FileListToFolder convert a filelist to filelistfolder
func FileListToFolder(fileList []model.File, folderName string) (out *FileListFolder) {
out = &FileListFolder{
Folders: make([]*FileListFolder, 0),
@ -52,6 +55,7 @@ func FileListToFolder(fileList []model.File, folderName string) (out *FileListFo
return
}
// TotalSize : gives the total size of filelistfolder
func (f *FileListFolder) TotalSize() (out int64) {
out = 0
for _, folder := range f.Folders {

Voir le fichier

@ -4,6 +4,7 @@ import (
"fmt"
)
// FormatFilesize : format file size
func FormatFilesize(bytes int64) string {
var unit string
var value float64

Voir le fichier

@ -14,19 +14,20 @@ import (
"github.com/nicksnyder/go-i18n/i18n/language"
)
// this interface is required to prevent a cyclic import between the languages and userService package.
// UserRetriever : this interface is required to prevent a cyclic import between the languages and userService package.
type UserRetriever interface {
RetrieveCurrentUser(r *http.Request) (model.User, error)
}
// TemplateTfunc : T func used in template
type TemplateTfunc func(string, ...interface{}) template.HTML
var (
defaultLanguage string = config.DefaultI18nConfig.DefaultLanguage
userRetriever UserRetriever = nil
defaultLanguage = config.DefaultI18nConfig.DefaultLanguage
userRetriever UserRetriever
)
// Initialize the languages translation
// InitI18n : Initialize the languages translation
func InitI18n(conf config.I18nConfig, retriever UserRetriever) error {
defaultLanguage = conf.DefaultLanguage
userRetriever = retriever
@ -52,11 +53,12 @@ func InitI18n(conf config.I18nConfig, retriever UserRetriever) error {
return nil
}
// GetDefaultLanguage : returns the default language from config
func GetDefaultLanguage() string {
return defaultLanguage
}
// When go-i18n finds a language with >0 translations, it uses it as the Tfunc
// TfuncAndLanguageWithFallback : When go-i18n finds a language with >0 translations, it uses it as the Tfunc
// However, if said language has a missing translation, it won't fallback to the "main" language
func TfuncAndLanguageWithFallback(language string, languages ...string) (i18n.TranslateFunc, *language.Language, error) {
fallbackLanguage := GetDefaultLanguage()
@ -81,6 +83,7 @@ func TfuncAndLanguageWithFallback(language string, languages ...string) (i18n.Tr
return translateFunction, tLang, err1
}
// GetAvailableLanguages : Get languages available on the website
func GetAvailableLanguages() (languages map[string]string) {
languages = make(map[string]string)
var T i18n.TranslateFunc
@ -97,10 +100,12 @@ func GetAvailableLanguages() (languages map[string]string) {
return
}
// GetDefaultTfunc : Gets T func from default language
func GetDefaultTfunc() (i18n.TranslateFunc, error) {
return i18n.Tfunc(defaultLanguage)
}
// GetTfuncAndLanguageFromRequest : Gets the T func and chosen language from the request
func GetTfuncAndLanguageFromRequest(r *http.Request) (T i18n.TranslateFunc, Tlang *language.Language) {
userLanguage := ""
user, _ := getCurrentUser(r)
@ -120,6 +125,7 @@ func GetTfuncAndLanguageFromRequest(r *http.Request) (T i18n.TranslateFunc, Tlan
return
}
// GetTfuncFromRequest : Gets the T func from the request
func GetTfuncFromRequest(r *http.Request) TemplateTfunc {
T, _ := GetTfuncAndLanguageFromRequest(r)
return func(id string, args ...interface{}) template.HTML {

Voir le fichier

@ -10,7 +10,7 @@ import (
func TestInitI18n(t *testing.T) {
conf := config.DefaultI18nConfig
conf.TranslationsDirectory = path.Join("..", "..", conf.TranslationsDirectory)
var retriever UserRetriever = nil // not required during initialization
var retriever UserRetriever // not required during initialization
err := InitI18n(conf, retriever)
if err != nil {

Voir le fichier

@ -9,6 +9,7 @@ import (
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
// LumberJackLogger : Initialize logger
func LumberJackLogger(filePath string, maxSize int, maxBackups int, maxAge int) *lumberjack.Logger {
return &lumberjack.Logger{
Filename: filePath,
@ -18,18 +19,21 @@ func LumberJackLogger(filePath string, maxSize int, maxBackups int, maxAge int)
}
}
// InitLogToStdoutDebug : set logrus to debug param
func InitLogToStdoutDebug() {
logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true})
logrus.SetOutput(os.Stdout)
logrus.SetLevel(logrus.DebugLevel)
}
// InitLogToStdout : set logrus to stdout
func InitLogToStdout() {
logrus.SetFormatter(&logrus.TextFormatter{})
logrus.SetOutput(os.Stdout)
logrus.SetLevel(logrus.WarnLevel)
}
// InitLogToFile : set logrus to output in file
func InitLogToFile() {
logrus.SetFormatter(&logrus.JSONFormatter{})
@ -112,7 +116,7 @@ func Panicf(msg string, args ...interface{}) {
logrus.Panicf(msg, args...)
}
// log response body data for debugging
// DebugResponse : log response body data for debugging
func DebugResponse(response *http.Response) string {
bodyBuffer := make([]byte, 5000)
var str string

Voir le fichier

@ -4,7 +4,7 @@ import (
"fmt"
)
// convert a binary infohash to a magnet uri given a display name and tracker urls
// InfoHashToMagnet : convert a binary infohash to a magnet uri given a display name and tracker urls
func InfoHashToMagnet(ih string, name string, trackers ...string) (str string) {
str = fmt.Sprintf("magnet:?xt=urn:btih:%s", ih)
if len(name) > 0 {

Voir le fichier

@ -34,6 +34,7 @@ func init() {
var HtmlMdRenderer md.Renderer
// MarkdownToHTML : convert markdown to html
// TODO: restrict certain types of markdown
func MarkdownToHTML(markdown string) template.HTML {
if len(markdown) >= 3 && markdown[:3] == "&gt;" {
@ -45,8 +46,8 @@ func MarkdownToHTML(markdown string) template.HTML {
return template.HTML(html)
}
/*
* Sanitize a message passed as a string according to a setted model or allowing a set of html tags and output a string
// Sanitize :
/* Sanitize a message passed as a string according to a setted model or allowing a set of html tags and output a string
*/
func Sanitize(msg string, elements ...string) string {
msg = repairHTMLTags(msg) // We repair possible broken html tags
@ -263,8 +264,8 @@ func Sanitize(msg string, elements ...string) string {
/*
* Should close any opened tags and strip any empty end tags
*/
func repairHTMLTags(brokenHtml string) string {
reader := strings.NewReader(brokenHtml)
func repairHTMLTags(brokenHTML string) string {
reader := strings.NewReader(brokenHTML)
root, err := html.Parse(reader)
if err != nil {
log.Fatal(err)

Voir le fichier

@ -2,14 +2,17 @@ package Messages
import (
"fmt"
"net/http"
"github.com/NyaaPantsu/nyaa/util/languages"
"github.com/gorilla/context"
"github.com/nicksnyder/go-i18n/i18n"
"net/http"
)
// MessagesKey : use for context
const MessagesKey = "messages"
// Messages struct
type Messages struct {
Errors map[string][]string
Infos map[string][]string
@ -17,6 +20,7 @@ type Messages struct {
T i18n.TranslateFunc
}
// GetMessages : Initialize or return the messages object from context
func GetMessages(r *http.Request) *Messages {
if rv := context.Get(r, MessagesKey); rv != nil {
mes := rv.(*Messages)
@ -24,13 +28,13 @@ func GetMessages(r *http.Request) *Messages {
mes.T = T
mes.r = r
return mes
} else {
context.Set(r, MessagesKey, &Messages{})
T, _ := languages.GetTfuncAndLanguageFromRequest(r)
return &Messages{make(map[string][]string), make(map[string][]string), r, T}
}
context.Set(r, MessagesKey, &Messages{})
T, _ := languages.GetTfuncAndLanguageFromRequest(r)
return &Messages{make(map[string][]string), make(map[string][]string), r, T}
}
// AddError : Add an error in category name with message msg
func (mes *Messages) AddError(name string, msg string) {
if mes.Errors == nil {
mes.Errors = make(map[string][]string)
@ -38,19 +42,28 @@ func (mes *Messages) AddError(name string, msg string) {
mes.Errors[name] = append(mes.Errors[name], msg)
mes.setMessagesInContext()
}
// AddErrorf : Add an error in category name with message msg formatted with args
func (mes *Messages) AddErrorf(name string, msg string, args ...interface{}) {
mes.AddError(name, fmt.Sprintf(msg, args...))
}
// AddErrorTf : Add an error in category name with translation string id formatted with args
func (mes *Messages) AddErrorTf(name string, id string, args ...interface{}) {
mes.AddErrorf(name, mes.T(id), args...)
}
// AddErrorT : Add an error in category name with translation string id
func (mes *Messages) AddErrorT(name string, id string) {
mes.AddError(name, mes.T(id))
}
// ImportFromError : Add an error in category name with message msg imported from type error
func (mes *Messages) ImportFromError(name string, err error) {
mes.AddError(name, err.Error())
}
// AddInfo : Add an info in category name with message msg
func (mes *Messages) AddInfo(name string, msg string) {
if mes.Infos == nil {
mes.Infos = make(map[string][]string)
@ -58,47 +71,65 @@ func (mes *Messages) AddInfo(name string, msg string) {
mes.Infos[name] = append(mes.Infos[name], msg)
mes.setMessagesInContext()
}
// AddInfof : Add an info in category name with message msg formatted with args
func (mes *Messages) AddInfof(name string, msg string, args ...interface{}) {
mes.AddInfo(name, fmt.Sprintf(msg, args...))
}
// AddInfoTf : Add an info in category name with translation string id formatted with args
func (mes *Messages) AddInfoTf(name string, id string, args ...interface{}) {
mes.AddInfof(name, mes.T(id), args...)
}
// AddInfoT : Add an info in category name with translation string id
func (mes *Messages) AddInfoT(name string, id string) {
mes.AddInfo(name, mes.T(id))
}
// ClearErrors : Erase all errors in messages
func (mes *Messages) ClearErrors() {
mes.Infos = nil
mes.setMessagesInContext()
}
// ClearInfos : Erase all infos in messages
func (mes *Messages) ClearInfos() {
mes.Errors = nil
mes.setMessagesInContext()
}
// GetAllErrors : Get all errors
func (mes *Messages) GetAllErrors() map[string][]string {
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
return mes.Errors
}
// GetErrors : Get all errors in category name
func (mes *Messages) GetErrors(name string) []string {
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
return mes.Errors[name]
}
// GetAllInfos : Get all infos
func (mes *Messages) GetAllInfos() map[string][]string {
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
return mes.Infos
}
// GetInfos : Get all infos in category name
func (mes *Messages) GetInfos(name string) []string {
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
return mes.Infos[name]
}
// HasErrors : Check if there are errors
func (mes *Messages) HasErrors() bool {
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
return len(mes.Errors) > 0
}
// HasInfos : Check if there are infos
func (mes *Messages) HasInfos() bool {
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
return len(mes.Infos) > 0

Voir le fichier

@ -1,5 +1,6 @@
package metainfo
/**
package for parsing bitorrent meta info objects
originally from XD i2p bittorrent client: https://github.com/majestrate/XD
*/
package metainfo

Voir le fichier

@ -4,5 +4,5 @@ import (
"errors"
)
// error for indicating we have an invalid torrent file
// ErrInvalidTorrentFile : error for indicating we have an invalid torrent file
var ErrInvalidTorrentFile = errors.New("invalid bittorrent file")

Voir le fichier

@ -11,18 +11,20 @@ import (
"github.com/zeebo/bencode"
)
// FilePath type
type FilePath []string
// get filepath
// FilePath : get filepath
func (f FilePath) FilePath() string {
return filepath.Join(f...)
}
/** open file using base path */
// Open : open file using base path
func (f FilePath) Open(base string) (*os.File, error) {
return os.OpenFile(filepath.Join(base, f.FilePath()), os.O_RDWR|os.O_CREATE, 0600)
}
// FileInfo struct
type FileInfo struct {
// length of file
Length uint64 `bencode:"length"`
@ -32,7 +34,7 @@ type FileInfo struct {
Sum []byte `bencode:"md5sum,omitempty"`
}
// info section of torrent file
// Info : info section of torrent file
type Info struct {
// length of pices in bytes
PieceLength uint32 `bencode:"piece length"`
@ -50,7 +52,7 @@ type Info struct {
Sum []byte `bencode:"md5sum,omitempty"`
}
// get fileinfos from this info section
// GetFiles : get fileinfos from this info section
func (i Info) GetFiles() (infos []FileInfo) {
if i.Length > 0 {
infos = append(infos, FileInfo{
@ -64,11 +66,12 @@ func (i Info) GetFiles() (infos []FileInfo) {
return
}
// NumPieces : length of Info
func (i Info) NumPieces() uint32 {
return uint32(len(i.Pieces) / 20)
}
// a torrent file
// TorrentFile : a torrent file
type TorrentFile struct {
Info Info `bencode:"info"`
Announce string `bencode:"announce"`
@ -79,7 +82,7 @@ type TorrentFile struct {
Encoding []byte `bencode:"encoding"`
}
// get total size of files from torrent info section
// TotalSize : get total size of files from torrent info section
func (tf *TorrentFile) TotalSize() uint64 {
if tf.IsSingleFile() {
return tf.Info.Length
@ -91,6 +94,7 @@ func (tf *TorrentFile) TotalSize() uint64 {
return total
}
// GetAllAnnounceURLS : get all trackers url
func (tf *TorrentFile) GetAllAnnounceURLS() (l []string) {
l = make([]string, 0, 64)
if len(tf.Announce) > 0 {
@ -106,16 +110,17 @@ func (tf *TorrentFile) GetAllAnnounceURLS() (l []string) {
return
}
// TorrentName : return torrent name
func (tf *TorrentFile) TorrentName() string {
return tf.Info.Path
}
// return true if this torrent is private otherwise return false
// IsPrivate : return true if this torrent is private otherwise return false
func (tf *TorrentFile) IsPrivate() bool {
return tf.Info.Private != nil && *tf.Info.Private == 1
}
// calculate infohash
// Infohash : calculate infohash
func (tf *TorrentFile) Infohash() (ih [20]byte, err error) {
s := sha1.New()
enc := bencode.NewEncoder(s)
@ -128,19 +133,19 @@ func (tf *TorrentFile) Infohash() (ih [20]byte, err error) {
return
}
// return true if this torrent is for a single file
// IsSingleFile : return true if this torrent is for a single file
func (tf *TorrentFile) IsSingleFile() bool {
return tf.Info.Length > 0
}
// bencode this file via an io.Writer
// Encode : bencode this file via an io.Writer
func (tf *TorrentFile) Encode(w io.Writer) (err error) {
enc := bencode.NewEncoder(w)
err = enc.Encode(tf)
return
}
// load from an io.Reader
// Decode : load from an io.Reader
func (tf *TorrentFile) Decode(r io.Reader) (err error) {
dec := bencode.NewDecoder(r)
err = dec.Decode(tf)

Voir le fichier

@ -1,11 +1,12 @@
package modelHelper
import (
"github.com/NyaaPantsu/nyaa/util/log"
msg "github.com/NyaaPantsu/nyaa/util/messages"
"net/http"
"reflect"
"strconv"
"github.com/NyaaPantsu/nyaa/util/log"
msg "github.com/NyaaPantsu/nyaa/util/messages"
)
// TODO: Rewrite module
@ -34,7 +35,7 @@ func AssignValue(model interface{}, form interface{}) {
}
}
// AssignValue assign form values to model.
// BindValueForm assign populate form from a request
func BindValueForm(form interface{}, r *http.Request) {
r.ParseForm()
formElem := reflect.ValueOf(form).Elem()
@ -57,6 +58,7 @@ func BindValueForm(form interface{}, r *http.Request) {
}
}
// ValidateForm : Check if a form is valid according to its tags
func ValidateForm(form interface{}, mes *msg.Messages) {
formElem := reflect.ValueOf(form).Elem()
for i := 0; i < formElem.NumField(); i++ {
@ -105,7 +107,7 @@ func ValidateForm(form interface{}, mes *msg.Messages) {
if tag.Get("needed") != "" && formElem.Field(i).Int() == 0 {
mes.AddErrorf(tag.Get("form"), "Field needed: %s", inputName)
}
if formElem.Field(i).Interface == nil && tag.Get("default") != "" {
if formElem.Field(i).Interface == nil && tag.Get("default") != "" { // FIXME: always false :'(
defaultValue, _ := strconv.Atoi(tag.Get("default"))
formElem.Field(i).SetInt(int64(defaultValue))
}
@ -119,7 +121,7 @@ func ValidateForm(form interface{}, mes *msg.Messages) {
if tag.Get("needed") != "" && formElem.Field(i).Float() == 0 {
mes.AddErrorf(tag.Get("form"), "Field needed: %s", inputName)
}
if formElem.Field(i).Interface == nil && tag.Get("default") != "" {
if formElem.Field(i).Interface == nil && tag.Get("default") != "" { // FIXME: always false :'(
defaultValue, _ := strconv.Atoi(tag.Get("default"))
formElem.Field(i).SetFloat(float64(defaultValue))
}
@ -130,7 +132,7 @@ func ValidateForm(form interface{}, mes *msg.Messages) {
mes.AddErrorf(tag.Get("form"), "Wrong value for the input: %s", inputName)
}
}
if formElem.Field(i).Interface == nil && tag.Get("default") != "" {
if formElem.Field(i).Interface == nil && tag.Get("default") != "" { // FIXME: always false :'(
defaultValue, _ := strconv.ParseBool(tag.Get("default"))
formElem.Field(i).SetBool(defaultValue)
}

Voir le fichier

@ -5,10 +5,12 @@ import (
"html/template"
)
// Safe : make un url safe
func Safe(s string) template.URL {
return template.URL(html.EscapeString(s))
}
// SafeText : make a string safe
func SafeText(s string) template.HTML {
return template.HTML(html.EscapeString(s))
}

Voir le fichier

@ -21,6 +21,7 @@ import (
var searchOperator string
var useTSQuery bool
// Configure : initialize search
func Configure(conf *config.SearchConfig) (err error) {
useTSQuery = false
// Postgres needs ILIKE for case-insensitivity
@ -35,7 +36,7 @@ func Configure(conf *config.SearchConfig) (err error) {
return
}
func stringIsAscii(input string) bool {
func stringIsASCII(input string) bool {
for _, char := range input {
if char > 127 {
return false
@ -44,21 +45,25 @@ func stringIsAscii(input string) bool {
return true
}
// SearchByQuery : search torrents according to request without user
func SearchByQuery(r *http.Request, pagenum int) (search common.SearchParam, tor []model.Torrent, count int, err error) {
search, tor, count, err = searchByQuery(r, pagenum, true, false, false)
return
}
// SearchByQueryWithUser : search torrents according to request with user
func SearchByQueryWithUser(r *http.Request, pagenum int) (search common.SearchParam, tor []model.Torrent, count int, err error) {
search, tor, count, err = searchByQuery(r, pagenum, true, true, false)
return
}
// SearchByQueryNoCount : search torrents according to request without user and count
func SearchByQueryNoCount(r *http.Request, pagenum int) (search common.SearchParam, tor []model.Torrent, err error) {
search, tor, _, err = searchByQuery(r, pagenum, false, false, false)
return
}
// SearchByQueryDeleted : search deleted torrents according to request with user and count
func SearchByQueryDeleted(r *http.Request, pagenum int) (search common.SearchParam, tor []model.Torrent, count int, err error) {
search, tor, count, err = searchByQuery(r, pagenum, true, true, true)
return
@ -239,7 +244,7 @@ func searchByQueryPostgres(r *http.Request, pagenum int, countAll bool, withUser
continue
}
if useTSQuery && stringIsAscii(word) {
if useTSQuery && stringIsASCII(word) {
conditions = append(conditions, "torrent_name @@ plainto_tsquery(?)")
parameters.Params = append(parameters.Params, word)
} else {

Voir le fichier

@ -7,6 +7,7 @@ import (
"github.com/NyaaPantsu/nyaa/util/log"
)
// SendError : Send an error as response
func SendError(w http.ResponseWriter, err error, code int) {
log.Warnf("%s:\n%s\n", err, debug.Stack())
http.Error(w, err.Error(), code)

Voir le fichier

@ -6,28 +6,34 @@ import (
"github.com/NyaaPantsu/nyaa/util/log"
)
// FewDaysLater : Give time now + some days
func FewDaysLater(day int) time.Time {
return FewDurationLater(time.Duration(day) * 24 * time.Hour)
}
// TwentyFourHoursLater : Give time now + 24 hours
func TwentyFourHoursLater() time.Time {
return FewDurationLater(time.Duration(24) * time.Hour)
}
// SixHoursLater : Give time now + 6 hours
func SixHoursLater() time.Time {
return FewDurationLater(time.Duration(6) * time.Hour)
}
// InTimeSpan : check if time given is in the given time encapsulation
func InTimeSpan(start, end, check time.Time) bool {
log.Debugf("check after before: %s %t %t\n", check, check.After(start), check.Before(end))
return check.After(start) && check.Before(end)
}
// InTimeSpanNow : check if time now is in the given time encapsulation
func InTimeSpanNow(start, end time.Time) bool {
now := time.Now()
return InTimeSpan(start, end, now)
}
// FewDurationLater : Give time now + some time duration
func FewDurationLater(duration time.Duration) time.Time {
// When Save time should considering UTC
fewDurationLater := time.Now().Add(duration)
@ -35,10 +41,12 @@ func FewDurationLater(duration time.Duration) time.Time {
return fewDurationLater
}
// FewDurationLaterMillisecond : Give time now + some millisecond
func FewDurationLaterMillisecond(duration time.Duration) int64 {
return FewDurationLater(duration).UnixNano() / int64(time.Millisecond)
}
// IsExpired : check if time given is expired
func IsExpired(expirationTime time.Time) bool {
log.Debugf("expirationTime : %s", expirationTime)
after := time.Now().After(expirationTime)

Voir le fichier

@ -8,6 +8,7 @@ import (
"io/ioutil"
)
// UnZlib : Is it deprecated?
func UnZlib(description []byte) (string, error) {
if len(description) > 0 {
b := bytes.NewReader(description)

Voir le fichier

@ -4,12 +4,12 @@ import (
"strings"
)
// return true if r is a whitespace rune
// IsWhitespace : return true if r is a whitespace rune
func IsWhitespace(r rune) bool {
return r == '\n' || r == '\t' || r == '\r' || r == ' '
}
// trim whitespaces from a string
// TrimWhitespaces : trim whitespaces from a string
func TrimWhitespaces(s string) string {
s = strings.TrimLeftFunc(s, IsWhitespace)
s = strings.TrimRightFunc(s, IsWhitespace)