Albirew/nyaa-pantsu
Archivé
1
0
Bifurcation 0
Cette révision appartient à :
bragason 2017-05-20 18:04:48 +00:00
révision 968bec3cf1
36 fichiers modifiés avec 529 ajouts et 177 suppressions

Voir le fichier

@ -12,14 +12,27 @@ import (
const (
// LastOldTorrentID is the highest torrent ID
// that was copied from the original Nyaa
LastOldTorrentID = 923000
TorrentsTableName = "torrents"
CommentsTableName = "comments"
// for sukebei
//TableName = "sukebei_torrents"
//CommentsTableName = "sukebei_comments"
LastOldTorrentID = 923000
TorrentsTableName = "torrents"
ReportsTableName = "torrent_reports"
CommentsTableName = "comments"
UploadsOldTableName = "user_uploads_old"
FilesTableName = "files"
// for sukebei:
//LastOldTorrentID = 2303945
//TorrentsTableName = "sukebei_torrents"
//ReportsTableName = "sukebei_torrent_reports"
//CommentsTableName = "sukebei_comments"
//UploadsOldTableName = "sukebei_user_uploads_old"
//FilesTableName = "sukebei_files"
)
func IsSukebei() bool {
return TorrentsTableName == "sukebei_torrents"
}
type Config struct {
Host string `json:"host"`
Port int `json:"port"`

9
config/torrents.go Fichier normal
Voir le fichier

@ -0,0 +1,9 @@
package config
var TorrentStatus = map[int]bool{
0:true,
1:true,
2:true,
3:true,
4:true,
}

Voir le fichier

@ -1,6 +1,7 @@
package model
import (
"github.com/NyaaPantsu/nyaa/config"
"github.com/zeebo/bencode"
)
@ -12,6 +13,10 @@ type File struct {
Filesize int64 `gorm:"column:filesize"`
}
func (f File) TableName() string {
return config.FilesTableName
}
// Returns the total size of memory allocated for this struct
func (f File) Size() int {
return (2 + len(f.BencodedPath) + 1) * 8;

Voir le fichier

@ -2,11 +2,11 @@ package model
import (
"time"
"github.com/NyaaPantsu/nyaa/config"
)
// TODO Add field to specify kind of reports
// TODO Add CreatedAt field
// INFO User can be null (anonymous reports)
// User can be null (anonymous reports)
// FIXME can't preload field Torrents for model.TorrentReport
type TorrentReport struct {
ID uint `gorm:"column:torrent_report_id;primary_key"`
@ -20,6 +20,10 @@ type TorrentReport struct {
User *User `gorm:"AssociationForeignKey:UserID;ForeignKey:user_id"`
}
func (r TorrentReport) TableName() string {
return config.ReportsTableName
}
type TorrentReportJson struct {
ID uint `json:"id"`
Description string `json:"description"`
@ -43,9 +47,8 @@ func getReportDescription(d string) string {
}
func (report *TorrentReport) ToJson() TorrentReportJson {
// FIXME: report.Torrent and report.User should never be nil
var t TorrentJSON = TorrentJSON{}
if report.Torrent != nil {
if report.Torrent != nil { // FIXME: report.Torrent should never be nil
t = report.Torrent.ToJSON()
}
var u UserJSON = UserJSON{}

Voir le fichier

@ -44,7 +44,7 @@ type Torrent struct {
WebsiteLink string `gorm:"column:website_link"`
DeletedAt *time.Time
Uploader *User `gorm:"ForeignKey:uploader"`
Uploader *User `gorm:"AssociationForeignKey:UploaderID;ForeignKey:user_id"`
OldUploader string `gorm:"-"` // ???????
OldComments []OldComment `gorm:"ForeignKey:torrent_id"`
Comments []Comment `gorm:"ForeignKey:torrent_id"`
@ -187,9 +187,12 @@ func (t *Torrent) ToJSON() TorrentJSON {
}
torrentlink := ""
if t.ID <= config.LastOldTorrentID && len(config.TorrentCacheLink) > 0 {
torrentlink = fmt.Sprintf(config.TorrentCacheLink, t.Hash)
if config.IsSukebei() {
torrentlink = "" // torrent cache doesn't have sukebei torrents
} else {
torrentlink = fmt.Sprintf(config.TorrentCacheLink, t.Hash)
}
} else if t.ID > config.LastOldTorrentID && len(config.TorrentStorageLink) > 0 {
// TODO: Fix as part of configuration changes (fix what?)
torrentlink = fmt.Sprintf(config.TorrentStorageLink, t.Hash)
}
res := TorrentJSON{
@ -223,7 +226,7 @@ func (t *Torrent) ToJSON() TorrentJSON {
/* Complete the functions when necessary... */
// Map Torrents to TorrentsToJSON without reallocations
func TorrentsToJSON(t []Torrent) []TorrentJSON { // TODO: Convert to singular version
func TorrentsToJSON(t []Torrent) []TorrentJSON {
json := make([]TorrentJSON, len(t))
for i := range t {
json[i] = t[i].ToJSON()

Voir le fichier

@ -2,6 +2,8 @@ package model
import (
"time"
"github.com/NyaaPantsu/nyaa/config"
)
const (
@ -86,8 +88,8 @@ type UserUploadsOld struct {
}
func (c UserUploadsOld) TableName() string {
// TODO: rename this in db
return "user_uploads_old"
// is this needed here?
return config.UploadsOldTableName
}
func (u *User) ToJSON() UserJSON {

Voir le fichier

@ -60,8 +60,8 @@
background-image: url(/img/megumin.png);
}
body {
background-color:#282A2E;
body, footer {
background-color: #282A2E;
color: #eff5f5;
}

Voir le fichier

@ -128,6 +128,10 @@ td {
color:#bbb;
}
.md-editor > textarea, .md-preview {
background: none !important;
}
/* Table style & fixes */
.table > tbody > tr > th, .nowrap {
white-space: nowrap;
@ -436,8 +440,7 @@ select#bottom_language_selector {
}
.text-error {
background: white;
color: #cf9fff;
color: #fb3333;
}
/* Wordbreak fix*/
@ -577,3 +580,8 @@ select#bottom_language_selector {
display:block !important;
}
}
@media (max-width: 1500px) {
#mascot {
display: none;
}
}

4
public/js/selectAll.js Fichier normal
Voir le fichier

@ -0,0 +1,4 @@
$("[data-selectall='checkbox']").on("change", function(e) {
var form = $(this).parents("form");
$(form).find("input[type='checkbox']").prop('checked', $(this).prop('checked'));
});

Voir le fichier

@ -7,6 +7,7 @@ import (
"strconv"
"strings"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/db"
"github.com/NyaaPantsu/nyaa/model"
"github.com/NyaaPantsu/nyaa/service"
@ -14,9 +15,11 @@ import (
"github.com/NyaaPantsu/nyaa/service/report"
"github.com/NyaaPantsu/nyaa/service/torrent"
"github.com/NyaaPantsu/nyaa/service/user"
"github.com/NyaaPantsu/nyaa/service/user/permission"
form "github.com/NyaaPantsu/nyaa/service/user/form"
"github.com/NyaaPantsu/nyaa/util/languages"
"github.com/NyaaPantsu/nyaa/util/log"
msg "github.com/NyaaPantsu/nyaa/util/messages"
"github.com/NyaaPantsu/nyaa/util/search"
"github.com/gorilla/mux"
)
@ -72,7 +75,6 @@ func (f *ReassignForm) ExtractInfo(r *http.Request) error {
}
func (f *ReassignForm) ExecuteAction() (int, error) {
var toBeChanged []uint
var err error
if f.By == "olduser" {
@ -93,7 +95,6 @@ func (f *ReassignForm) ExecuteAction() (int, error) {
num += 1
}
}
// TODO: clean shit from user_uploads_old if needed
return num, nil
}
@ -133,20 +134,20 @@ func TorrentsListPanel(w http.ResponseWriter, r *http.Request) {
if !log.CheckError(err) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
}
offset := 100
searchParam, torrents, _, err := search.SearchByQuery(r, pagenum)
searchForm := SearchForm{
SearchParam: searchParam,
Category: searchParam.Category.String(),
ShowItemsPerPage: true,
}
searchParam, torrents, count, err := search.SearchByQueryWithUser(r, pagenum)
searchForm := SearchForm{
SearchParam: searchParam,
Category: searchParam.Category.String(),
ShowItemsPerPage: true,
}
messages := msg.GetMessages(r)
languages.SetTranslationFromRequest(panelTorrentList, r)
navigation := Navigation{int(searchParam.Max), offset, pagenum, "mod_tlist_page"}
ptlv := PanelTorrentListVbs{torrents, searchForm, navigation, currentUser, r.URL}
navigation := Navigation{ count, int(searchParam.Max), pagenum, "mod_tlist_page"}
ptlv := PanelTorrentListVbs{torrents, searchForm, navigation, currentUser, messages.GetAllErrors(), messages.GetAllInfos(), r.URL}
err = panelTorrentList.ExecuteTemplate(w, "admin_index.html", ptlv)
log.CheckError(err)
}
@ -343,3 +344,61 @@ func TorrentPostReassignModPanel(w http.ResponseWriter, r *http.Request) {
err_ := panelTorrentReassign.ExecuteTemplate(w, "admin_index.html", htv)
log.CheckError(err_)
}
func TorrentsPostListPanel(w http.ResponseWriter, r *http.Request) {
torrentManyAction(r)
TorrentsListPanel(w, r)
}
/*
* Controller to modify multiple torrents and can be used by the owner of the torrent or admin
*/
func torrentManyAction(r *http.Request) {
currentUser := GetUser(r)
r.ParseForm()
torrentsSelected := r.Form["torrent_id"] // should be []string
action := r.FormValue("action")
moveTo, _ := strconv.Atoi(r.FormValue("moveto"))
messages := msg.GetMessages(r) // new util for errors and infos
if action == "" {
messages.AddError("errors", "You have to tell what you want to do with your selection!")
}
if action == "move" && r.FormValue("moveto") == "" { // We need to check the form value, not the int one because hidden is 0
messages.AddError("errors", "Thou has't to telleth whither thee wanteth to moveth thy selection!")
}
if len(torrentsSelected) == 0 {
messages.AddError("errors", "You need to select at least 1 element!")
}
if !messages.HasErrors() {
for _, torrent_id := range torrentsSelected {
torrent, _ := torrentService.GetTorrentById(torrent_id)
if torrent.ID > 0 && userPermission.CurrentOrAdmin(currentUser, torrent.UploaderID) {
switch action {
case "move":
if config.TorrentStatus[moveTo] {
torrent.Status = moveTo
db.ORM.Save(&torrent)
messages.AddInfof("infos", "Torrent %s moved!", torrent.Name)
} else {
messages.AddErrorf("errors", "No such status %d exist!", moveTo)
}
case "delete":
_, err := torrentService.DeleteTorrent(torrent_id)
if err != nil {
messages.ImportFromError("errors", err)
} else {
messages.AddInfof("infos", "Torrent %s deleted!", torrent.Name)
}
default:
messages.AddErrorf("errors", "No such action %s exist!", action)
}
} else {
messages.AddErrorf("errors", "Torrent with ID %s doesn't exist!", torrent_id)
}
}
}
}

6
router/router.go Fichier normal → Fichier exécutable
Voir le fichier

@ -70,8 +70,10 @@ func init() {
// sure the page is only accessible by moderators
// TODO Find a native mux way to add a 'prehook' for route /mod
Router.HandleFunc("/mod", WrapModHandler(IndexModPanel)).Name("mod_index")
Router.HandleFunc("/mod/torrents", WrapModHandler(TorrentsListPanel)).Name("mod_tlist")
Router.HandleFunc("/mod/torrents/{page}", WrapModHandler(TorrentsListPanel)).Name("mod_tlist_page")
Router.HandleFunc("/mod/torrents", WrapModHandler(TorrentsListPanel)).Name("mod_tlist").Methods("GET")
Router.HandleFunc("/mod/torrents/{page}", WrapModHandler(TorrentsListPanel)).Name("mod_tlist_page").Methods("GET")
Router.HandleFunc("/mod/torrents", WrapModHandler(TorrentsPostListPanel)).Methods("POST")
Router.HandleFunc("/mod/torrents/{page}", WrapModHandler(TorrentsPostListPanel)).Methods("POST")
Router.HandleFunc("/mod/reports", WrapModHandler(TorrentReportListPanel)).Name("mod_trlist")
Router.HandleFunc("/mod/reports/{page}", WrapModHandler(TorrentReportListPanel)).Name("mod_trlist_page")
Router.HandleFunc("/mod/users", WrapModHandler(UsersListPanel)).Name("mod_ulist")

Voir le fichier

@ -2,7 +2,7 @@ package router
import (
"html/template"
"log"
//"log"
"math"
"net/url"
"strconv"
@ -109,11 +109,14 @@ var FuncMap = template.FuncMap{
if nav.CurrentPage > pagesSelectable/2 {
startValue = (int(math.Min((float64(nav.CurrentPage)+math.Floor(float64(pagesSelectable)/2)), maxPages)) - pagesSelectable + 1)
}
if startValue < 1 {
startValue = 1
}
endValue := (startValue + pagesSelectable - 1)
if endValue > int(maxPages) {
endValue = int(maxPages)
}
log.Println(nav.TotalItem)
//log.Println(nav.TotalItem)
for i := startValue; i <= endValue; i++ {
pageNum := strconv.Itoa(i)
url, _ := Router.Get(nav.Route).URL("page", pageNum)
@ -131,13 +134,7 @@ var FuncMap = template.FuncMap{
}
return template.HTML(ret)
},
"Sukebei": func() bool {
if config.TorrentsTableName == "sukebei_torrents" {
return true
} else {
return false
}
},
"Sukebei": config.IsSukebei,
"T": i18n.IdentityTfunc,
"Ts": i18n.IdentityTfunc,
"getDefaultLanguage": languages.GetDefaultLanguage,

Voir le fichier

@ -36,6 +36,8 @@ type NotFoundTemplateVariables struct {
type ViewTemplateVariables struct {
Torrent model.TorrentJSON
CaptchaID string
FormErrors map[string][]string
Infos map[string][]string
Search SearchForm
Navigation Navigation
User *model.User
@ -116,6 +118,7 @@ type DatabaseDumpTemplateVariables struct {
type UploadTemplateVariables struct {
Upload UploadForm
FormErrors map[string][]string
Search SearchForm
Navigation Navigation
User *model.User
@ -150,6 +153,8 @@ type PanelTorrentListVbs struct {
Search SearchForm
Navigation Navigation
User *model.User
Errors map[string][]string
Infos map[string][]string
URL *url.URL // For parsing Url in templates
}
type PanelUserListVbs struct {

Voir le fichier

@ -40,6 +40,7 @@ type UploadForm struct {
Description string
Status int
CaptchaID string
WebsiteLink string
Infohash string
CategoryID int
@ -58,25 +59,29 @@ const UploadFormMagnet = "magnet"
const UploadFormCategory = "c"
const UploadFormRemake = "remake"
const UploadFormDescription = "desc"
const UploadFormWebsiteLink = "website_link"
const UploadFormStatus = "status"
// error indicating that you can't send both a magnet link and torrent
var ErrTorrentPlusMagnet = errors.New("upload either a torrent file or magnet link, not both")
var ErrTorrentPlusMagnet = errors.New("Upload either a torrent file or magnet link, not both")
// error indicating a torrent is private
var ErrPrivateTorrent = errors.New("torrent is private")
var ErrPrivateTorrent = errors.New("Torrent is private")
// error indicating a problem with its trackers
var ErrTrackerProblem = errors.New("torrent does not have any (working) trackers: https://" + config.WebAddress + "/faq#trackers")
var ErrTrackerProblem = errors.New("Torrent does not have any (working) trackers: https://" + config.WebAddress + "/faq#trackers")
// error indicating a torrent's name is invalid
var ErrInvalidTorrentName = errors.New("torrent name is invalid")
var ErrInvalidTorrentName = errors.New("Torrent name is invalid")
// error indicating a torrent's description is invalid
var ErrInvalidTorrentDescription = errors.New("torrent description is invalid")
var ErrInvalidTorrentDescription = errors.New("Torrent description is invalid")
// error indicating a torrent's description is invalid
var ErrInvalidWebsiteLink = errors.New("Website url or IRC link is invalid")
// error indicating a torrent's category is invalid
var ErrInvalidTorrentCategory = errors.New("torrent category is invalid")
var ErrInvalidTorrentCategory = errors.New("Torrent category is invalid")
var p = bluemonday.UGCPolicy()
@ -88,6 +93,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
f.Name = r.FormValue(UploadFormName)
f.Category = r.FormValue(UploadFormCategory)
f.Description = r.FormValue(UploadFormDescription)
f.WebsiteLink = r.FormValue(UploadFormWebsiteLink)
f.Status, _ = strconv.Atoi(r.FormValue(UploadFormStatus))
f.Magnet = r.FormValue(UploadFormMagnet)
f.Remake = r.FormValue(UploadFormRemake) == "on"
@ -95,6 +101,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
// trim whitespace
f.Name = util.TrimWhitespaces(f.Name)
f.Description = p.Sanitize(util.TrimWhitespaces(f.Description))
f.WebsiteLink = util.TrimWhitespaces(f.WebsiteLink)
f.Magnet = util.TrimWhitespaces(f.Magnet)
cache.Impl.ClearAll()
@ -115,6 +122,13 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
} else {
return ErrInvalidTorrentCategory
}
if f.WebsiteLink != "" {
// WebsiteLink
urlRegexp, _ := regexp.Compile(`^(https?:\/\/|ircs?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$`)
if !urlRegexp.MatchString(f.WebsiteLink) {
return ErrInvalidWebsiteLink
}
}
// first: parse torrent file (if any) to fill missing information
tfile, _, err := r.FormFile(UploadFormTorrent)
@ -175,7 +189,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
}
xt := magnetUrl.Query().Get("xt")
if !strings.HasPrefix(xt, "urn:btih:") {
return errors.New("incorrect magnet")
return errors.New("Incorrect magnet")
}
xt = strings.SplitAfter(xt, ":")[2]
f.Infohash = strings.ToUpper(strings.Split(xt, "&")[0])
@ -189,7 +203,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
return err
}
if !isBase16 {
return errors.New("incorrect hash")
return errors.New("Incorrect hash")
}
} else {
//convert to base16

Voir le fichier

@ -1,18 +1,17 @@
package router
import (
"fmt"
"net/http"
"strconv"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/db"
"github.com/NyaaPantsu/nyaa/model"
"github.com/NyaaPantsu/nyaa/service/captcha"
"github.com/NyaaPantsu/nyaa/service/upload"
"github.com/NyaaPantsu/nyaa/service/user/permission"
"github.com/NyaaPantsu/nyaa/util/languages"
msg "github.com/NyaaPantsu/nyaa/util/messages"
"github.com/gorilla/mux"
)
@ -25,31 +24,28 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
UploadPostHandler(w, r)
} else if r.Method == "GET" {
UploadGetHandler(w, r)
} else {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
UploadGetHandler(w, r)
}
func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
var uploadForm UploadForm
defer r.Body.Close()
user := GetUser(r)
messages := msg.GetMessages(r) // new util for errors and infos
if userPermission.NeedsCaptcha(user) {
userCaptcha := captcha.Extract(r)
if !captcha.Authenticate(userCaptcha) {
http.Error(w, captcha.ErrInvalidCaptcha.Error(), http.StatusInternalServerError)
return
messages.AddError("errors", captcha.ErrInvalidCaptcha.Error())
}
}
// validation is done in ExtractInfo()
err := uploadForm.ExtractInfo(r)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
messages.AddError("errors", err.Error())
}
status := model.TorrentStatusNormal
if uploadForm.Remake { // overrides trusted
@ -59,8 +55,12 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
}
var sameTorrents int
db.ORM.Model(&model.Torrent{}).Table(config.TorrentsTableName).Where("torrent_hash = ?", uploadForm.Infohash).Count(&sameTorrents)
if sameTorrents == 0 {
db.ORM.Model(&model.Torrent{}).Where("torrent_hash = ?", uploadForm.Infohash).Count(&sameTorrents)
if sameTorrents > 0 {
messages.AddError("errors", "Torrent already in database !")
}
if !messages.HasErrors() {
// add to db and redirect
torrent := model.Torrent{
Name: uploadForm.Name,
@ -71,8 +71,9 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
Date: time.Now(),
Filesize: uploadForm.Filesize,
Description: uploadForm.Description,
WebsiteLink: uploadForm.WebsiteLink,
UploaderID: user.ID}
db.ORM.Table(config.TorrentsTableName).Create(&torrent)
db.ORM.Create(&torrent)
// add filelist to files db, if we have one
if len(uploadForm.FileList) > 0 {
@ -80,8 +81,7 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
file := model.File{TorrentID: torrent.ID, Filesize: uploadedFile.Filesize}
err := file.SetPath(uploadedFile.Path)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
messages.AddError("errors", err.Error())
}
db.ORM.Create(&file)
}
@ -92,18 +92,16 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
http.Redirect(w, r, url.String(), 302)
} else {
err = fmt.Errorf("Torrent already in database!")
http.Error(w, err.Error(), http.StatusInternalServerError)
return
http.Redirect(w, r, url.String()+"?success", 302)
}
}
func UploadGetHandler(w http.ResponseWriter, r *http.Request) {
languages.SetTranslationFromRequest(uploadTemplate, r)
messages := msg.GetMessages(r) // new util for errors and infos
var uploadForm UploadForm
_ = uploadForm.ExtractInfo(r)
user := GetUser(r)
if userPermission.NeedsCaptcha(user) {
uploadForm.CaptchaID = captcha.GetID()
@ -113,6 +111,7 @@ func UploadGetHandler(w http.ResponseWriter, r *http.Request) {
utv := UploadTemplateVariables{
Upload: uploadForm,
FormErrors: messages.GetAllErrors(),
Search: NewSearchForm(),
Navigation: NewNavigation(),
User: GetUser(r),

Voir le fichier

@ -282,13 +282,14 @@ func UserLoginPostHandler(w http.ResponseWriter, r *http.Request) {
if errorTmpl != nil {
http.Error(w, errorTmpl.Error(), http.StatusInternalServerError)
}
return
} else {
url, _ := Router.Get("home").URL()
http.Redirect(w, r, url.String(), http.StatusSeeOther)
}
}
if len(err) > 0 {
languages.SetTranslationFromRequest(viewRegisterTemplate, r)
languages.SetTranslationFromRequest(viewLoginTemplate, r)
htv := UserLoginFormVariables{b, err, NewSearchForm(), NewNavigation(), GetUser(r), r.URL, mux.CurrentRoute(r)}
errorTmpl := viewLoginTemplate.ExecuteTemplate(w, "index.html", htv)
if errorTmpl != nil {

Voir le fichier

@ -14,12 +14,18 @@ import (
"github.com/NyaaPantsu/nyaa/util"
"github.com/NyaaPantsu/nyaa/util/languages"
"github.com/NyaaPantsu/nyaa/util/log"
msg "github.com/NyaaPantsu/nyaa/util/messages"
"github.com/gorilla/mux"
)
func ViewHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
messages := msg.GetMessages(r)
if (r.URL.Query()["success"] != nil) {
messages.AddInfo("infos", "Torrent uploaded successfully!")
}
torrent, err := torrentService.GetTorrentById(id)
if err != nil {
@ -32,7 +38,7 @@ func ViewHandler(w http.ResponseWriter, r *http.Request) {
if userPermission.NeedsCaptcha(user) {
captchaID = captcha.GetID()
}
htv := ViewTemplateVariables{b, captchaID, NewSearchForm(), NewNavigation(), user, r.URL, mux.CurrentRoute(r)}
htv := ViewTemplateVariables{b, captchaID, messages.GetAllErrors(), messages.GetAllInfos(), NewSearchForm(), NewNavigation(), user, r.URL, mux.CurrentRoute(r)}
languages.SetTranslationFromRequest(viewTemplate, r)
err = viewTemplate.ExecuteTemplate(w, "index.html", htv)

Voir le fichier

@ -1,7 +1,6 @@
package commentService
import (
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/db"
"github.com/NyaaPantsu/nyaa/model"
)
@ -9,7 +8,7 @@ import (
func GetAllComments(limit int, offset int, conditions string, values ...interface{}) ([]model.Comment, int) {
var comments []model.Comment
var nbComments int
db.ORM.Table(config.CommentsTableName).Model(&comments).Where(conditions, values...).Count(&nbComments)
db.ORM.Model(&comments).Where(conditions, values...).Count(&nbComments)
db.ORM.Preload("User").Limit(limit).Offset(offset).Where(conditions, values...).Find(&comments)
return comments, nbComments
}

Voir le fichier

@ -11,6 +11,7 @@ import (
"github.com/NyaaPantsu/nyaa/model"
"github.com/NyaaPantsu/nyaa/service"
"github.com/NyaaPantsu/nyaa/util"
// "github.com/NyaaPantsu/nyaa/util/log"
)
/* Function to interact with Models
@ -53,15 +54,18 @@ func GetTorrentById(id string) (torrent model.Torrent, err error) {
return
}
tmp := db.ORM.Table(config.TorrentsTableName).Where("torrent_id = ?", id).Preload("Comments").Preload("FileList")
tmp := db.ORM.Where("torrent_id = ?", id).Preload("Comments")
if id_int > config.LastOldTorrentID {
tmp = tmp.Preload("FileList")
}
if id_int <= config.LastOldTorrentID && !config.IsSukebei() {
// only preload old comments if they could actually exist
tmp = tmp.Preload("OldComments")
}
err = tmp.Error
if err != nil {
return
}
if id_int <= config.LastOldTorrentID {
// only preload old comments if they could actually exist
tmp = tmp.Preload("OldComments")
}
if tmp.Find(&torrent).RecordNotFound() {
err = errors.New("Article is not found.")
return
@ -91,23 +95,28 @@ func GetTorrentById(id string) (torrent model.Torrent, err error) {
// won't fetch user or comments
func GetRawTorrentById(id uint) (torrent model.Torrent, err error) {
err = nil
if db.ORM.Table(config.TorrentsTableName).Table(config.TorrentsTableName).Where("torrent_id = ?", id).Find(&torrent).RecordNotFound() {
if db.ORM.Where("torrent_id = ?", id).Find(&torrent).RecordNotFound() {
err = errors.New("Article is not found.")
}
return
}
func GetTorrentsOrderByNoCount(parameters *serviceBase.WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, err error) {
torrents, _, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, false)
torrents, _, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, false, false)
return
}
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)
torrents, count, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, true, false)
return
}
func getTorrentsOrderBy(parameters *serviceBase.WhereParams, orderBy string, limit int, offset int, countAll bool) (
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)
return
}
func getTorrentsOrderBy(parameters *serviceBase.WhereParams, orderBy string, limit int, offset int, countAll bool, withUser bool) (
torrents []model.Torrent, count int, err error,
) {
var conditionArray []string
@ -122,12 +131,11 @@ func getTorrentsOrderBy(parameters *serviceBase.WhereParams, orderBy string, lim
conditions := strings.Join(conditionArray, " AND ")
if countAll {
// FIXME: `deleted_at IS NULL` is duplicate in here because GORM handles this for us
err = db.ORM.Model(&torrents).Table(config.TorrentsTableName).Where(conditions, params...).Count(&count).Error
err = db.ORM.Model(&torrents).Where(conditions, params...).Count(&count).Error
if err != nil {
return
}
}
// TODO: Vulnerable to injections. Use query builder. (is it?)
// build custom db query for performance reasons
dbQuery := "SELECT * FROM " + config.TorrentsTableName
@ -146,7 +154,14 @@ func getTorrentsOrderBy(parameters *serviceBase.WhereParams, orderBy string, lim
if limit != 0 || offset != 0 { // if limits provided
dbQuery = dbQuery + " LIMIT " + strconv.Itoa(limit) + " OFFSET " + strconv.Itoa(offset)
}
err = db.ORM.Preload("Comments").Raw(dbQuery, params...).Find(&torrents).Error
dbQ := db.ORM
if withUser {
dbQ = dbQ.Preload("Uploader")
}
if countAll {
dbQ = dbQ.Preload("Comments")
}
err = dbQ.Raw(dbQuery, params...).Find(&torrents).Error
return
}
@ -177,18 +192,18 @@ func GetAllTorrentsDB() ([]model.Torrent, int, error) {
func DeleteTorrent(id string) (int, error) {
var torrent model.Torrent
if db.ORM.Table(config.TorrentsTableName).First(&torrent, id).RecordNotFound() {
if db.ORM.First(&torrent, id).RecordNotFound() {
return http.StatusNotFound, errors.New("Torrent is not found.")
}
if db.ORM.Table(config.TorrentsTableName).Delete(&torrent).Error != nil {
return http.StatusInternalServerError, errors.New("Torrent is not deleted.")
if db.ORM.Delete(&torrent).Error != nil {
return http.StatusInternalServerError, errors.New("Torrent was not deleted.")
}
return http.StatusOK, nil
}
func UpdateTorrent(torrent model.Torrent) (int, error) {
if db.ORM.Table(config.TorrentsTableName).Save(torrent).Error != nil {
return http.StatusInternalServerError, errors.New("Torrent is not updated.")
if db.ORM.Save(torrent).Error != nil {
return http.StatusInternalServerError, errors.New("Torrent was not updated.")
}
return http.StatusOK, nil

Voir le fichier

@ -7,6 +7,7 @@ import (
formStruct "github.com/NyaaPantsu/nyaa/service/user/form"
"github.com/NyaaPantsu/nyaa/util/modelHelper"
"github.com/NyaaPantsu/nyaa/util/timeHelper"
"github.com/gorilla/context"
"github.com/gorilla/securecookie"
"golang.org/x/crypto/bcrypt"
"net/http"
@ -14,7 +15,10 @@ import (
"time"
)
const CookieName = "session"
const (
CookieName = "session"
UserContextKey = "user"
)
// If you want to keep login cookies between restarts you need to make these permanent
var cookieHandler = securecookie.New(
@ -113,7 +117,7 @@ func RegisterHandler(w http.ResponseWriter, r *http.Request) (int, error) {
return RegisterHanderFromForm(w, registrationForm)
}
// CurrentUser determines the current user from the request
// CurrentUser determines the current user from the request or context
func CurrentUser(r *http.Request) (model.User, error) {
var user model.User
var encoded string
@ -131,8 +135,17 @@ func CurrentUser(r *http.Request) (model.User, error) {
if err != nil {
return user, err
}
if db.ORM.Where("user_id = ?", user_id).First(&user).RecordNotFound() {
return user, errors.New("User not found")
userFromContext := getUserFromContext(r)
if userFromContext.ID > 0 && user_id == userFromContext.ID {
user = userFromContext
} else {
if db.ORM.Where("user_id = ?", user_id).First(&user).RecordNotFound() {
return user, errors.New("User not found")
} else {
setUserToContext(r, user)
}
}
if user.IsBanned() {
@ -141,3 +154,13 @@ func CurrentUser(r *http.Request) (model.User, error) {
}
return user, nil
}
func getUserFromContext(r *http.Request) model.User {
if rv := context.Get(r, UserContextKey); rv != nil {
return rv.(model.User)
}
return model.User{}
}
func setUserToContext(r *http.Request, val model.User) {
context.Set(r, UserContextKey, val)
}

Voir le fichier

@ -7,7 +7,6 @@ import (
"strconv"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/db"
"github.com/NyaaPantsu/nyaa/model"
formStruct "github.com/NyaaPantsu/nyaa/service/user/form"
@ -129,7 +128,7 @@ func RetrieveUser(r *http.Request, id string) (*model.PublicUser, bool, uint, in
var currentUserID uint
var isAuthor bool
if db.ORM.Table(config.TorrentsTableName).First(&user, id).RecordNotFound() {
if db.ORM.First(&user, id).RecordNotFound() {
return nil, isAuthor, currentUserID, http.StatusNotFound, errors.New("user not found")
}
currentUser, err := CurrentUser(r)

Voir le fichier

@ -13,7 +13,11 @@
<li><a href="{{ genRoute "user_logout" }}"><i class="fa fa-sign-out"></i> {{ T "sign_out"}}</a></li>
</ul>
{{ else }}
<a href="#" class="dropdown-toggle profile-image" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ T "member" }}<span class="caret"></span></a>
<a href="#" class="dropdown-toggle profile-image" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
<span class="hidden-md hidden-sm">{{ T "member" }}</span>
<span class="glyphicon glyphicon-user visible-md-inline"></span>
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="{{ genRoute "user_login" }}"><i class="fa fa-sign-out"></i> {{ T "sign_in"}}</a></li>
<li><a href="{{ genRoute "user_register" }}"><i class="fa fa-cog"></i> {{ T "sign_up"}}</a></li>

Voir le fichier

@ -32,14 +32,14 @@
{{.Name}}
</a>
</td>
<td class="date date-short">{{.Date}}</td>
<td class="filesize">{{.Filesize}}</td>
<td class="nowrap date-short">{{.Date}}</td>
<td class="nowrap">{{.Filesize}}</td>
<td>
<a href="{{.Magnet}}" title="Magnet link">
<a href="{{.Magnet}}" title="{{ T "magnet_link" }}">
<span class="glyphicon glyphicon-magnet" aria-hidden="true"></span>
</a>
{{if ne .TorrentLink ""}}
<a href="{{.TorrentLink}}" title="Torrent file">
<a href="{{.TorrentLink}}" title="{{ T "torrent_file" }}">
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
</a>
{{end}}

Voir le fichier

@ -2,21 +2,54 @@
{{define "contclass"}}cont-view{{end}}
{{define "content"}}
<div class="blockBody">
<table class="table">
<tr>
<th class="col-xs-10">Torrent Name</th>
<th class="col-xs-1">Uploader</th>
<th class="col-xs-1">Action</th>
</tr>
<form method="post" action="">
{{ range (index $.Infos "infos")}}
<div class="alert alert-info"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-info-sign"></i> {{ . }}</div>
{{end}}
{{ range (index $.Errors "errors")}}
<div class="alert alert-danger"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-exclamation-sign"></i> {{ . }}</div>
{{end}}
<nav class="navbar navbar-default">
<div class="navbar-form">
<div class="form-group">
<select class="form-control" name="action">
<option value="">Action...</option>
<option value="move">Move</option>
<option value="delete">Delete</option>
</select>
<select class="form-control" style="display: none;" name="moveto">
<option value="">To...</option>
<option value="0">{{T "torrent_status_hidden"}}</option>
<option value="1">{{T "torrent_status_normal"}}</option>
<option value="2">{{T "torrent_status_remake"}}</option>
<option value="3">{{T "trusted"}}</option>
<option value="4">A+</option>
</select>
</div>
<input type="submit" class="btn btn-success" value="Apply">
<input type="reset" class="btn btn-danger" value="Reset">
</div>
</nav>
<div class="table-responsive">
<table class="table table-hover">
<tr>
<th style="width:12px;"><input type="checkbox" name="checkall" data-selectall="checkbox"></th>
<th>Torrent Name</th>
<th>Uploader</th>
<th>Action</th>
</tr>
{{ range .Torrents}}
<tr>
<td><a href="{{ genViewTorrentRoute .ID }}">{{ .Name }}</a> (<a href="{{ genRoute "mod_tedit" }}?id={{.ID}}">Edit</a>)</td>
<td><a href="{{ genRoute "mod_tlist" }}?userID={{.UploaderID}}">{{ .UploaderID }}</a></td>
<td><a href="{{ genRoute "mod_tdelete" }}?id={{ .ID }}" class="btn btn-danger btn-lg" onclick="if (!confirm('Are you sure?')) return false;"><i class="glyphicon glyphicon-trash"></i> {{ T "delete" }}</a></td>
</tr>
{{end}}
</table>
{{ range .Torrents}}
<tr>
<td><input type="checkbox" name="torrent_id" value="{{.ID }}"></td>
<td><a href="{{ genViewTorrentRoute .ID }}">{{ .Name }}</a> (<a href="{{ genRoute "mod_tedit" }}?id={{.ID}}">Edit</a>)</td>
<td>{{ if gt .UploaderID 0 }}<a href="{{ genRoute "mod_tlist" }}?userID={{.UploaderID}}">{{ .Uploader.Username }}</a>{{ else }}れんちょん{{end}}</td>
<td><a href="{{ genRoute "mod_tdelete" }}?id={{ .ID }}" class="btn btn-danger" onclick="if (!confirm('Are you sure?')) return false;"><i class="glyphicon glyphicon-trash"></i> {{ T "delete" }}</a></td>
</tr>
{{end}}
</table>
</div>
</form>
<nav class="torrentNav" aria-label="Page navigation">
<ul class="pagination">
{{ genNav .Navigation .URL 5 }}
@ -24,3 +57,15 @@
</nav>
</div>
{{end}}
{{ define "js_footer"}}
<!-- JS Function for selecting multiple checkboxes -->
<script type="text/javascript" src="{{ .URL.Parse "/js/selectAll.js" }}"></script>
<script type="text/javascript">
$("select[name='action']").on("change", function(e) {
if ($(this).val() == "move")
$(this).siblings("select[name='moveto']").show()
else
$(this).siblings("select[name='moveto']").hide()
});
</script>
{{end}}

Voir le fichier

@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Nyaa Pantsu - {{block "title" .}}{{ T "error_404" }}{{end}}</title>
<title>{{if Sukebei}}Sukebei{{else}}Nyaa{{end}} Pantsu - {{block "title" .}}{{ T "error_404" }}{{end}}</title>
<link rel="icon" type="image/png" href="/img/favicon.png?v=3" />
<!-- RSS Feed with Context -->
@ -71,6 +71,7 @@
{{block "search_button" .}}{{end}}
</div>
</form>
<div style="clear: both;"></div>
{{block "content" .}}{{end}}
</div>
<footer style="text-align: center; padding-bottom: 2rem;font-size: 2rem;font-family: cursive; color: #616161;text-shadow: -1px -1px #999999;">

Voir le fichier

@ -24,11 +24,11 @@
<td class="name">
{{.Name}}
</td>
<td class="hidden-xs date date-short">{{.Date}}</td>
<td class="hidden-xs filesize">{{.Filesize}}</td>
<td class="hidden-xs nowrap date-short">{{.Date}}</td>
<td class="hidden-xs nowrap">{{.Filesize}}</td>
<td class="hidden-xs">
{{if ne .TorrentLink ""}}
<a href="{{.TorrentLink}}" title="Torrent file">
<a href="{{.TorrentLink}}" title="{{ T "torrent_file" }}">
<span class="glyphicon glyphicon-floppy-save" aria-hidden="true"></span>
</a>
{{end}}

Voir le fichier

@ -3,7 +3,7 @@
{{define "content"}}
<audio id="nyaapassu" hidden>
<source src="http://nyanpass.com/nyanpass.mp3" type="audio/mpeg">
<source src="https://a.doko.moe/sewang.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
<audio id="explosion" hidden>
@ -11,7 +11,7 @@ Your browser does not support the audio element.
Your browser does not support the audio element.
</audio>
<span id="mascot" class="visible-lg-block"></span>
<span id="mascot"></span>
<div class="blockBody">
<nav>
@ -25,13 +25,15 @@ Your browser does not support the audio element.
<table class="table custom-table-hover">
<tr>
<th class="col-xs-1 hidden-xs">{{T "category"}}</th>
<th class="col-xs-5">
<th class="col-xs-12">
<a href="{{ genSearchWithOrdering .URL "1" }}">{{T "name"}}{{ genSortArrows .URL "1" }}</a>
</th>
<th class="col-xs-1 hidden-xs">
<a href="{{ genSearchWithOrdering .URL "5" }}">{{T "S"}}{{ genSortArrows .URL "5" }}</a> /
<a href="{{ genSearchWithOrdering .URL "6" }}">{{T "L"}}{{ genSortArrows .URL "6" }}</a> /
<a href="{{ genSearchWithOrdering .URL "7" }}">{{T "D"}}{{ genSortArrows .URL "7" }}</a>
</th>
<!-- <th class="col-xs-1 hidden-xs"><span class="glyphicon glyphicon-comment"></span></th> -->
<th class="col-xs-1 hidden-xs"><a href="{{ genSearchWithOrdering .URL "5" }}">{{T "S"}}{{ genSortArrows .URL "5" }}</a></th>
<th class="col-xs-1 hidden-xs"><a href="{{ genSearchWithOrdering .URL "6" }}">{{T "L"}}{{ genSortArrows .URL "6" }}</a></th>
<th class="col-xs-1 hidden-xs"><a href="{{ genSearchWithOrdering .URL "7" }}">{{T "D"}}{{ genSortArrows .URL "7" }}</a></th>
<th class="col-xs-1 hidden-xs"><a href="{{ genSearchWithOrdering .URL "2" }}">{{T "date"}}{{ genSortArrows .URL "2" }}</th></a>
<th class="col-xs-1 hidden-xs"><a href="{{ genSearchWithOrdering .URL "4" }}">{{T "size"}}{{ genSortArrows .URL "4" }}</a></th>
<th class="col-xs-1 hidden-xs">{{T "links"}}</th>
@ -62,11 +64,13 @@ Your browser does not support the audio element.
</td>
-->
{{if .LastScrape.IsZero}}
<td class="hidden-xs" colspan="3" align="center">{{T "unknown"}}</td>
<td class="hidden-xs" align="center">{{T "unknown"}}</td>
{{else}}
<td class="hidden-xs"><b class="text-success">{{.Seeders}}</b></td>
<td class="hidden-xs"><b class="text-danger">{{.Leechers}}</b></td>
<td class="hidden-xs">{{.Completed}}</td>
<td class="hidden-xs">
<b class="text-success">{{.Seeders}}</b> /
<b class="text-danger">{{.Leechers}}</b> /
{{.Completed}}
</td>
{{end}}
<td class="hidden-xs nowrap date-short">{{.Date}}</td>
<td class="hidden-xs nowrap">{{.Filesize}}</td>

Voir le fichier

@ -5,7 +5,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Nyaa Pantsu - {{block "title" .}}{{ T "error_404" }}{{end}}</title>
<title>{{if Sukebei}}Sukebei{{else}}Nyaa{{end}} Pantsu - {{block "title" .}}{{ T "error_404" }}{{end}}</title>
<link rel="icon" type="image/png" href="/img/favicon.png?v=3" />
<!-- RSS Feed with Context -->

Voir le fichier

@ -4,7 +4,9 @@
{{with .Upload}}
<hr>
<form enctype="multipart/form-data" role="upload" method="POST">
{{ range (index $.FormErrors "errors")}}
<div class="alert alert-danger"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-exclamation-sign"></i> {{ . }}</div>
{{end}}
<div class="form-group">
<label for="name">{{T "name"}}</label>
<input type="text" name="name" id="name" class="form-control" placeholder="{{T "file_name"}}" value="{{.Name}}" autofocus required>
@ -69,7 +71,11 @@
<div class="form-group">
<label for="desc">{{T "torrent_description"}}</label>
<p class="help-block">{{T "description_markdown_notice"}}</p>
<textarea name="desc" id="desc" class="form-contro torrent-desc" rows="15">{{.Description}}</textarea>
<textarea name="desc" id="desc" class="form-control torrent-desc" rows="15">{{.Description}}</textarea>
</div>
<div class="form-group">
<label for="website_link">{{T "website_link"}}</label>
<input name="website_link" id="website_link" class="form-control" type="text" value="{{.WebsiteLink}}">
</div>
{{block "captcha" .}}{{end}}

Voir le fichier

@ -4,6 +4,12 @@
<div class="blockBody">
{{with .Torrent}}
<hr>
{{ range (index $.FormErrors "errors")}}
<div class="alert alert-danger"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-exclamation-sign"></i> {{ . }}</div>
{{end}}
{{ range (index $.Infos "infos")}}
<div class="alert alert-info"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-info-sign"></i> {{ . }}</div>
{{end}}
<div class="content" style="margin-bottom: 2em;">
<div class="row">
<div class="col-md-12">
@ -16,9 +22,11 @@
<div class="col-md-12">
<div style="float: left;">
{{ if Sukebei }}
<img style="float:left; margin-right: 1em;" src="{{$.URL.Parse (printf "/img/torrents/sukebei/%s%s.png" .Category .SubCategory) }}" title="{{ T (Category_Sukebei .Category .SubCategory) }}">
<img style="float:left; margin-right: 1em;" src="{{$.URL.Parse (printf "/img/torrents/sukebei/%s%s.png" .Category .SubCategory) }}" title="{{ T (Category_Sukebei .Category .SubCategory) }}">
<span style="vertical-align:middle;font-size:large;">{{ T (Category_Sukebei .Category .SubCategory) }}</span>
{{ else }}
<img style="float:left; margin-right: 1em;" src="{{$.URL.Parse (printf "/img/torrents/%s.png" .SubCategory) }}" title="{{ T (Category_Nyaa .Category .SubCategory) }}">
<img style="float:left; margin-right: 1em;" src="{{$.URL.Parse (printf "/img/torrents/%s.png" .SubCategory) }}" title="{{ T (Category_Nyaa .Category .SubCategory) }}">
<span style="vertical-align:middle;font-size:large;">{{ T (Category_Nyaa .Category .SubCategory) }}</span>
{{ end }}
<br />
<h4 style="display:inline-block">
@ -72,31 +80,23 @@
{{end}}
<div class="row">
<div class="col-md-12 col-xs-6">
<div class="row">
<div class="col-md-4">{{T "seeders"}}</div>
<div class="col-md-4">{{T "leechers"}}</div>
<div class="col-md-4">{{T "completed"}}</div>
</div>
</div>
<div class="col-md-12 col-xs-6">
<div class="row">
{{if .LastScrape.IsZero}}
<div class="col-md-12" align="center">{{T "unknown"}}</div>
{{else}}
<div class="col-md-4">{{.Seeders}}</div>
<div class="col-md-4">{{.Leechers}}</div>
<div class="col-md-4"><span class="completed" style="">{{.Completed}}</span></div>
{{end}}
</div>
</div>
<div class="col-md-12 col-xs-12">
<div class="row">
{{if not .LastScrape.IsZero}}
<div class="col-md-4 col-xs-8">{{T "last_scraped"}}</div>
<div class="col-md-8 col-xs-4 date-short">{{ formatDateRFC .LastScrape }}</div>
{{end}}
</div>
</div>
<div class="row">
<div class="col-md-4">{{T "seeders"}}</div>
<div class="col-md-4">{{T "leechers"}}</div>
<div class="col-md-4">{{T "completed"}}</div>
</div>
</div>
<div class="col-md-12 col-xs-6">
<div class="row">
{{if .LastScrape.IsZero}}
<div class="col-md-12" align="center">{{T "unknown"}}</div>
{{else}}
<div class="col-md-4">{{.Seeders}}</div>
<div class="col-md-4">{{.Leechers}}</div>
<div class="col-md-4"><span class="completed" style="">{{.Completed}}</span></div>
{{end}}
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
@ -105,6 +105,11 @@
<div class="leechs" style="width: {{ calcWidthLeech .Seeders .Leechers }}%;"></div>
</div>
</div>
<div class="col-md-12 col-xs-12">
{{if not .LastScrape.IsZero}}
{{T "last_scraped"}}<span class="date-short">{{ formatDateRFC .LastScrape }}</span>
{{end}}
</div>
</div>
<hr>
</div>

Voir le fichier

@ -751,6 +751,10 @@
"id": "last_scraped",
"translation": "Dernier scrape effectué : "
},
{
"id": "server_status_link",
"translation": "Statut du serveur"
},
{
"id": "no_database_dumps_available",
"translation": "Aucune sauvegarde de base de données n'est disponible en ce moment."

Voir le fichier

@ -197,7 +197,7 @@
},
{
"id": "404_not_found",
"translation": "404 ページが見つかりません"
"translation": "404 - ページが見つかりません"
},
{
"id": "no_torrents_uploaded",
@ -755,6 +755,10 @@
"id": "last_scraped",
"translation": "最終更新日: "
},
{
"id": "server_status_link",
"translation": "サーバーの状態"
},
{
"id": "no_database_dumps_available",
"translation": "現在利用可能なデータベースダンプはありません。"

Voir le fichier

@ -53,7 +53,7 @@
},
{
"id":"terms_conditions_confirm",
"translation": "Dacă daţi click <strong class=\"label label-primary\">Register</strong>, sunteţi de acord cu <a href=\"#\" data-toggle=\"modal\" data-target=\"#t_and_c_m\">Termenii şi Condiţiile</a> acestui site, incluzand folosirea noastra de Cookie-uri."
"translation": "Dacă daţi click <strong class=\"label label-primary\">Register</strong>, sunteţi de acord cu <a href=\"#\" data-toggle=\"modal\" data-target=\"#t_and_c_m\">Termenii şi Condiţiile</a> acestui site, incluzând folosirea noastra de Cookie-uri."
},
{
"id":"signin",
@ -105,7 +105,7 @@
},
{
"id":"signup_verification_noemail",
"translation": "Înregistrarea a fost reusită, acum îţi poţi folosi contul."
"translation": "Înregistrarea a fost reuşită, acum îţi poţi folosi contul."
},
{
"id":"settings",
@ -133,7 +133,7 @@
},
{
"id":"profile_page",
"translation": "%s Pagina de profil"
"translation": "Pagina de profil a lui %s"
},
{
"id":"see_more_torrents_from",
@ -201,7 +201,7 @@
},
{
"id": "no_torrents_uploaded",
"translation": "Niciun torrent uploadad incă!"
"translation": "Niciun torrent uploadat încă!"
},
{
"id": "profile",
@ -229,7 +229,7 @@
},
{
"id": "notice_keep_seeding",
"translation": "ATENŢIE: STAI LA SEED ŞI ACTIVEAZĂ DHT"
"translation": "ATENŢIE: STAI LA SEED ŞI ACTIVEAZĂ DHT ÎN CLIENTUL DE TORRENTE!"
},
{
"id": "official_nyaapocalipse_faq",
@ -738,5 +738,25 @@
{
"id": "cancel",
"translation": "Anulează"
}
]
},
{
"id": "please_include_our_tracker",
"translation": "Te rog include udp://tracker.doko.moe:6969 la trackerele tale."
},
{
"id": "unknown",
"translation": "Necunoscut"
},
{
"id": "last_scraped",
"translation": "Ultimul scrape: "
},
{
"id": "server_status_link",
"translation": "Statusul servărului poate fi găsit aici"
},
{
"id": "no_database_dumps_available",
"translation": "Dumpurile bazei de date nu sunt disponibile în acest moment."
}
]

Voir le fichier

@ -197,7 +197,7 @@
},
{
"id": "404_not_found",
"translation": "404 Not Found"
"translation": "404 ไม่พบหน้านี้"
},
{
"id": "no_torrents_uploaded",
@ -751,8 +751,12 @@
"id": "last_scraped",
"translation": "Scrap ครั้งล่าสุด: "
},
{
"id": "server_status_link",
"translation": "สามารถดูสถานะของเซิร์ฟเวอร์ได้ที่นี่"
},
{
"id": "no_database_dumps_available",
"translation": "ยังไม่มีไฟล์ดัมพ์ฐานข้อมูลในขณะนี้"
}
}
]

82
util/messages/messages.go Fichier normal
Voir le fichier

@ -0,0 +1,82 @@
package Messages
import (
"github.com/gorilla/context"
"fmt"
"net/http"
)
const MessagesKey = "messages"
type Messages struct {
Errors map[string][]string
Infos map[string][]string
r *http.Request
}
func GetMessages(r *http.Request) Messages {
if rv := context.Get(r, MessagesKey); rv != nil {
return rv.(Messages)
} else {
context.Set(r, MessagesKey, Messages{})
return Messages{make(map[string][]string),make(map[string][]string), r}
}
}
func (mes Messages) AddError(name string, msg string) {
mes.Errors[name] = append(mes.Errors[name], msg)
mes.setMessagesInContext()
}
func (mes Messages) AddErrorf( name string, msg string, args ...interface{}) {
mes.AddError(name, fmt.Sprintf(msg, args...))
}
func (mes Messages) ImportFromError(name string, err error) {
mes.AddError(name, err.Error())
}
func (mes Messages) AddInfo(name string, msg string) {
mes.Infos[name] = append(mes.Infos[name], msg)
mes.setMessagesInContext()
}
func (mes Messages) AddInfof(name string, msg string, args ...interface{}) {
mes.AddInfo(name, fmt.Sprintf(msg, args...))
}
func (mes Messages) ClearErrors() {
mes.Infos = nil
mes.setMessagesInContext()
}
func (mes Messages) ClearInfos() {
mes.Errors = nil
mes.setMessagesInContext()
}
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
}
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]
}
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
}
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]
}
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
}
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
}
func (mes Messages) setMessagesInContext() {
context.Set(mes.r, MessagesKey, mes)
}

Voir le fichier

@ -44,16 +44,21 @@ func stringIsAscii(input string) bool {
}
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)
search, tor, count, err = searchByQuery(r, pagenum, true, false)
return
}
func SearchByQueryWithUser(r *http.Request, pagenum int) (search common.SearchParam, tor []model.Torrent, count int, err error) {
search, tor, count, err = searchByQuery(r, pagenum, true, true)
return
}
func SearchByQueryNoCount(r *http.Request, pagenum int) (search common.SearchParam, tor []model.Torrent, err error) {
search, tor, _, err = searchByQuery(r, pagenum, false)
search, tor, _, err = searchByQuery(r, pagenum, false, false)
return
}
func searchByQuery(r *http.Request, pagenum int, countAll bool) (
func searchByQuery(r *http.Request, pagenum int, countAll bool, withUser bool) (
search common.SearchParam, tor []model.Torrent, count int, err error,
) {
max, err := strconv.ParseUint(r.URL.Query().Get("max"), 10, 32)
@ -211,8 +216,10 @@ func searchByQuery(r *http.Request, pagenum int, countAll bool) (
tor, count, err = cache.Impl.Get(search, func() (tor []model.Torrent, count int, err error) {
if countAll {
if countAll && !withUser {
tor, count, err = torrentService.GetTorrentsOrderBy(&parameters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
} else if withUser {
tor, count, err = torrentService.GetTorrentsWithUserOrderBy(&parameters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
} else {
tor, err = torrentService.GetTorrentsOrderByNoCount(&parameters, orderBy, int(search.Max), int(search.Max)*(search.Page-1))
}