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

Controllers are now separated

They are in different folders and all loaded in controllers/router.go.
This means that you only have to create a folder with a router.go file and import this folder in main router.go to add a handler.
Cette révision appartient à :
akuma06 2017-07-16 17:14:21 +02:00
Parent eb5ded4a27
révision 2c8344faf9
58 fichiers modifiés avec 1989 ajouts et 1588 suppressions

Voir le fichier

@ -1,4 +1,4 @@
package controllers
package activitiesController
import (
"html"
@ -6,6 +6,7 @@ import (
"strconv"
"strings"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models/activities"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/log"
@ -21,7 +22,7 @@ func ActivityListHandler(c *gin.Context) {
filter := c.Query("filter")
var err error
currentUser := getUser(c)
currentUser := router.GetUser(c)
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {

Voir le fichier

@ -0,0 +1,8 @@
package activitiesController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
router.Get().Any("/activities", ActivityListHandler)
router.Get().Any("/activities/p/:page", ActivityListHandler)
}

Voir le fichier

@ -1,4 +1,4 @@
package controllers
package apiController
import (
"html"
@ -8,6 +8,7 @@ import (
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/controllers/feed"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/models/users"
@ -80,7 +81,7 @@ func APIHandler(c *gin.Context) {
c.Header("Content-Type", "application/json")
t := c.Query("t")
if t != "" {
RSSTorznabHandler(c)
feedController.RSSTorznabHandler(c)
} else {
page := c.Param("page")
whereParams := structs.WhereParams{}
@ -467,7 +468,7 @@ func APISearchHandler(c *gin.Context) {
return
}
if pagenum <= 0 {
NotFoundHandler(c)
c.AbortWithStatus(http.StatusNotFound)
return
}
}

20
controllers/api/router.go Fichier normal
Voir le fichier

@ -0,0 +1,20 @@
package apiController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
api := router.Get().Group("/api")
{
api.GET("", APIHandler)
api.GET("/p/:page", APIHandler)
api.GET("/view/:id", APIViewHandler)
api.HEAD("/view/:id", APIViewHeadHandler)
api.POST("/upload", APIUploadHandler)
api.POST("/login", APILoginHandler)
api.GET("/token/check", APICheckTokenHandler)
api.GET("/token/refresh", APIRefreshTokenHandler)
api.Any("/search", APISearchHandler)
api.Any("/search/p/:page", APISearchHandler)
api.PUT("/update", APIUpdateHandler)
}
}

10
controllers/captcha/router.go Fichier normal
Voir le fichier

@ -0,0 +1,10 @@
package captchaController
import (
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/utils/captcha"
)
func init() {
router.Get().Any("/captcha/*hash", captcha.ServeFiles)
}

Voir le fichier

@ -1,4 +1,4 @@
package controllers
package databasedumpsController
import (
"fmt"

Voir le fichier

@ -0,0 +1,7 @@
package databasedumpsController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
router.Get().Any("/dumps", DatabaseDumpHandler)
}

Voir le fichier

@ -1,4 +1,4 @@
package controllers
package faqController
import (
"github.com/NyaaPantsu/nyaa/templates"

7
controllers/faq/router.go Fichier normal
Voir le fichier

@ -0,0 +1,7 @@
package faqController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
router.Get().Any("/faq", FaqHandler)
}

69
controllers/feed/eztv.go Fichier normal
Voir le fichier

@ -0,0 +1,69 @@
package feedController
import (
"net/http"
"strconv"
"strings"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/utils/feeds"
"github.com/gin-gonic/gin"
"github.com/gorilla/feeds"
)
// RSSEztvHandler : Controller for displaying rss feed, accepting common search arguments
func RSSEztvHandler(c *gin.Context) {
// We only get the basic variable for rss based on search param
torrents, createdAsTime, title, err := getTorrentList(c)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
feed := &nyaafeeds.RssFeed{
Title: title,
Link: config.WebAddress() + "/",
PubDate: createdAsTime.String(),
}
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
for i, torrent := range torrents {
torrentJSON := torrent.ToJSON()
feed.Items[i] = &nyaafeeds.RssItem{
Title: torrentJSON.Name,
Link: config.WebAddress() + "/download/" + torrentJSON.Hash,
Category: &nyaafeeds.RssCategory{
Domain: config.WebAddress() + "/search?c=" + torrentJSON.Category + "_" + torrentJSON.SubCategory,
},
Description: string(torrentJSON.Description),
Comments: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
PubDate: torrent.Date.Format(time.RFC822),
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
Enclosure: &nyaafeeds.RssEnclosure{
URL: config.WebAddress() + "/download/" + strings.TrimSpace(torrentJSON.Hash),
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
Type: "application/x-bittorrent",
},
Torrent: &nyaafeeds.RssTorrent{
Xmlns: "http://xmlns.ezrss.it/0.1/",
FileName: torrentJSON.Name + ".torrent",
ContentLength: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
InfoHash: torrentJSON.Hash,
MagnetURI: string(torrentJSON.Magnet),
},
}
}
// allow cross domain AJAX requests
c.Header("Access-Control-Allow-Origin", "*")
rss, rssErr := feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
_, writeErr := c.Writer.Write([]byte(rss))
if writeErr != nil {
c.AbortWithError(http.StatusInternalServerError, writeErr)
}
}

85
controllers/feed/helpers.go Fichier normal
Voir le fichier

@ -0,0 +1,85 @@
package feedController
import (
"errors"
"html"
"strconv"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/NyaaPantsu/nyaa/utils/feeds"
"github.com/NyaaPantsu/nyaa/utils/search"
"github.com/gin-gonic/gin"
)
func getTorrentList(c *gin.Context) (torrents []models.Torrent, createdAsTime time.Time, title string, err error) {
page := c.Param("page")
userID := c.Param("id")
cat := c.Query("cat")
offset := 0
if c.Query("offset") != "" {
offset, err = strconv.Atoi(html.EscapeString(c.Query("offset")))
if err != nil {
return
}
}
createdAsTime = time.Now()
if len(torrents) > 0 {
createdAsTime = torrents[0].Date
}
title = "Nyaa Pantsu"
if config.IsSukebei() {
title = "Sukebei Pantsu"
}
pagenum := 1
if page == "" && offset > 0 { // first page for offset is 0
pagenum = offset + 1
} else if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if err != nil {
return
}
}
if pagenum <= 0 {
err = errors.New("Page number is invalid")
return
}
if userID != "" {
userIDnum := 0
userIDnum, err = strconv.Atoi(html.EscapeString(userID))
// Should we have a feed for anonymous uploads?
if err != nil || userIDnum == 0 {
return
}
_, _, err = users.FindForAdmin(uint(userIDnum))
if err != nil {
return
}
// Set the user ID on the request, so that SearchByQuery finds it.
query := c.Request.URL.Query()
query.Set("userID", userID)
c.Request.URL.RawQuery = query.Encode()
}
if cat != "" {
query := c.Request.URL.Query()
catConv := nyaafeeds.ConvertToCat(cat)
if catConv == "" {
return
}
query.Set("c", catConv)
c.Request.URL.RawQuery = query.Encode()
}
_, torrents, err = search.ByQueryNoCount(c, pagenum)
return
}

59
controllers/feed/magnet.go Fichier normal
Voir le fichier

@ -0,0 +1,59 @@
package feedController
import (
"net/http"
"strconv"
"strings"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/utils/feeds"
"github.com/gin-gonic/gin"
"github.com/gorilla/feeds"
)
// RSSMagnetHandler : Controller for displaying rss feeds with magnet URL, accepting common search arguments
func RSSMagnetHandler(c *gin.Context) {
// We only get the basic variable for rss based on search param
torrents, createdAsTime, title, err := getTorrentList(c)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
feed := &nyaafeeds.RssFeed{
Title: title,
Link: config.WebAddress() + "/",
PubDate: createdAsTime.String(),
}
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
for i, torrent := range torrents {
torrentJSON := torrent.ToJSON()
feed.Items[i] = &nyaafeeds.RssItem{
Title: torrentJSON.Name,
Link: &nyaafeeds.RssMagnetLink{Text: string(torrentJSON.Magnet)},
Description: string(torrentJSON.Description),
PubDate: torrent.Date.Format(time.RFC822),
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
Enclosure: &nyaafeeds.RssEnclosure{
URL: config.WebAddress() + "/download/" + strings.TrimSpace(torrentJSON.Hash),
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
Type: "application/x-bittorrent",
},
}
}
// allow cross domain AJAX requests
c.Header("Access-Control-Allow-Origin", "*")
rss, rssErr := feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
_, writeErr := c.Writer.Write([]byte(rss))
if writeErr != nil {
c.AbortWithError(http.StatusInternalServerError, writeErr)
}
}

15
controllers/feed/router.go Fichier normal
Voir le fichier

@ -0,0 +1,15 @@
package feedController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
router.Get().Any("/feed", RSSHandler)
router.Get().Any("/feed/p/:page", RSSHandler)
router.Get().Any("/feed/magnet", RSSMagnetHandler)
router.Get().Any("/feed/magnet/p/:page", RSSMagnetHandler)
router.Get().Any("/feed/torznab", RSSTorznabHandler)
router.Get().Any("/feed/torznab/api", RSSTorznabHandler)
router.Get().Any("/feed/torznab/p/:page", RSSTorznabHandler)
router.Get().Any("/feed/eztv", RSSEztvHandler)
router.Get().Any("/feed/eztv/p/:page", RSSEztvHandler)
}

59
controllers/feed/rss.go Fichier normal
Voir le fichier

@ -0,0 +1,59 @@
package feedController
import (
"net/http"
"strconv"
"strings"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/utils/feeds"
"github.com/gin-gonic/gin"
"github.com/gorilla/feeds"
)
// RSSHandler : Controller for displaying rss feed, accepting common search arguments
func RSSHandler(c *gin.Context) {
// We only get the basic variable for rss based on search param
torrents, createdAsTime, title, err := getTorrentList(c)
if err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
}
feed := &nyaafeeds.RssFeed{
Title: title,
Link: config.WebAddress() + "/",
PubDate: createdAsTime.String(),
}
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
for i, torrent := range torrents {
torrentJSON := torrent.ToJSON()
feed.Items[i] = &nyaafeeds.RssItem{
Title: torrentJSON.Name,
Link: config.WebAddress() + "/download/" + torrentJSON.Hash,
Description: string(torrentJSON.Description),
PubDate: torrent.Date.Format(time.RFC822),
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
Enclosure: &nyaafeeds.RssEnclosure{
URL: config.WebAddress() + "/download/" + strings.TrimSpace(torrentJSON.Hash),
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
Type: "application/x-bittorrent",
},
}
}
// allow cross domain AJAX requests
c.Header("Access-Control-Allow-Origin", "*")
rss, rssErr := feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
_, writeErr := c.Writer.Write([]byte(rss))
if writeErr != nil {
c.AbortWithError(http.StatusInternalServerError, writeErr)
}
}

194
controllers/feed/torznab.go Fichier normal
Voir le fichier

@ -0,0 +1,194 @@
package feedController
import (
"net/http"
"strconv"
"strings"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/utils/categories"
"github.com/NyaaPantsu/nyaa/utils/feeds"
"github.com/NyaaPantsu/nyaa/utils/publicSettings"
"github.com/gin-gonic/gin"
"github.com/gorilla/feeds"
)
// RSSTorznabHandler : Controller for displaying rss feed, accepting common search arguments
func RSSTorznabHandler(c *gin.Context) {
t := c.Query("t")
rss := ""
title := "Nyaa Pantsu"
if config.IsSukebei() {
title = "Sukebei Pantsu"
}
if t == "caps" {
T := publicSettings.GetTfuncFromRequest(c)
cats := categories.GetSelect(true, true)
var categories []*nyaafeeds.RssCategoryTorznab
categories = append(categories, &nyaafeeds.RssCategoryTorznab{
ID: "5070",
Name: "Anime",
Description: "Anime",
})
last := 0
for _, v := range cats {
if len(v.ID) <= 2 {
categories = append(categories, &nyaafeeds.RssCategoryTorznab{
ID: nyaafeeds.ConvertFromCat(v.ID),
Name: string(T(v.Name)),
})
last++
} else {
categories[last].Subcat = append(categories[last].Subcat, &nyaafeeds.RssSubCat{
ID: nyaafeeds.ConvertFromCat(v.ID),
Name: string(T(v.Name)),
})
}
}
feed := &nyaafeeds.RssCaps{
Server: &nyaafeeds.RssServer{
Version: "1.0",
Title: title,
Strapline: "...",
Email: config.Get().Email.From,
URL: config.WebAddress(),
Image: config.WebAddress() + "/img/logo.png",
},
Limits: &nyaafeeds.RssLimits{
Max: "300",
Default: "50",
},
Registration: &nyaafeeds.RssRegistration{
Available: "yes",
Open: "yes",
},
Searching: &nyaafeeds.RssSearching{
Search: &nyaafeeds.RssSearch{
Available: "yes",
SupportedParams: "q",
},
TvSearch: &nyaafeeds.RssSearch{
Available: "no",
},
MovieSearch: &nyaafeeds.RssSearch{
Available: "no",
},
},
Categories: &nyaafeeds.RssCategories{
Category: categories,
},
}
var rssErr error
rss, rssErr = feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
} else {
// We only get the basic variable for rss based on search param
torrents, createdAsTime, title, err := getTorrentList(c)
if err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
}
feed := &nyaafeeds.RssFeed{
Title: title,
Xmlns: "http://torznab.com/schemas/2015/feed",
Link: config.WebAddress() + "/",
PubDate: createdAsTime.String(),
}
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
for i, torrent := range torrents {
torrentJSON := torrent.ToJSON()
filesNumber := ""
if len(torrentJSON.FileList) > 0 {
filesNumber = strconv.Itoa(len(torrentJSON.FileList))
}
seeders := ""
if torrentJSON.Seeders > 0 {
seeders = strconv.Itoa(int(torrentJSON.Seeders))
}
leechers := ""
if torrentJSON.Leechers > 0 {
leechers = strconv.Itoa(int(torrentJSON.Leechers))
}
feed.Items[i] = &nyaafeeds.RssItem{
Title: torrentJSON.Name,
Link: config.WebAddress() + "/download/" + torrentJSON.Hash,
Category: &nyaafeeds.RssCategory{
Domain: config.WebAddress() + "/search?c=" + torrentJSON.Category + "_" + torrentJSON.SubCategory,
},
Description: string(torrentJSON.Description),
Comments: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
PubDate: torrent.Date.Format(time.RFC822),
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
Enclosure: &nyaafeeds.RssEnclosure{
URL: config.WebAddress() + "/download/" + strings.TrimSpace(torrentJSON.Hash),
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
Type: "application/x-bittorrent",
},
}
torznab := []*nyaafeeds.RssTorznab{}
if torrentJSON.Filesize > 0 {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "size",
Value: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
})
}
if filesNumber != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "files",
Value: filesNumber,
})
}
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "grabs",
Value: strconv.Itoa(int(torrentJSON.Completed)),
})
if seeders != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "seeders",
Value: seeders,
})
}
if leechers != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "leechers",
Value: leechers,
})
}
if torrentJSON.Hash != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "infohash",
Value: torrentJSON.Hash,
})
}
if torrentJSON.Magnet != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "magneturl",
Value: string(torrentJSON.Magnet),
})
}
if len(torznab) > 0 {
feed.Items[i].Torznab = torznab
}
}
var rssErr error
rss, rssErr = feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
}
// allow cross domain AJAX requests
c.Header("Access-Control-Allow-Origin", "*")
_, writeErr := c.Writer.Write([]byte(rss))
if writeErr != nil {
c.AbortWithError(http.StatusInternalServerError, writeErr)
}
}

Voir le fichier

@ -1,16 +1,18 @@
package controllers
package middlewares
import (
"net/http"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/log"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/gin-gonic/gin"
)
func errorMiddleware() gin.HandlerFunc {
// Middleware for managing errors on status
func ErrorMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Next()
if config.Get().Environment == "DEVELOPMENT" {
@ -31,10 +33,10 @@ func errorMiddleware() gin.HandlerFunc {
}
}
// Make sure the user is a moderator, otherwise return forbidden
func modMiddleware() gin.HandlerFunc {
// ModMiddleware Make sure the user is a moderator, otherwise return forbidden
func ModMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
currentUser := getUser(c)
currentUser := router.GetUser(c)
if !currentUser.HasAdmin() {
NotFoundHandler(c)
}
@ -44,7 +46,7 @@ func modMiddleware() gin.HandlerFunc {
func pprofHandler(handler http.HandlerFunc) gin.HandlerFunc {
return func(c *gin.Context) {
currentUser := getUser(c)
currentUser := router.GetUser(c)
if currentUser.HasAdmin() {
handler.ServeHTTP(c.Writer, c.Request)
} else {

Voir le fichier

@ -1,4 +1,4 @@
package controllers
package middlewares
import (
"net/http"

Voir le fichier

@ -0,0 +1,7 @@
package middlewares
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
router.Get().Use(ErrorMiddleware())
}

36
controllers/moderator/api.go Fichier normal
Voir le fichier

@ -0,0 +1,36 @@
package moderatorController
import (
"net/http"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/gin-gonic/gin"
)
// APIMassMod : This function is used on the frontend for the mass
/* Query is: action=status|delete|owner|category|multiple
* Needed: torrent_id[] Ids of torrents in checkboxes of name torrent_id
*
* Needed on context:
* status=0|1|2|3|4 according to config/find.go (can be omitted if action=delete|owner|category|multiple)
* owner is the User ID of the new owner of the torrents (can be omitted if action=delete|status|category|multiple)
* category is the category string (eg. 1_3) of the new category of the torrents (can be omitted if action=delete|status|owner|multiple)
*
* withreport is the bool to enable torrent reports deletion (can be omitted)
*
* In case of action=multiple, torrents can be at the same time changed status, owner and category
*/
func APIMassMod(c *gin.Context) {
torrentManyAction(c)
messages := msg.GetMessages(c) // new utils for errors and infos
c.Header("Content-Type", "application/json")
var mapOk map[string]interface{}
if !messages.HasErrors() {
mapOk = map[string]interface{}{"ok": true, "infos": messages.GetAllInfos()["infos"]}
} else { // We need to show error messages
mapOk = map[string]interface{}{"ok": false, "errors": messages.GetAllErrors()["errors"]}
}
c.JSON(http.StatusOK, mapOk)
}

Voir le fichier

@ -0,0 +1,53 @@
package moderatorController
import (
"html"
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/activities"
"github.com/NyaaPantsu/nyaa/models/comments"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/log"
"github.com/gin-gonic/gin"
)
// CommentsListPanel : Controller for listing comments, can accept pages and userID
func CommentsListPanel(c *gin.Context) {
page := c.Param("page")
pagenum := 1
offset := 100
userid := c.Query("userid")
var err error
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
var conditions string
var values []interface{}
if userid != "" {
conditions = "user_id = ?"
values = append(values, userid)
}
comments, nbComments := comments.FindAll(offset, (pagenum-1)*offset, conditions, values...)
nav := templates.Navigation{nbComments, offset, pagenum, "mod/comments/p"}
templates.ModelList(c, "admin/commentlist.jet.html", comments, nav, templates.NewSearchForm(c))
}
// CommentDeleteModPanel : Controller for deleting a comment
func CommentDeleteModPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
comment, _, err := comments.Delete(uint(id))
if err == nil {
activities.Log(&models.User{}, comment.Identifier(), "delete", "comment_deleted_by", strconv.Itoa(int(comment.ID)), comment.User.Username, router.GetUser(c).Username)
}
c.Redirect(http.StatusSeeOther, "/mod/comments?deleted")
}

Voir le fichier

@ -0,0 +1,64 @@
package moderatorController
import (
"html"
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/log"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/search"
"github.com/gin-gonic/gin"
)
// DeletedTorrentsModPanel : Controller for viewing deleted torrents, accept common search arguments
func DeletedTorrentsModPanel(c *gin.Context) {
page := c.Param("page")
messages := msg.GetMessages(c) // new utils for errors and infos
deleted := c.Request.URL.Query()["deleted"]
unblocked := c.Request.URL.Query()["unblocked"]
blocked := c.Request.URL.Query()["blocked"]
if deleted != nil {
messages.AddInfoT("infos", "torrent_deleted_definitely")
}
if blocked != nil {
messages.AddInfoT("infos", "torrent_blocked")
}
if unblocked != nil {
messages.AddInfoT("infos", "torrent_unblocked")
}
var err error
pagenum := 1
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
searchParam, torrents, count, err := search.ByQueryDeleted(c, pagenum)
if err != nil {
messages.Error(err)
}
category := ""
if len(searchParam.Category) > 0 {
category = searchParam.Category[0].String()
}
searchForm := templates.SearchForm{
TorrentParam: searchParam,
Category: category,
ShowItemsPerPage: true,
}
nav := templates.Navigation{count, int(searchParam.Max), pagenum, "mod/torrents/deleted/p"}
search := searchForm
templates.ModelList(c, "admin/torrentlist.jet.html", torrents, nav, search)
}
// DeletedTorrentsPostPanel : Controller for viewing deleted torrents after a mass update, accept common search arguments
func DeletedTorrentsPostPanel(c *gin.Context) {
torrentManyAction(c)
DeletedTorrentsModPanel(c)
}

Voir le fichier

@ -0,0 +1,157 @@
package moderatorController
import (
"strconv"
"strings"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/activities"
"github.com/NyaaPantsu/nyaa/models/reports"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/NyaaPantsu/nyaa/utils/categories"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/search/structs"
"github.com/gin-gonic/gin"
)
/*
* Controller to modify multiple torrents and can be used by the owner of the torrent or admin
*/
func torrentManyAction(c *gin.Context) {
currentUser := router.GetUser(c)
torrentsSelected := c.PostFormArray("torrent_id") // should be []string
action := c.PostForm("action")
status, _ := strconv.Atoi(c.PostForm("status"))
owner, _ := strconv.Atoi(c.PostForm("owner"))
category := c.PostForm("category")
withReport, _ := strconv.ParseBool(c.DefaultPostForm("withreport", "false"))
messages := msg.GetMessages(c) // new utils for errors and infos
catID, subCatID := -1, -1
var err error
if action == "" {
messages.AddErrorT("errors", "no_action_selected")
}
if action == "status" && c.PostForm("status") == "" { // We need to check the form value, not the int one because hidden is 0
messages.AddErrorT("errors", "no_move_location_selected")
}
if action == "owner" && c.PostForm("owner") == "" { // We need to check the form value, not the int one because renchon is 0
messages.AddErrorT("errors", "no_owner_selected")
}
if action == "category" && category == "" {
messages.AddErrorT("errors", "no_category_selected")
}
if len(torrentsSelected) == 0 {
messages.AddErrorT("errors", "select_one_element")
}
if !config.Get().Torrents.Status[status] { // Check if the status exist
messages.AddErrorTf("errors", "no_status_exist", status)
status = -1
}
if !currentUser.HasAdmin() {
if c.PostForm("status") != "" { // Condition to check if a user try to change torrent status without having the right permission
if (status == models.TorrentStatusTrusted && !currentUser.IsTrusted()) || status == models.TorrentStatusAPlus || status == 0 {
status = models.TorrentStatusNormal
}
}
if c.PostForm("owner") != "" { // Only admins can change owner of torrents
owner = -1
}
withReport = false // Users should not be able to remove reports
}
if c.PostForm("owner") != "" && currentUser.HasAdmin() { // We check that the user given exist and if not we return an error
_, _, errorUser := users.FindForAdmin(uint(owner))
if errorUser != nil {
messages.AddErrorTf("errors", "no_user_found_id", owner)
owner = -1
}
}
if category != "" {
catsSplit := strings.Split(category, "_")
// need this to prevent out of index panics
if len(catsSplit) == 2 {
catID, err = strconv.Atoi(catsSplit[0])
if err != nil {
messages.AddErrorT("errors", "invalid_torrent_category")
}
subCatID, err = strconv.Atoi(catsSplit[1])
if err != nil {
messages.AddErrorT("errors", "invalid_torrent_category")
}
if !categories.Exists(category) {
messages.AddErrorT("errors", "invalid_torrent_category")
}
}
}
if !messages.HasErrors() {
for _, torrentID := range torrentsSelected {
id, _ := strconv.Atoi(torrentID)
torrent, _ := torrents.FindByID(uint(id))
if torrent.ID > 0 && currentUser.CurrentOrAdmin(torrent.UploaderID) {
if action == "status" || action == "multiple" || action == "category" || action == "owner" {
/* If we don't delete, we make changes according to the form posted and we save at the end */
if c.PostForm("status") != "" && status != -1 {
torrent.Status = status
messages.AddInfoTf("infos", "torrent_moved", torrent.Name)
}
if c.PostForm("owner") != "" && owner != -1 {
torrent.UploaderID = uint(owner)
messages.AddInfoTf("infos", "torrent_owner_changed", torrent.Name)
}
if category != "" && catID != -1 && subCatID != -1 {
torrent.Category = catID
torrent.SubCategory = subCatID
messages.AddInfoTf("infos", "torrent_category_changed", torrent.Name)
}
/* Changes are done, we save */
_, err := torrent.UpdateUnscope()
if err == nil {
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), "edited", "torrent_edited_by", strconv.Itoa(int(torrent.ID)), username, router.GetUser(c).Username)
}
} else if action == "delete" {
if status == models.TorrentStatusBlocked { // Then we should lock torrents before deleting them
torrent.Status = status
messages.AddInfoTf("infos", "torrent_moved", torrent.Name)
torrent.UpdateUnscope()
}
_, _, err = torrent.Delete(false)
if err != nil {
messages.ImportFromError("errors", err)
} else {
messages.AddInfoTf("infos", "torrent_deleted", torrent.Name)
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), "deleted", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, router.GetUser(c).Username)
}
} else {
messages.AddErrorTf("errors", "no_action_exist", action)
}
if withReport {
whereParams := structs.CreateWhereParams("torrent_id = ?", torrentID)
reports, _, _ := reports.FindOrderBy(&whereParams, "", 0, 0)
for _, report := range reports {
report.Delete(false)
}
messages.AddInfoTf("infos", "torrent_reports_deleted", torrent.Name)
}
} else {
messages.AddErrorTf("errors", "torrent_not_exist", torrentID)
}
}
}
}

22
controllers/moderator/index.go Fichier normal
Voir le fichier

@ -0,0 +1,22 @@
package moderatorController
import (
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/comments"
"github.com/NyaaPantsu/nyaa/models/reports"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/gin-gonic/gin"
)
// IndexModPanel : Controller for showing index page of Mod Panel
func IndexModPanel(c *gin.Context) {
offset := 10
torrents, _, _ := torrents.FindAll(offset, 0)
users, _ := users.FindUsersForAdmin(offset, 0)
comments, _ := comments.FindAll(offset, 0, "", "")
torrentReports, _, _ := reports.GetAll(offset, 0)
templates.PanelAdmin(c, torrents, models.TorrentReportsToJSON(torrentReports), users, comments)
}

Voir le fichier

@ -0,0 +1,56 @@
package moderatorController
import (
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/NyaaPantsu/nyaa/templates"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/validator/torrent"
"github.com/gin-gonic/gin"
)
// TorrentReassignModPanel : Controller for reassigning a torrent, after GET request
func TorrentReassignModPanel(c *gin.Context) {
templates.Form(c, "admin/reassign.jet.html", torrentValidator.ReassignForm{})
}
// ExecuteAction : Function for applying the changes from ReassignForm
func ExecuteReassign(f *torrentValidator.ReassignForm) (int, error) {
var toBeChanged []uint
var err error
if f.By == "olduser" {
toBeChanged, err = users.FindOldUploadsByUsername(f.Data)
if err != nil {
return 0, err
}
} else if f.By == "torrentid" {
toBeChanged = f.Torrents
}
num := 0
for _, torrentID := range toBeChanged {
torrent, err2 := torrents.FindRawByID(torrentID)
if err2 == nil {
torrent.UploaderID = f.AssignTo
torrent.Update(true)
num++
}
}
return num, nil
}
// TorrentPostReassignModPanel : Controller for reassigning a torrent, after POST request
func TorrentPostReassignModPanel(c *gin.Context) {
var rForm torrentValidator.ReassignForm
messages := msg.GetMessages(c)
if rForm.ExtractInfo(c) {
count, err2 := ExecuteReassign(&rForm)
if err2 != nil {
messages.AddErrorT("errors", "something_went_wrong")
} else {
messages.AddInfoTf("infos", "nb_torrents_updated", count)
}
}
templates.Form(c, "admin/reassign.jet.html", rForm)
}

Voir le fichier

@ -0,0 +1,51 @@
package moderatorController
import (
"fmt"
"html"
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/reports"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/log"
"github.com/gin-gonic/gin"
)
// TorrentReportListPanel : Controller for listing torrent reports, can accept pages
func TorrentReportListPanel(c *gin.Context) {
page := c.Param("page")
pagenum := 1
offset := 100
var err error
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
torrentReports, nbReports, _ := reports.GetAll(offset, (pagenum-1)*offset)
reportJSON := models.TorrentReportsToJSON(torrentReports)
nav := templates.Navigation{nbReports, offset, pagenum, "mod/reports/p"}
templates.ModelList(c, "admin/torrent_report.jet.html", reportJSON, nav, templates.NewSearchForm(c))
}
// TorrentReportDeleteModPanel : Controller for deleting a torrent report
func TorrentReportDeleteModPanel(c *gin.Context) {
id := c.Query("id")
fmt.Println(id)
idNum, _ := strconv.ParseUint(id, 10, 64)
_, _, _ = reports.Delete(uint(idNum))
/* If we need to log report delete activity
if err == nil {
activity.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_report_deleted_by", strconv.Itoa(int(report.ID)), router.GetUser(c).Username)
}
*/
c.Redirect(http.StatusSeeOther, "/mod/reports?deleted")
}

Voir le fichier

@ -0,0 +1,38 @@
package moderatorController
import (
"github.com/NyaaPantsu/nyaa/controllers/middlewares"
"github.com/NyaaPantsu/nyaa/controllers/router"
)
func init() {
modRoutes := router.Get().Group("/mod", middlewares.ModMiddleware())
{
modRoutes.Any("/", IndexModPanel)
modRoutes.GET("/torrents", TorrentsListPanel)
modRoutes.GET("/torrents/p/:page", TorrentsListPanel)
modRoutes.POST("/torrents", TorrentsPostListPanel)
modRoutes.POST("/torrents/p/:page", TorrentsPostListPanel)
modRoutes.GET("/torrents/deleted", DeletedTorrentsModPanel)
modRoutes.GET("/torrents/deleted/p/:page", DeletedTorrentsModPanel)
modRoutes.POST("/torrents/deleted", DeletedTorrentsPostPanel)
modRoutes.POST("/torrents/deleted/p/:page", DeletedTorrentsPostPanel)
modRoutes.Any("/reports", TorrentReportListPanel)
modRoutes.Any("/reports/p/:page", TorrentReportListPanel)
modRoutes.Any("/users", UsersListPanel)
modRoutes.Any("/users/p/:page", UsersListPanel)
modRoutes.Any("/comments", CommentsListPanel)
modRoutes.Any("/comments/p/:page", CommentsListPanel)
modRoutes.Any("/comment", CommentsListPanel) // TODO
modRoutes.GET("/torrent", TorrentEditModPanel)
modRoutes.POST("/torrent", TorrentPostEditModPanel)
modRoutes.Any("/torrent/delete", TorrentDeleteModPanel)
modRoutes.Any("/torrent/block", TorrentBlockModPanel)
modRoutes.Any("/report/delete", TorrentReportDeleteModPanel)
modRoutes.Any("/comment/delete", CommentDeleteModPanel)
modRoutes.GET("/reassign", TorrentReassignModPanel)
modRoutes.POST("/reassign", TorrentPostReassignModPanel)
apiMod := modRoutes.Group("/api")
apiMod.Any("/torrents", APIMassMod)
}
}

Voir le fichier

@ -0,0 +1,193 @@
package moderatorController
import (
"html"
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/activities"
"github.com/NyaaPantsu/nyaa/models/reports"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/log"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/search"
"github.com/NyaaPantsu/nyaa/utils/search/structs"
"github.com/NyaaPantsu/nyaa/utils/upload"
"github.com/NyaaPantsu/nyaa/utils/validator/torrent"
"github.com/gin-gonic/gin"
)
// TorrentsListPanel : Controller for listing torrents, can accept common search arguments
func TorrentsListPanel(c *gin.Context) {
page := c.Param("page")
messages := msg.GetMessages(c)
deleted := c.Request.URL.Query()["deleted"]
unblocked := c.Request.URL.Query()["unblocked"]
blocked := c.Request.URL.Query()["blocked"]
if deleted != nil {
messages.AddInfoTf("infos", "torrent_deleted", "")
}
if blocked != nil {
messages.AddInfoT("infos", "torrent_blocked")
}
if unblocked != nil {
messages.AddInfoT("infos", "torrent_unblocked")
}
var err error
pagenum := 1
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
searchParam, torrents, count, err := search.ByQueryWithUser(c, pagenum)
if err != nil {
messages.Error(err)
}
category := ""
if len(searchParam.Category) > 0 {
category = searchParam.Category[0].String()
}
searchForm := templates.SearchForm{
TorrentParam: searchParam,
Category: category,
ShowItemsPerPage: true,
}
nav := templates.Navigation{count, int(searchParam.Max), pagenum, "mod/torrents/p"}
templates.ModelList(c, "admin/torrentlist.jet.html", torrents, nav, searchForm)
}
// TorrentEditModPanel : Controller for editing a torrent after GET request
func TorrentEditModPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
torrent, _ := torrents.FindUnscopeByID(uint(id))
torrentJSON := torrent.ToJSON()
uploadForm := upload.NewTorrentRequest()
uploadForm.Name = torrentJSON.Name
uploadForm.Category = torrentJSON.Category + "_" + torrentJSON.SubCategory
uploadForm.Status = torrentJSON.Status
uploadForm.Hidden = torrent.Hidden
uploadForm.WebsiteLink = string(torrentJSON.WebsiteLink)
uploadForm.Description = string(torrentJSON.Description)
uploadForm.Languages = torrent.Languages
templates.Form(c, "admin/paneltorrentedit.jet.html", uploadForm)
}
// TorrentPostEditModPanel : Controller for editing a torrent after POST request
func TorrentPostEditModPanel(c *gin.Context) {
var uploadForm torrentValidator.TorrentRequest
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
messages := msg.GetMessages(c)
torrent, _ := torrents.FindUnscopeByID(uint(id))
if torrent.ID > 0 {
errUp := upload.ExtractEditInfo(c, &uploadForm)
if errUp != nil {
messages.AddErrorT("errors", "fail_torrent_update")
}
if !messages.HasErrors() {
// update some (but not all!) values
torrent.Name = uploadForm.Name
torrent.Category = uploadForm.CategoryID
torrent.SubCategory = uploadForm.SubCategoryID
torrent.Status = uploadForm.Status
torrent.Hidden = uploadForm.Hidden
torrent.WebsiteLink = uploadForm.WebsiteLink
torrent.Description = uploadForm.Description
torrent.Languages = uploadForm.Languages
_, err := torrent.UpdateUnscope()
messages.AddInfoT("infos", "torrent_updated")
if err == nil { // We only log edit torrent for admins
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), "edit", "torrent_edited_by", strconv.Itoa(int(torrent.ID)), username, router.GetUser(c).Username)
}
}
}
templates.Form(c, "admin/paneltorrentedit.jet.html", uploadForm)
}
// TorrentDeleteModPanel : Controller for deleting a torrent
func TorrentDeleteModPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
definitely := c.Request.URL.Query()["definitely"]
var returnRoute = "/mod/torrents"
torrent, errFind := torrents.FindByID(uint(id))
if errFind == nil {
var err error
if definitely != nil {
_, _, err = torrent.DefinitelyDelete()
//delete reports of torrent
whereParams := structs.CreateWhereParams("torrent_id = ?", id)
reports, _, _ := reports.FindOrderBy(&whereParams, "", 0, 0)
for _, report := range reports {
report.Delete(true)
}
returnRoute = "/mod/torrents/deleted"
} else {
_, _, err = torrent.Delete(false)
//delete reports of torrent
whereParams := structs.CreateWhereParams("torrent_id = ?", id)
reports, _, _ := reports.FindOrderBy(&whereParams, "", 0, 0)
for _, report := range reports {
report.Delete(false)
}
}
if err == nil {
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, router.GetUser(c).Username)
}
}
c.Redirect(http.StatusSeeOther, returnRoute+"?deleted")
}
// TorrentBlockModPanel : Controller to lock torrents, redirecting to previous page
func TorrentBlockModPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
torrent, _, err := torrents.ToggleBlock(uint(id))
var returnRoute, action string
if torrent.IsDeleted() {
returnRoute = "/mod/torrents/deleted"
} else {
returnRoute = "/mod/torrents"
}
if torrent.IsBlocked() {
action = "blocked"
} else {
action = "unblocked"
}
if err == nil {
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), action, "torrent_"+action+"_by", strconv.Itoa(int(torrent.ID)), username, router.GetUser(c).Username)
}
c.Redirect(http.StatusSeeOther, returnRoute+"?"+action)
}
// TorrentsPostListPanel : Controller for listing torrents, after POST request when mass update
func TorrentsPostListPanel(c *gin.Context) {
torrentManyAction(c)
TorrentsListPanel(c)
}

32
controllers/moderator/users.go Fichier normal
Voir le fichier

@ -0,0 +1,32 @@
package moderatorController
import (
"html"
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/log"
"github.com/gin-gonic/gin"
)
// UsersListPanel : Controller for listing users, can accept pages
func UsersListPanel(c *gin.Context) {
page := c.Param("page")
pagenum := 1
offset := 100
var err error
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
users, nbUsers := users.FindUsersForAdmin(offset, (pagenum-1)*offset)
nav := templates.Navigation{nbUsers, offset, pagenum, "mod/users/p"}
templates.ModelList(c, "admin/userlist.jet.html", users, nav, templates.NewSearchForm(c))
}

Voir le fichier

@ -1,568 +0,0 @@
package controllers
import (
"fmt"
"html"
"net/http"
"strconv"
"strings"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/activities"
"github.com/NyaaPantsu/nyaa/models/comments"
"github.com/NyaaPantsu/nyaa/models/reports"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/categories"
"github.com/NyaaPantsu/nyaa/utils/log"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/search"
"github.com/NyaaPantsu/nyaa/utils/search/structs"
"github.com/NyaaPantsu/nyaa/utils/upload"
"github.com/NyaaPantsu/nyaa/utils/validator/torrent"
"github.com/gin-gonic/gin"
)
// IndexModPanel : Controller for showing index page of Mod Panel
func IndexModPanel(c *gin.Context) {
offset := 10
torrents, _, _ := torrents.FindAll(offset, 0)
users, _ := users.FindUsersForAdmin(offset, 0)
comments, _ := comments.FindAll(offset, 0, "", "")
torrentReports, _, _ := reports.GetAll(offset, 0)
templates.PanelAdmin(c, torrents, models.TorrentReportsToJSON(torrentReports), users, comments)
}
// TorrentsListPanel : Controller for listing torrents, can accept common search arguments
func TorrentsListPanel(c *gin.Context) {
page := c.Param("page")
messages := msg.GetMessages(c)
deleted := c.Request.URL.Query()["deleted"]
unblocked := c.Request.URL.Query()["unblocked"]
blocked := c.Request.URL.Query()["blocked"]
if deleted != nil {
messages.AddInfoTf("infos", "torrent_deleted", "")
}
if blocked != nil {
messages.AddInfoT("infos", "torrent_blocked")
}
if unblocked != nil {
messages.AddInfoT("infos", "torrent_unblocked")
}
var err error
pagenum := 1
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
searchParam, torrents, count, err := search.ByQueryWithUser(c, pagenum)
if err != nil {
messages.Error(err)
}
category := ""
if len(searchParam.Category) > 0 {
category = searchParam.Category[0].String()
}
searchForm := templates.SearchForm{
TorrentParam: searchParam,
Category: category,
ShowItemsPerPage: true,
}
nav := templates.Navigation{count, int(searchParam.Max), pagenum, "mod/torrents/p"}
templates.ModelList(c, "admin/torrentlist.jet.html", torrents, nav, searchForm)
}
// TorrentReportListPanel : Controller for listing torrent reports, can accept pages
func TorrentReportListPanel(c *gin.Context) {
page := c.Param("page")
pagenum := 1
offset := 100
var err error
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
torrentReports, nbReports, _ := reports.GetAll(offset, (pagenum-1)*offset)
reportJSON := models.TorrentReportsToJSON(torrentReports)
nav := templates.Navigation{nbReports, offset, pagenum, "mod/reports/p"}
templates.ModelList(c, "admin/torrent_report.jet.html", reportJSON, nav, templates.NewSearchForm(c))
}
// UsersListPanel : Controller for listing users, can accept pages
func UsersListPanel(c *gin.Context) {
page := c.Param("page")
pagenum := 1
offset := 100
var err error
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
users, nbUsers := users.FindUsersForAdmin(offset, (pagenum-1)*offset)
nav := templates.Navigation{nbUsers, offset, pagenum, "mod/users/p"}
templates.ModelList(c, "admin/userlist.jet.html", users, nav, templates.NewSearchForm(c))
}
// CommentsListPanel : Controller for listing comments, can accept pages and userID
func CommentsListPanel(c *gin.Context) {
page := c.Param("page")
pagenum := 1
offset := 100
userid := c.Query("userid")
var err error
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
var conditions string
var values []interface{}
if userid != "" {
conditions = "user_id = ?"
values = append(values, userid)
}
comments, nbComments := comments.FindAll(offset, (pagenum-1)*offset, conditions, values...)
nav := templates.Navigation{nbComments, offset, pagenum, "mod/comments/p"}
templates.ModelList(c, "admin/commentlist.jet.html", comments, nav, templates.NewSearchForm(c))
}
// TorrentEditModPanel : Controller for editing a torrent after GET request
func TorrentEditModPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
torrent, _ := torrents.FindUnscopeByID(uint(id))
torrentJSON := torrent.ToJSON()
uploadForm := upload.NewTorrentRequest()
uploadForm.Name = torrentJSON.Name
uploadForm.Category = torrentJSON.Category + "_" + torrentJSON.SubCategory
uploadForm.Status = torrentJSON.Status
uploadForm.Hidden = torrent.Hidden
uploadForm.WebsiteLink = string(torrentJSON.WebsiteLink)
uploadForm.Description = string(torrentJSON.Description)
uploadForm.Languages = torrent.Languages
templates.Form(c, "admin/paneltorrentedit.jet.html", uploadForm)
}
// TorrentPostEditModPanel : Controller for editing a torrent after POST request
func TorrentPostEditModPanel(c *gin.Context) {
var uploadForm torrentValidator.TorrentRequest
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
messages := msg.GetMessages(c)
torrent, _ := torrents.FindUnscopeByID(uint(id))
if torrent.ID > 0 {
errUp := upload.ExtractEditInfo(c, &uploadForm)
if errUp != nil {
messages.AddErrorT("errors", "fail_torrent_update")
}
if !messages.HasErrors() {
// update some (but not all!) values
torrent.Name = uploadForm.Name
torrent.Category = uploadForm.CategoryID
torrent.SubCategory = uploadForm.SubCategoryID
torrent.Status = uploadForm.Status
torrent.Hidden = uploadForm.Hidden
torrent.WebsiteLink = uploadForm.WebsiteLink
torrent.Description = uploadForm.Description
torrent.Languages = uploadForm.Languages
_, err := torrent.UpdateUnscope()
messages.AddInfoT("infos", "torrent_updated")
if err == nil { // We only log edit torrent for admins
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), "edit", "torrent_edited_by", strconv.Itoa(int(torrent.ID)), username, getUser(c).Username)
}
}
}
templates.Form(c, "admin/paneltorrentedit.jet.html", uploadForm)
}
// CommentDeleteModPanel : Controller for deleting a comment
func CommentDeleteModPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
comment, _, err := comments.Delete(uint(id))
if err == nil {
activities.Log(&models.User{}, comment.Identifier(), "delete", "comment_deleted_by", strconv.Itoa(int(comment.ID)), comment.User.Username, getUser(c).Username)
}
c.Redirect(http.StatusSeeOther, "/mod/comments?deleted")
}
// TorrentDeleteModPanel : Controller for deleting a torrent
func TorrentDeleteModPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
definitely := c.Request.URL.Query()["definitely"]
var returnRoute = "/mod/torrents"
torrent, errFind := torrents.FindByID(uint(id))
if errFind == nil {
var err error
if definitely != nil {
_, _, err = torrent.DefinitelyDelete()
//delete reports of torrent
whereParams := structs.CreateWhereParams("torrent_id = ?", id)
reports, _, _ := reports.FindOrderBy(&whereParams, "", 0, 0)
for _, report := range reports {
report.Delete(true)
}
returnRoute = "/mod/torrents/deleted"
} else {
_, _, err = torrent.Delete(false)
//delete reports of torrent
whereParams := structs.CreateWhereParams("torrent_id = ?", id)
reports, _, _ := reports.FindOrderBy(&whereParams, "", 0, 0)
for _, report := range reports {
report.Delete(false)
}
}
if err == nil {
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, getUser(c).Username)
}
}
c.Redirect(http.StatusSeeOther, returnRoute+"?deleted")
}
// TorrentReportDeleteModPanel : Controller for deleting a torrent report
func TorrentReportDeleteModPanel(c *gin.Context) {
id := c.Query("id")
fmt.Println(id)
idNum, _ := strconv.ParseUint(id, 10, 64)
_, _, _ = reports.Delete(uint(idNum))
/* If we need to log report delete activity
if err == nil {
activity.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_report_deleted_by", strconv.Itoa(int(report.ID)), getUser(c).Username)
}
*/
c.Redirect(http.StatusSeeOther, "/mod/reports?deleted")
}
// TorrentReassignModPanel : Controller for reassigning a torrent, after GET request
func TorrentReassignModPanel(c *gin.Context) {
templates.Form(c, "admin/reassign.jet.html", torrentValidator.ReassignForm{})
}
// ExecuteAction : Function for applying the changes from ReassignForm
func ExecuteReassign(f *torrentValidator.ReassignForm) (int, error) {
var toBeChanged []uint
var err error
if f.By == "olduser" {
toBeChanged, err = users.FindOldUploadsByUsername(f.Data)
if err != nil {
return 0, err
}
} else if f.By == "torrentid" {
toBeChanged = f.Torrents
}
num := 0
for _, torrentID := range toBeChanged {
torrent, err2 := torrents.FindRawByID(torrentID)
if err2 == nil {
torrent.UploaderID = f.AssignTo
torrent.Update(true)
num++
}
}
return num, nil
}
// TorrentPostReassignModPanel : Controller for reassigning a torrent, after POST request
func TorrentPostReassignModPanel(c *gin.Context) {
var rForm torrentValidator.ReassignForm
messages := msg.GetMessages(c)
if rForm.ExtractInfo(c) {
count, err2 := ExecuteReassign(&rForm)
if err2 != nil {
messages.AddErrorT("errors", "something_went_wrong")
} else {
messages.AddInfoTf("infos", "nb_torrents_updated", count)
}
}
templates.Form(c, "admin/reassign.jet.html", rForm)
}
// TorrentsPostListPanel : Controller for listing torrents, after POST request when mass update
func TorrentsPostListPanel(c *gin.Context) {
torrentManyAction(c)
TorrentsListPanel(c)
}
// APIMassMod : This function is used on the frontend for the mass
/* Query is: action=status|delete|owner|category|multiple
* Needed: torrent_id[] Ids of torrents in checkboxes of name torrent_id
*
* Needed on context:
* status=0|1|2|3|4 according to config/find.go (can be omitted if action=delete|owner|category|multiple)
* owner is the User ID of the new owner of the torrents (can be omitted if action=delete|status|category|multiple)
* category is the category string (eg. 1_3) of the new category of the torrents (can be omitted if action=delete|status|owner|multiple)
*
* withreport is the bool to enable torrent reports deletion (can be omitted)
*
* In case of action=multiple, torrents can be at the same time changed status, owner and category
*/
func APIMassMod(c *gin.Context) {
torrentManyAction(c)
messages := msg.GetMessages(c) // new utils for errors and infos
c.Header("Content-Type", "application/json")
var mapOk map[string]interface{}
if !messages.HasErrors() {
mapOk = map[string]interface{}{"ok": true, "infos": messages.GetAllInfos()["infos"]}
} else { // We need to show error messages
mapOk = map[string]interface{}{"ok": false, "errors": messages.GetAllErrors()["errors"]}
}
c.JSON(http.StatusOK, mapOk)
}
// DeletedTorrentsModPanel : Controller for viewing deleted torrents, accept common search arguments
func DeletedTorrentsModPanel(c *gin.Context) {
page := c.Param("page")
messages := msg.GetMessages(c) // new utils for errors and infos
deleted := c.Request.URL.Query()["deleted"]
unblocked := c.Request.URL.Query()["unblocked"]
blocked := c.Request.URL.Query()["blocked"]
if deleted != nil {
messages.AddInfoT("infos", "torrent_deleted_definitely")
}
if blocked != nil {
messages.AddInfoT("infos", "torrent_blocked")
}
if unblocked != nil {
messages.AddInfoT("infos", "torrent_unblocked")
}
var err error
pagenum := 1
if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if !log.CheckError(err) {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
}
searchParam, torrents, count, err := search.ByQueryDeleted(c, pagenum)
if err != nil {
messages.Error(err)
}
category := ""
if len(searchParam.Category) > 0 {
category = searchParam.Category[0].String()
}
searchForm := templates.SearchForm{
TorrentParam: searchParam,
Category: category,
ShowItemsPerPage: true,
}
nav := templates.Navigation{count, int(searchParam.Max), pagenum, "mod/torrents/deleted/p"}
search := searchForm
templates.ModelList(c, "admin/torrentlist.jet.html", torrents, nav, search)
}
// DeletedTorrentsPostPanel : Controller for viewing deleted torrents after a mass update, accept common search arguments
func DeletedTorrentsPostPanel(c *gin.Context) {
torrentManyAction(c)
DeletedTorrentsModPanel(c)
}
// TorrentBlockModPanel : Controller to lock torrents, redirecting to previous page
func TorrentBlockModPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
torrent, _, err := torrents.ToggleBlock(uint(id))
var returnRoute, action string
if torrent.IsDeleted() {
returnRoute = "/mod/torrents/deleted"
} else {
returnRoute = "/mod/torrents"
}
if torrent.IsBlocked() {
action = "blocked"
} else {
action = "unblocked"
}
if err == nil {
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), action, "torrent_"+action+"_by", strconv.Itoa(int(torrent.ID)), username, getUser(c).Username)
}
c.Redirect(http.StatusSeeOther, returnRoute+"?"+action)
}
/*
* Controller to modify multiple torrents and can be used by the owner of the torrent or admin
*/
func torrentManyAction(c *gin.Context) {
currentUser := getUser(c)
torrentsSelected := c.PostFormArray("torrent_id") // should be []string
action := c.PostForm("action")
status, _ := strconv.Atoi(c.PostForm("status"))
owner, _ := strconv.Atoi(c.PostForm("owner"))
category := c.PostForm("category")
withReport, _ := strconv.ParseBool(c.DefaultPostForm("withreport", "false"))
messages := msg.GetMessages(c) // new utils for errors and infos
catID, subCatID := -1, -1
var err error
if action == "" {
messages.AddErrorT("errors", "no_action_selected")
}
if action == "status" && c.PostForm("status") == "" { // We need to check the form value, not the int one because hidden is 0
messages.AddErrorT("errors", "no_move_location_selected")
}
if action == "owner" && c.PostForm("owner") == "" { // We need to check the form value, not the int one because renchon is 0
messages.AddErrorT("errors", "no_owner_selected")
}
if action == "category" && category == "" {
messages.AddErrorT("errors", "no_category_selected")
}
if len(torrentsSelected) == 0 {
messages.AddErrorT("errors", "select_one_element")
}
if !config.Get().Torrents.Status[status] { // Check if the status exist
messages.AddErrorTf("errors", "no_status_exist", status)
status = -1
}
if !currentUser.HasAdmin() {
if c.PostForm("status") != "" { // Condition to check if a user try to change torrent status without having the right permission
if (status == models.TorrentStatusTrusted && !currentUser.IsTrusted()) || status == models.TorrentStatusAPlus || status == 0 {
status = models.TorrentStatusNormal
}
}
if c.PostForm("owner") != "" { // Only admins can change owner of torrents
owner = -1
}
withReport = false // Users should not be able to remove reports
}
if c.PostForm("owner") != "" && currentUser.HasAdmin() { // We check that the user given exist and if not we return an error
_, _, errorUser := users.FindForAdmin(uint(owner))
if errorUser != nil {
messages.AddErrorTf("errors", "no_user_found_id", owner)
owner = -1
}
}
if category != "" {
catsSplit := strings.Split(category, "_")
// need this to prevent out of index panics
if len(catsSplit) == 2 {
catID, err = strconv.Atoi(catsSplit[0])
if err != nil {
messages.AddErrorT("errors", "invalid_torrent_category")
}
subCatID, err = strconv.Atoi(catsSplit[1])
if err != nil {
messages.AddErrorT("errors", "invalid_torrent_category")
}
if !categories.Exists(category) {
messages.AddErrorT("errors", "invalid_torrent_category")
}
}
}
if !messages.HasErrors() {
for _, torrentID := range torrentsSelected {
id, _ := strconv.Atoi(torrentID)
torrent, _ := torrents.FindByID(uint(id))
if torrent.ID > 0 && currentUser.CurrentOrAdmin(torrent.UploaderID) {
if action == "status" || action == "multiple" || action == "category" || action == "owner" {
/* If we don't delete, we make changes according to the form posted and we save at the end */
if c.PostForm("status") != "" && status != -1 {
torrent.Status = status
messages.AddInfoTf("infos", "torrent_moved", torrent.Name)
}
if c.PostForm("owner") != "" && owner != -1 {
torrent.UploaderID = uint(owner)
messages.AddInfoTf("infos", "torrent_owner_changed", torrent.Name)
}
if category != "" && catID != -1 && subCatID != -1 {
torrent.Category = catID
torrent.SubCategory = subCatID
messages.AddInfoTf("infos", "torrent_category_changed", torrent.Name)
}
/* Changes are done, we save */
_, err := torrent.UpdateUnscope()
if err == nil {
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), "edited", "torrent_edited_by", strconv.Itoa(int(torrent.ID)), username, getUser(c).Username)
}
} else if action == "delete" {
if status == models.TorrentStatusBlocked { // Then we should lock torrents before deleting them
torrent.Status = status
messages.AddInfoTf("infos", "torrent_moved", torrent.Name)
torrent.UpdateUnscope()
}
_, _, err = torrent.Delete(false)
if err != nil {
messages.ImportFromError("errors", err)
} else {
messages.AddInfoTf("infos", "torrent_deleted", torrent.Name)
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
activities.Log(&models.User{}, torrent.Identifier(), "deleted", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, getUser(c).Username)
}
} else {
messages.AddErrorTf("errors", "no_action_exist", action)
}
if withReport {
whereParams := structs.CreateWhereParams("torrent_id = ?", torrentID)
reports, _, _ := reports.FindOrderBy(&whereParams, "", 0, 0)
for _, report := range reports {
report.Delete(false)
}
messages.AddInfoTf("infos", "torrent_reports_deleted", torrent.Name)
}
} else {
messages.AddErrorTf("errors", "torrent_not_exist", torrentID)
}
}
}
}

Voir le fichier

@ -44,7 +44,7 @@
//
// https://blog.golang.org/2011/06/profiling-go-programs.html
//
package controllers
package pprofController
import (
"bufio"

18
controllers/pprof/router.go Fichier normal
Voir le fichier

@ -0,0 +1,18 @@
package pprofController
import "github.com/NyaaPantsu/nyaa/controllers/router"
import "github.com/NyaaPantsu/nyaa/controllers/middlewares"
func init() {
// Adding pprof support
pprofRoutes := router.Get().Group("/debug/pprof", middlewares.ModMiddleware())
{
pprofRoutes.GET("/", PprofIndex)
pprofRoutes.GET("/block", PprofIndex)
pprofRoutes.GET("/heap", PprofIndex)
pprofRoutes.GET("/profile", PprofProfile)
pprofRoutes.POST("/symbol", PprofSymbol)
pprofRoutes.GET("/symbol", PprofSymbol)
pprofRoutes.GET("/trace", PprofTrace)
}
}

71
controllers/report/report.go Fichier normal
Voir le fichier

@ -0,0 +1,71 @@
package reportController
import (
"fmt"
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models/reports"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/captcha"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/gin-gonic/gin"
)
// ReportTorrentHandler : Controller for sending a torrent report
func ReportTorrentHandler(c *gin.Context) {
fmt.Println("report")
id, _ := strconv.ParseInt(c.Param("id"), 10, 32)
messages := msg.GetMessages(c)
captchaError := "?reported"
currentUser := router.GetUser(c)
if currentUser.NeedsCaptcha() {
userCaptcha := captcha.Extract(c)
if !captcha.Authenticate(userCaptcha) {
captchaError = "?badcaptcha"
messages.AddErrorT("errors", "bad_captcha")
}
}
torrent, err := torrents.FindByID(uint(id))
if err != nil {
messages.Error(err)
}
if !messages.HasErrors() {
_, err := reports.Create(c.PostForm("report_type"), torrent, currentUser)
messages.AddInfoTf("infos", "report_msg", id)
if err != nil {
messages.ImportFromError("errors", err)
}
c.Redirect(http.StatusSeeOther, "/view/"+strconv.Itoa(int(torrent.ID))+captchaError)
} else {
ReportViewTorrentHandler(c)
}
}
// ReportViewTorrentHandler : Controller for sending a torrent report
func ReportViewTorrentHandler(c *gin.Context) {
type Report struct {
ID uint
CaptchaID string
}
id, _ := strconv.ParseInt(c.Param("id"), 10, 32)
messages := msg.GetMessages(c)
currentUser := router.GetUser(c)
if currentUser.ID > 0 {
torrent, err := torrents.FindByID(uint(id))
if err != nil {
messages.Error(err)
}
captchaID := ""
if currentUser.NeedsCaptcha() {
captchaID = captcha.GetID()
}
templates.Form(c, "site/torrents/report.jet.html", Report{torrent.ID, captchaID})
} else {
c.Status(404)
}
}

12
controllers/report/router.go Fichier normal
Voir le fichier

@ -0,0 +1,12 @@
package reportController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
reportRoutes := router.Get().Group("/report")
{
//reporting a torrent
reportRoutes.GET("/:id", ReportViewTorrentHandler)
reportRoutes.POST("/:id", ReportTorrentHandler)
}
}

Voir le fichier

@ -3,159 +3,30 @@ package controllers
import (
"net/http"
"github.com/NyaaPantsu/nyaa/utils/captcha"
"github.com/gin-gonic/gin"
_ "github.com/NyaaPantsu/nyaa/controllers/activities" // activities controller
_ "github.com/NyaaPantsu/nyaa/controllers/api" // api controller
_ "github.com/NyaaPantsu/nyaa/controllers/captcha" // captcha controller
_ "github.com/NyaaPantsu/nyaa/controllers/databasedumps" // databasedumps controller
_ "github.com/NyaaPantsu/nyaa/controllers/faq" // faq controller
_ "github.com/NyaaPantsu/nyaa/controllers/feed" // feed controller
_ "github.com/NyaaPantsu/nyaa/controllers/middlewares" // middlewares
_ "github.com/NyaaPantsu/nyaa/controllers/moderator" // moderator controller
_ "github.com/NyaaPantsu/nyaa/controllers/pprof" // pprof controller
_ "github.com/NyaaPantsu/nyaa/controllers/report" // report controller
"github.com/NyaaPantsu/nyaa/controllers/router"
_ "github.com/NyaaPantsu/nyaa/controllers/search" // search controller
_ "github.com/NyaaPantsu/nyaa/controllers/settings" // settings controller
_ "github.com/NyaaPantsu/nyaa/controllers/torrent" // torrent controller
_ "github.com/NyaaPantsu/nyaa/controllers/upload" // upload controller
_ "github.com/NyaaPantsu/nyaa/controllers/user" // user controller
"github.com/justinas/nosurf"
)
// Router variable for exporting the route configuration
var Router *gin.Engine
// CSRFRouter : CSRF protection for Router variable for exporting the route configuration
var CSRFRouter *nosurf.CSRFHandler
func init() {
Router = gin.New()
//Router.Use(gzip.Gzip(gzip.DefaultCompression)) // FIXME I can't make it work :/
Router.Use(gin.Logger())
Router.Use(gin.Recovery())
Router.Use(errorMiddleware())
// Static file handlers
// TODO Use config from cli
// TODO Make sure the directory exists
Router.StaticFS("/css/", http.Dir("./public/css/"))
Router.StaticFS("/js/", http.Dir("./public/js/"))
Router.StaticFS("/img/", http.Dir("./public/img/"))
Router.StaticFS("/apidoc/", http.Dir("./apidoc/"))
Router.StaticFS("/dbdumps/", http.Dir(DatabaseDumpPath))
Router.StaticFS("/gpg/", http.Dir(GPGPublicKeyPath))
// We don't need CSRF here
Router.Any("/", SearchHandler)
Router.Any("/p/:page", SearchHandler)
Router.Any("/search", SearchHandler)
Router.Any("/search/:page", SearchHandler)
Router.Any("/verify/email/:token", UserVerifyEmailHandler)
Router.Any("/faq", FaqHandler)
Router.Any("/activities", ActivityListHandler)
Router.Any("/activities/p/:page", ActivityListHandler)
Router.Any("/feed", RSSHandler)
Router.Any("/feed/p/:page", RSSHandler)
Router.Any("/feed/magnet", RSSMagnetHandler)
Router.Any("/feed/magnet/p/:page", RSSMagnetHandler)
Router.Any("/feed/torznab", RSSTorznabHandler)
Router.Any("/feed/torznab/api", RSSTorznabHandler)
Router.Any("/feed/torznab/p/:page", RSSTorznabHandler)
Router.Any("/feed/eztv", RSSEztvHandler)
Router.Any("/feed/eztv/p/:page", RSSEztvHandler)
// !!! This line need to have the same download location as the one define in config.TorrentStorageLink !!!
Router.Any("/download/:hash", DownloadTorrent)
Router.Any("/upload", UploadHandler)
Router.POST("/login", UserLoginPostHandler)
Router.GET("/register", UserRegisterFormHandler)
Router.GET("/login", UserLoginFormHandler)
Router.POST("/register", UserRegisterPostHandler)
Router.POST("/logout", UserLogoutHandler)
Router.GET("/notifications", UserNotificationsHandler)
reportRoutes := Router.Group("/report")
{
//reporting a torrent
reportRoutes.GET("/:id", ReportViewTorrentHandler)
reportRoutes.POST("/:id", ReportTorrentHandler)
}
torrentViewRoutes := Router.Group("/view")
{
torrentViewRoutes.GET("/:id", ViewHandler)
torrentViewRoutes.HEAD("/:id", ViewHeadHandler)
torrentViewRoutes.POST("/:id", PostCommentHandler)
}
torrentRoutes := Router.Group("/torrent")
{
torrentRoutes.GET("/", TorrentEditUserPanel)
torrentRoutes.POST("/", TorrentPostEditUserPanel)
torrentRoutes.GET("/delete", TorrentDeleteUserPanel)
}
userRoutes := Router.Group("/user")
{
userRoutes.GET("/:id/:username", UserProfileHandler)
userRoutes.GET("/:id/:username/follow", UserFollowHandler)
userRoutes.GET("/:id/:username/edit", UserDetailsHandler)
userRoutes.POST("/:id/:username/edit", UserProfileFormHandler)
userRoutes.GET("/:id/:username/apireset", UserAPIKeyResetHandler)
userRoutes.GET("/:id/:username/feed/*page", RSSHandler)
}
// We don't need CSRF here
api := Router.Group("/api")
{
api.GET("", APIHandler)
api.GET("/p/:page", APIHandler)
api.GET("/view/:id", APIViewHandler)
api.HEAD("/view/:id", APIViewHeadHandler)
api.POST("/upload", APIUploadHandler)
api.POST("/login", APILoginHandler)
api.GET("/token/check", APICheckTokenHandler)
api.GET("/token/refresh", APIRefreshTokenHandler)
api.Any("/search", APISearchHandler)
api.Any("/search/p/:page", APISearchHandler)
api.PUT("/update", APIUpdateHandler)
}
// INFO Everything under /mod should be wrapped by wrapModHandler. This make
// sure the page is only accessible by moderators
// We don't need CSRF here
modRoutes := Router.Group("/mod", modMiddleware())
{
modRoutes.Any("/", IndexModPanel)
modRoutes.GET("/torrents", TorrentsListPanel)
modRoutes.GET("/torrents/p/:page", TorrentsListPanel)
modRoutes.POST("/torrents", TorrentsPostListPanel)
modRoutes.POST("/torrents/p/:page", TorrentsPostListPanel)
modRoutes.GET("/torrents/deleted", DeletedTorrentsModPanel)
modRoutes.GET("/torrents/deleted/p/:page", DeletedTorrentsModPanel)
modRoutes.POST("/torrents/deleted", DeletedTorrentsPostPanel)
modRoutes.POST("/torrents/deleted/p/:page", DeletedTorrentsPostPanel)
modRoutes.Any("/reports", TorrentReportListPanel)
modRoutes.Any("/reports/p/:page", TorrentReportListPanel)
modRoutes.Any("/users", UsersListPanel)
modRoutes.Any("/users/p/:page", UsersListPanel)
modRoutes.Any("/comments", CommentsListPanel)
modRoutes.Any("/comments/p/:page", CommentsListPanel)
modRoutes.Any("/comment", CommentsListPanel) // TODO
modRoutes.GET("/torrent", TorrentEditModPanel)
modRoutes.POST("/torrent", TorrentPostEditModPanel)
modRoutes.Any("/torrent/delete", TorrentDeleteModPanel)
modRoutes.Any("/torrent/block", TorrentBlockModPanel)
modRoutes.Any("/report/delete", TorrentReportDeleteModPanel)
modRoutes.Any("/comment/delete", CommentDeleteModPanel)
modRoutes.GET("/reassign", TorrentReassignModPanel)
modRoutes.POST("/reassign", TorrentPostReassignModPanel)
apiMod := modRoutes.Group("/api")
apiMod.Any("/torrents", APIMassMod)
}
Router.Any("/captcha/*hash", captcha.ServeFiles)
Router.Any("/dumps", DatabaseDumpHandler)
Router.GET("/settings", SeePublicSettingsHandler)
Router.POST("/settings", ChangePublicSettingsHandler)
// Adding pprof support
pprofRoutes := Router.Group("/debug/pprof", modMiddleware())
{
pprofRoutes.GET("/", PprofIndex)
pprofRoutes.GET("/block", PprofIndex)
pprofRoutes.GET("/heap", PprofIndex)
pprofRoutes.GET("/profile", PprofProfile)
pprofRoutes.POST("/symbol", PprofSymbol)
pprofRoutes.GET("/symbol", PprofSymbol)
pprofRoutes.GET("/trace", PprofTrace)
}
CSRFRouter = nosurf.New(Router)
CSRFRouter = nosurf.New(router.Get())
CSRFRouter.ExemptRegexp("/api(?:/.+)*")
CSRFRouter.ExemptRegexp("/mod(?:/.+)*")
CSRFRouter.ExemptPath("/upload")

Voir le fichier

@ -1,4 +1,4 @@
package controllers
package router
import (
"github.com/NyaaPantsu/nyaa/models"
@ -6,7 +6,8 @@ import (
"github.com/gin-gonic/gin"
)
func getUser(c *gin.Context) *models.User {
// GetUser return the current user from the context
func GetUser(c *gin.Context) *models.User {
user, _, _ := cookies.CurrentUser(c)
if user == nil {
return &models.User{}

20
controllers/router/router.go Fichier normal
Voir le fichier

@ -0,0 +1,20 @@
package router
import (
"sync"
"github.com/gin-gonic/gin"
)
var router *gin.Engine
var once sync.Once
// Get return a router signleton
func Get() *gin.Engine {
once.Do(func() {
router = gin.New()
router.Use(gin.Logger())
router.Use(gin.Recovery())
})
return router
}

Voir le fichier

@ -1,415 +0,0 @@
package controllers
import (
"errors"
"html"
"net/http"
"strconv"
"strings"
"time"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/NyaaPantsu/nyaa/utils/categories"
"github.com/NyaaPantsu/nyaa/utils/feeds"
"github.com/NyaaPantsu/nyaa/utils/publicSettings"
"github.com/NyaaPantsu/nyaa/utils/search"
"github.com/gin-gonic/gin"
"github.com/gorilla/feeds"
)
// RSSHandler : Controller for displaying rss feed, accepting common search arguments
func RSSHandler(c *gin.Context) {
// We only get the basic variable for rss based on search param
torrents, createdAsTime, title, err := getTorrentList(c)
if err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
}
feed := &nyaafeeds.RssFeed{
Title: title,
Link: config.WebAddress() + "/",
PubDate: createdAsTime.String(),
}
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
for i, torrent := range torrents {
torrentJSON := torrent.ToJSON()
feed.Items[i] = &nyaafeeds.RssItem{
Title: torrentJSON.Name,
Link: config.WebAddress() + "/download/" + torrentJSON.Hash,
Description: string(torrentJSON.Description),
PubDate: torrent.Date.Format(time.RFC822),
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
Enclosure: &nyaafeeds.RssEnclosure{
URL: config.WebAddress() + "/download/" + strings.TrimSpace(torrentJSON.Hash),
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
Type: "application/x-bittorrent",
},
}
}
// allow cross domain AJAX requests
c.Header("Access-Control-Allow-Origin", "*")
rss, rssErr := feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
_, writeErr := c.Writer.Write([]byte(rss))
if writeErr != nil {
c.AbortWithError(http.StatusInternalServerError, writeErr)
}
}
// RSSMagnetHandler : Controller for displaying rss feeds with magnet URL, accepting common search arguments
func RSSMagnetHandler(c *gin.Context) {
// We only get the basic variable for rss based on search param
torrents, createdAsTime, title, err := getTorrentList(c)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
feed := &nyaafeeds.RssFeed{
Title: title,
Link: config.WebAddress() + "/",
PubDate: createdAsTime.String(),
}
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
for i, torrent := range torrents {
torrentJSON := torrent.ToJSON()
feed.Items[i] = &nyaafeeds.RssItem{
Title: torrentJSON.Name,
Link: &nyaafeeds.RssMagnetLink{Text: string(torrentJSON.Magnet)},
Description: string(torrentJSON.Description),
PubDate: torrent.Date.Format(time.RFC822),
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
Enclosure: &nyaafeeds.RssEnclosure{
URL: config.WebAddress() + "/download/" + strings.TrimSpace(torrentJSON.Hash),
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
Type: "application/x-bittorrent",
},
}
}
// allow cross domain AJAX requests
c.Header("Access-Control-Allow-Origin", "*")
rss, rssErr := feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
_, writeErr := c.Writer.Write([]byte(rss))
if writeErr != nil {
c.AbortWithError(http.StatusInternalServerError, writeErr)
}
}
// RSSEztvHandler : Controller for displaying rss feed, accepting common search arguments
func RSSEztvHandler(c *gin.Context) {
// We only get the basic variable for rss based on search param
torrents, createdAsTime, title, err := getTorrentList(c)
if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
return
}
feed := &nyaafeeds.RssFeed{
Title: title,
Link: config.WebAddress() + "/",
PubDate: createdAsTime.String(),
}
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
for i, torrent := range torrents {
torrentJSON := torrent.ToJSON()
feed.Items[i] = &nyaafeeds.RssItem{
Title: torrentJSON.Name,
Link: config.WebAddress() + "/download/" + torrentJSON.Hash,
Category: &nyaafeeds.RssCategory{
Domain: config.WebAddress() + "/search?c=" + torrentJSON.Category + "_" + torrentJSON.SubCategory,
},
Description: string(torrentJSON.Description),
Comments: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
PubDate: torrent.Date.Format(time.RFC822),
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
Enclosure: &nyaafeeds.RssEnclosure{
URL: config.WebAddress() + "/download/" + strings.TrimSpace(torrentJSON.Hash),
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
Type: "application/x-bittorrent",
},
Torrent: &nyaafeeds.RssTorrent{
Xmlns: "http://xmlns.ezrss.it/0.1/",
FileName: torrentJSON.Name + ".torrent",
ContentLength: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
InfoHash: torrentJSON.Hash,
MagnetURI: string(torrentJSON.Magnet),
},
}
}
// allow cross domain AJAX requests
c.Header("Access-Control-Allow-Origin", "*")
rss, rssErr := feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
_, writeErr := c.Writer.Write([]byte(rss))
if writeErr != nil {
c.AbortWithError(http.StatusInternalServerError, writeErr)
}
}
// RSSTorznabHandler : Controller for displaying rss feed, accepting common search arguments
func RSSTorznabHandler(c *gin.Context) {
t := c.Query("t")
rss := ""
title := "Nyaa Pantsu"
if config.IsSukebei() {
title = "Sukebei Pantsu"
}
if t == "caps" {
T := publicSettings.GetTfuncFromRequest(c)
cats := categories.GetSelect(true, true)
var categories []*nyaafeeds.RssCategoryTorznab
categories = append(categories, &nyaafeeds.RssCategoryTorznab{
ID: "5070",
Name: "Anime",
Description: "Anime",
})
last := 0
for _, v := range cats {
if len(v.ID) <= 2 {
categories = append(categories, &nyaafeeds.RssCategoryTorznab{
ID: nyaafeeds.ConvertFromCat(v.ID),
Name: string(T(v.Name)),
})
last++
} else {
categories[last].Subcat = append(categories[last].Subcat, &nyaafeeds.RssSubCat{
ID: nyaafeeds.ConvertFromCat(v.ID),
Name: string(T(v.Name)),
})
}
}
feed := &nyaafeeds.RssCaps{
Server: &nyaafeeds.RssServer{
Version: "1.0",
Title: title,
Strapline: "...",
Email: config.Get().Email.From,
URL: config.WebAddress(),
Image: config.WebAddress() + "/img/logo.png",
},
Limits: &nyaafeeds.RssLimits{
Max: "300",
Default: "50",
},
Registration: &nyaafeeds.RssRegistration{
Available: "yes",
Open: "yes",
},
Searching: &nyaafeeds.RssSearching{
Search: &nyaafeeds.RssSearch{
Available: "yes",
SupportedParams: "q",
},
TvSearch: &nyaafeeds.RssSearch{
Available: "no",
},
MovieSearch: &nyaafeeds.RssSearch{
Available: "no",
},
},
Categories: &nyaafeeds.RssCategories{
Category: categories,
},
}
var rssErr error
rss, rssErr = feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
} else {
// We only get the basic variable for rss based on search param
torrents, createdAsTime, title, err := getTorrentList(c)
if err != nil {
c.AbortWithError(http.StatusBadRequest, err)
return
}
feed := &nyaafeeds.RssFeed{
Title: title,
Xmlns: "http://torznab.com/schemas/2015/feed",
Link: config.WebAddress() + "/",
PubDate: createdAsTime.String(),
}
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
for i, torrent := range torrents {
torrentJSON := torrent.ToJSON()
filesNumber := ""
if len(torrentJSON.FileList) > 0 {
filesNumber = strconv.Itoa(len(torrentJSON.FileList))
}
seeders := ""
if torrentJSON.Seeders > 0 {
seeders = strconv.Itoa(int(torrentJSON.Seeders))
}
leechers := ""
if torrentJSON.Leechers > 0 {
leechers = strconv.Itoa(int(torrentJSON.Leechers))
}
feed.Items[i] = &nyaafeeds.RssItem{
Title: torrentJSON.Name,
Link: config.WebAddress() + "/download/" + torrentJSON.Hash,
Category: &nyaafeeds.RssCategory{
Domain: config.WebAddress() + "/search?c=" + torrentJSON.Category + "_" + torrentJSON.SubCategory,
},
Description: string(torrentJSON.Description),
Comments: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
PubDate: torrent.Date.Format(time.RFC822),
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
Enclosure: &nyaafeeds.RssEnclosure{
URL: config.WebAddress() + "/download/" + strings.TrimSpace(torrentJSON.Hash),
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
Type: "application/x-bittorrent",
},
}
torznab := []*nyaafeeds.RssTorznab{}
if torrentJSON.Filesize > 0 {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "size",
Value: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
})
}
if filesNumber != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "files",
Value: filesNumber,
})
}
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "grabs",
Value: strconv.Itoa(int(torrentJSON.Completed)),
})
if seeders != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "seeders",
Value: seeders,
})
}
if leechers != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "leechers",
Value: leechers,
})
}
if torrentJSON.Hash != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "infohash",
Value: torrentJSON.Hash,
})
}
if torrentJSON.Magnet != "" {
torznab = append(torznab, &nyaafeeds.RssTorznab{
Name: "magneturl",
Value: string(torrentJSON.Magnet),
})
}
if len(torznab) > 0 {
feed.Items[i].Torznab = torznab
}
}
var rssErr error
rss, rssErr = feeds.ToXML(feed)
if rssErr != nil {
c.AbortWithError(http.StatusInternalServerError, rssErr)
}
}
// allow cross domain AJAX requests
c.Header("Access-Control-Allow-Origin", "*")
_, writeErr := c.Writer.Write([]byte(rss))
if writeErr != nil {
c.AbortWithError(http.StatusInternalServerError, writeErr)
}
}
func getTorrentList(c *gin.Context) (torrents []models.Torrent, createdAsTime time.Time, title string, err error) {
page := c.Param("page")
userID := c.Param("id")
cat := c.Query("cat")
offset := 0
if c.Query("offset") != "" {
offset, err = strconv.Atoi(html.EscapeString(c.Query("offset")))
if err != nil {
return
}
}
createdAsTime = time.Now()
if len(torrents) > 0 {
createdAsTime = torrents[0].Date
}
title = "Nyaa Pantsu"
if config.IsSukebei() {
title = "Sukebei Pantsu"
}
pagenum := 1
if page == "" && offset > 0 { // first page for offset is 0
pagenum = offset + 1
} else if page != "" {
pagenum, err = strconv.Atoi(html.EscapeString(page))
if err != nil {
return
}
}
if pagenum <= 0 {
err = errors.New("Page number is invalid")
return
}
if userID != "" {
userIDnum := 0
userIDnum, err = strconv.Atoi(html.EscapeString(userID))
// Should we have a feed for anonymous uploads?
if err != nil || userIDnum == 0 {
return
}
_, _, err = users.FindForAdmin(uint(userIDnum))
if err != nil {
return
}
// Set the user ID on the request, so that SearchByQuery finds it.
query := c.Request.URL.Query()
query.Set("userID", userID)
c.Request.URL.RawQuery = query.Encode()
}
if cat != "" {
query := c.Request.URL.Query()
catConv := nyaafeeds.ConvertToCat(cat)
if catConv == "" {
return
}
query.Set("c", catConv)
c.Request.URL.RawQuery = query.Encode()
}
_, torrents, err = search.ByQueryNoCount(c, pagenum)
return
}

10
controllers/search/router.go Fichier normal
Voir le fichier

@ -0,0 +1,10 @@
package searchController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
router.Get().Any("/", SearchHandler)
router.Get().Any("/p/:page", SearchHandler)
router.Get().Any("/search", SearchHandler)
router.Get().Any("/search/:page", SearchHandler)
}

Voir le fichier

@ -1,4 +1,4 @@
package controllers
package searchController
import (
"html"

Voir le fichier

@ -0,0 +1,8 @@
package settingsController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
router.Get().GET("/settings", SeePublicSettingsHandler)
router.Get().POST("/settings", ChangePublicSettingsHandler)
}

Voir le fichier

@ -1,10 +1,11 @@
package controllers
package settingsController
import (
"net/http"
"net/url"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/templates"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/publicSettings"
@ -52,7 +53,7 @@ func ChangePublicSettingsHandler(c *gin.Context) {
}
// If logged in, update user settings.
user := getUser(c)
user := router.GetUser(c)
if user.ID > 0 {
user.Language = lang
user.Theme = theme

20
controllers/static/static.go Fichier normal
Voir le fichier

@ -0,0 +1,20 @@
package staticController
import (
"net/http"
"github.com/NyaaPantsu/nyaa/controllers/databasedumps"
"github.com/NyaaPantsu/nyaa/controllers/router"
)
func init() {
// Static file handlers
// TODO Use config from cli
// TODO Make sure the directory exists
router.Get().StaticFS("/css/", http.Dir("./public/css/"))
router.Get().StaticFS("/js/", http.Dir("./public/js/"))
router.Get().StaticFS("/img/", http.Dir("./public/img/"))
router.Get().StaticFS("/apidoc/", http.Dir("./apidoc/"))
router.Get().StaticFS("/dbdumps/", http.Dir(databasedumpsController.DatabaseDumpPath))
router.Get().StaticFS("/gpg/", http.Dir(databasedumpsController.GPGPublicKeyPath))
}

54
controllers/torrent/comment.go Fichier normal
Voir le fichier

@ -0,0 +1,54 @@
package torrentController
import (
"net/http"
"strconv"
"strings"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models/comments"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/utils/captcha"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/sanitize"
"github.com/gin-gonic/gin"
)
// PostCommentHandler : Controller for posting a comment
func PostCommentHandler(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 32)
torrent, err := torrents.FindByID(uint(id))
if err != nil {
c.Status(http.StatusNotFound)
return
}
currentUser := router.GetUser(c)
messages := msg.GetMessages(c)
if currentUser.NeedsCaptcha() {
userCaptcha := captcha.Extract(c)
if !captcha.Authenticate(userCaptcha) {
messages.AddErrorT("errors", "bad_captcha")
}
}
content := sanitize.Sanitize(c.PostForm("comment"), "comment")
if strings.TrimSpace(content) == "" {
messages.AddErrorT("errors", "comment_empty")
}
if len(content) > config.Get().CommentLength {
messages.AddErrorT("errors", "comment_toolong")
}
if !messages.HasErrors() {
_, err := comments.Create(content, torrent, currentUser)
if err != nil {
messages.Error(err)
}
}
url := "/view/" + strconv.FormatUint(uint64(torrent.ID), 10)
c.Redirect(302, url)
}

44
controllers/torrent/delete.go Fichier normal
Voir le fichier

@ -0,0 +1,44 @@
package torrentController
import (
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/activities"
"github.com/NyaaPantsu/nyaa/models/reports"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/utils/search/structs"
"github.com/gin-gonic/gin"
)
// TorrentDeleteUserPanel : Controller for deleting a user torrent by a user
func TorrentDeleteUserPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
currentUser := router.GetUser(c)
torrent, _ := torrents.FindByID(uint(id))
if currentUser.CurrentOrAdmin(torrent.UploaderID) {
_, _, err := torrent.Delete(false)
if err == nil {
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
if currentUser.HasAdmin() { // We hide username on log activity if user is not admin and torrent is hidden
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, currentUser.Username)
} else {
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, username)
}
//delete reports of torrent
whereParams := structs.CreateWhereParams("torrent_id = ?", id)
torrentReports, _, _ := reports.FindOrderBy(&whereParams, "", 0, 0)
for _, report := range torrentReports {
report.Delete(false)
}
}
c.Redirect(http.StatusSeeOther, "/?deleted")
} else {
c.AbortWithStatus(http.StatusNotFound)
}
}

Voir le fichier

@ -0,0 +1,54 @@
package torrentController
import (
"errors"
"fmt"
"io"
"net/http"
"os"
"strconv"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/gin-gonic/gin"
)
// DownloadTorrent : Controller for downloading a torrent
func DownloadTorrent(c *gin.Context) {
hash := c.Param("hash")
if hash == "" && len(config.Get().Torrents.FileStorage) == 0 {
//File not found, send 404
c.AbortWithError(http.StatusNotFound, errors.New("File not found"))
return
}
//Check if file exists and open
Openfile, err := os.Open(fmt.Sprintf("%s%c%s.torrent", config.Get().Torrents.FileStorage, os.PathSeparator, hash))
if err != nil {
//File not found, send 404
c.AbortWithError(http.StatusNotFound, errors.New("File not found"))
return
}
defer Openfile.Close() //Close after function return
//Get the file size
FileStat, _ := Openfile.Stat() //Get info from file
FileSize := strconv.FormatInt(FileStat.Size(), 10) //Get file size as a string
torrent, err := torrents.FindRawByHash(hash)
if err != nil {
//File not found, send 404
c.AbortWithError(http.StatusNotFound, errors.New("File not found"))
return
}
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.torrent\"", torrent.Name))
c.Header("Content-Type", "application/x-bittorrent")
c.Header("Content-Length", FileSize)
//Send the file
// We reset the offset to 0
Openfile.Seek(0, 0)
io.Copy(c.Writer, Openfile) //'Copy' the file to the client
}

58
controllers/torrent/edit.go Fichier normal
Voir le fichier

@ -0,0 +1,58 @@
package torrentController
import (
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/templates"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/upload"
"github.com/NyaaPantsu/nyaa/utils/validator/torrent"
"github.com/gin-gonic/gin"
)
// TorrentEditUserPanel : Controller for editing a user torrent by a user, after GET request
func TorrentEditUserPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
torrent, _ := torrents.FindByID(uint(id))
currentUser := router.GetUser(c)
if currentUser.CurrentOrAdmin(torrent.UploaderID) {
uploadForm := torrentValidator.TorrentRequest{}
uploadForm.Name = torrent.Name
uploadForm.Category = strconv.Itoa(torrent.Category) + "_" + strconv.Itoa(torrent.SubCategory)
uploadForm.Remake = torrent.Status == models.TorrentStatusRemake
uploadForm.WebsiteLink = string(torrent.WebsiteLink)
uploadForm.Description = string(torrent.Description)
uploadForm.Hidden = torrent.Hidden
uploadForm.Languages = torrent.Languages
templates.Form(c, "site/torrents/edit.jet.html", uploadForm)
} else {
c.AbortWithStatus(http.StatusNotFound)
}
}
// TorrentPostEditUserPanel : Controller for editing a user torrent by a user, after post request
func TorrentPostEditUserPanel(c *gin.Context) {
var uploadForm torrentValidator.UpdateRequest
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
uploadForm.ID = uint(id)
messages := msg.GetMessages(c)
torrent, _ := torrents.FindByID(uint(id))
currentUser := router.GetUser(c)
if torrent.ID > 0 && currentUser.CurrentOrAdmin(torrent.UploaderID) {
errUp := upload.ExtractEditInfo(c, &uploadForm.Update)
if errUp != nil {
messages.AddErrorT("errors", "fail_torrent_update")
}
if !messages.HasErrors() {
upload.UpdateTorrent(&uploadForm, torrent, currentUser).Update(currentUser.HasAdmin())
messages.AddInfoT("infos", "torrent_updated")
}
templates.Form(c, "site/torrents/edit.jet.html", uploadForm.Update)
} else {
c.AbortWithStatus(http.StatusNotFound)
}
}

20
controllers/torrent/router.go Fichier normal
Voir le fichier

@ -0,0 +1,20 @@
package torrentController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
router.Get().Any("/download/:hash", DownloadTorrent)
torrentRoutes := router.Get().Group("/torrent")
{
torrentRoutes.GET("/", TorrentEditUserPanel)
torrentRoutes.POST("/", TorrentPostEditUserPanel)
torrentRoutes.GET("/delete", TorrentDeleteUserPanel)
}
torrentViewRoutes := router.Get().Group("/view")
{
torrentViewRoutes.GET("/:id", ViewHandler)
torrentViewRoutes.HEAD("/:id", ViewHeadHandler)
torrentViewRoutes.POST("/:id", PostCommentHandler)
}
}

67
controllers/torrent/view.go Fichier normal
Voir le fichier

@ -0,0 +1,67 @@
package torrentController
import (
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models/notifications"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/captcha"
"github.com/NyaaPantsu/nyaa/utils/filelist"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/gin-gonic/gin"
)
// ViewHandler : Controller for displaying a torrent
func ViewHandler(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 32)
messages := msg.GetMessages(c)
user := router.GetUser(c)
if c.Request.URL.Query()["success"] != nil {
messages.AddInfoT("infos", "torrent_uploaded")
}
if c.Request.URL.Query()["badcaptcha"] != nil {
messages.AddErrorT("errors", "bad_captcha")
}
if c.Request.URL.Query()["reported"] != nil {
messages.AddInfoTf("infos", "report_msg", id)
}
torrent, err := torrents.FindByID(uint(id))
if c.Request.URL.Query()["notif"] != nil {
notifications.ToggleReadNotification(torrent.Identifier(), user.ID)
}
if err != nil {
c.Status(http.StatusNotFound)
return
}
b := torrent.ToJSON()
folder := filelist.FileListToFolder(torrent.FileList, "root")
captchaID := ""
if user.NeedsCaptcha() {
captchaID = captcha.GetID()
}
templates.Torrent(c, b, folder, captchaID)
}
// ViewHeadHandler : Controller for checking a torrent
func ViewHeadHandler(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 32)
if err != nil {
return
}
_, err = torrents.FindRawByID(uint(id))
if err != nil {
c.Status(http.StatusNotFound)
return
}
c.AbortWithStatus(http.StatusOK)
}

7
controllers/upload/router.go Fichier normal
Voir le fichier

@ -0,0 +1,7 @@
package uploadController
import "github.com/NyaaPantsu/nyaa/controllers/router"
func init() {
router.Get().Any("/upload", UploadHandler)
}

Voir le fichier

@ -1,10 +1,11 @@
package controllers
package uploadController
import (
"errors"
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/captcha"
@ -17,7 +18,7 @@ import (
// UploadHandler : Main Controller for uploading a torrent
func UploadHandler(c *gin.Context) {
user := getUser(c)
user := router.GetUser(c)
if !user.CanUpload() {
T := publicSettings.GetTfuncFromRequest(c)
c.AbortWithError(http.StatusBadRequest, errors.New(string(T("uploads_disabled"))))
@ -34,7 +35,7 @@ func UploadHandler(c *gin.Context) {
// UploadPostHandler : Controller for uploading a torrent, after POST request, redirect or makes error in messages
func UploadPostHandler(c *gin.Context) {
var uploadForm torrentValidator.TorrentRequest
user := getUser(c)
user := router.GetUser(c)
messages := msg.GetMessages(c) // new utils for errors and infos
if user.NeedsCaptcha() {
@ -68,7 +69,7 @@ func UploadPostHandler(c *gin.Context) {
func UploadGetHandler(c *gin.Context) {
var uploadForm torrentValidator.TorrentRequest
_ = upload.ExtractInfo(c, &uploadForm)
user := getUser(c)
user := router.GetUser(c)
if user.NeedsCaptcha() {
uploadForm.CaptchaID = captcha.GetID()
} else {

29
controllers/user/follow.go Fichier normal
Voir le fichier

@ -0,0 +1,29 @@
package userController
import (
"net/http"
"strconv"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/gin-gonic/gin"
)
// UserFollowHandler : Controller to follow/unfollow users, need user id to follow
func UserFollowHandler(c *gin.Context) {
var followAction string
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
currentUser := router.GetUser(c)
user, _, errorUser := users.FindForAdmin(uint(id))
if errorUser == nil && user.ID > 0 {
if !currentUser.IsFollower(user) {
followAction = "followed"
currentUser.SetFollow(user)
} else {
followAction = "unfollowed"
currentUser.RemoveFollow(user)
}
}
url := "/user/" + strconv.Itoa(int(user.ID)) + "/" + user.Username + "?" + followAction
c.Redirect(http.StatusSeeOther, url)
}

46
controllers/user/login.go Fichier normal
Voir le fichier

@ -0,0 +1,46 @@
package userController
import (
"net/http"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/cookies"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/validator"
"github.com/NyaaPantsu/nyaa/utils/validator/user"
"github.com/gin-gonic/gin"
)
// UserLoginFormHandler : Getting View User Login
func UserLoginFormHandler(c *gin.Context) {
_, _, errorUser := cookies.CurrentUser(c)
// User is already connected, redirect to home
if errorUser == nil {
c.Redirect(http.StatusSeeOther, "/")
return
}
loginForm := userValidator.LoginForm{
RedirectTo: c.DefaultQuery("redirectTo", ""),
}
templates.Form(c, "site/user/login.jet.html", loginForm)
}
// UserLoginPostHandler : Post Login controller
func UserLoginPostHandler(c *gin.Context) {
b := userValidator.LoginForm{}
c.Bind(&b)
messages := msg.GetMessages(c)
validator.ValidateForm(&b, messages)
if !messages.HasErrors() {
_, _, errorUser := cookies.CreateUserAuthentication(c, &b)
if errorUser == nil {
url := c.DefaultPostForm("redirectTo", "/")
c.Redirect(http.StatusSeeOther, url)
return
}
messages.ErrorT(errorUser)
}
UserLoginFormHandler(c)
}

20
controllers/user/logout.go Fichier normal
Voir le fichier

@ -0,0 +1,20 @@
package userController
import (
"net/http"
"github.com/NyaaPantsu/nyaa/utils/cookies"
"github.com/gin-gonic/gin"
)
// UserLogoutHandler : Controller to logout users
func UserLogoutHandler(c *gin.Context) {
logout := c.PostForm("logout")
if logout != "" {
cookies.Clear(c)
url := c.DefaultPostForm("redirectTo", "/")
c.Redirect(http.StatusSeeOther, url)
} else {
c.Status(http.StatusNotFound)
}
}

Voir le fichier

@ -1,15 +1,16 @@
package controllers
package userController
import (
"net/http"
"strconv"
"time"
"net/http"
"github.com/NyaaPantsu/nyaa/controllers/router"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/notifications"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/captcha"
"github.com/NyaaPantsu/nyaa/utils/cookies"
"github.com/NyaaPantsu/nyaa/utils/crypto"
"github.com/NyaaPantsu/nyaa/utils/email"
@ -21,35 +22,6 @@ import (
"github.com/gin-gonic/gin"
)
// UserRegisterFormHandler : Getting View User Registration
func UserRegisterFormHandler(c *gin.Context) {
_, _, errorUser := cookies.CurrentUser(c)
// User is already connected, redirect to home
if errorUser == nil {
SearchHandler(c)
return
}
registrationForm := userValidator.RegistrationForm{}
c.Bind(&registrationForm)
registrationForm.CaptchaID = captcha.GetID()
templates.Form(c, "site/user/register.jet.html", registrationForm)
}
// UserLoginFormHandler : Getting View User Login
func UserLoginFormHandler(c *gin.Context) {
_, _, errorUser := cookies.CurrentUser(c)
// User is already connected, redirect to home
if errorUser == nil {
SearchHandler(c)
return
}
loginForm := userValidator.LoginForm{
RedirectTo: c.DefaultQuery("redirectTo", ""),
}
templates.Form(c, "site/user/login.jet.html", loginForm)
}
// UserProfileHandler : Getting User Profile
func UserProfileHandler(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
@ -58,7 +30,7 @@ func UserProfileHandler(c *gin.Context) {
userProfile, _, errorUser := users.FindForAdmin(uint(id))
if errorUser == nil {
currentUser := getUser(c)
currentUser := router.GetUser(c)
follow := c.Request.URL.Query()["followed"]
unfollow := c.Request.URL.Query()["unfollowed"]
deleteVar := c.Request.URL.Query()["delete"]
@ -95,14 +67,14 @@ func UserProfileHandler(c *gin.Context) {
templates.UserProfile(c, userProfile)
}
} else {
NotFoundHandler(c)
c.Status(http.StatusNotFound)
}
}
// UserDetailsHandler : Getting User Profile Details View
func UserDetailsHandler(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
currentUser := getUser(c)
currentUser := router.GetUser(c)
userProfile, _, errorUser := users.FindForAdmin(uint(id))
if errorUser == nil && currentUser.CurrentOrAdmin(userProfile.ID) {
@ -112,17 +84,17 @@ func UserDetailsHandler(c *gin.Context) {
userProfile.ParseSettings()
templates.UserProfileEdit(c, userProfile, b, availableLanguages)
} else {
NotFoundHandler(c)
c.Status(http.StatusNotFound)
}
}
// UserProfileFormHandler : Getting View User Profile Update
func UserProfileFormHandler(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
currentUser := getUser(c)
currentUser := router.GetUser(c)
userProfile, _, errorUser := users.FindForAdmin(uint(id))
if errorUser != nil || !currentUser.CurrentOrAdmin(userProfile.ID) || userProfile.ID == 0 {
NotFoundHandler(c)
c.Status(http.StatusNotFound)
return
}
userProfile.ParseSettings()
@ -176,114 +148,9 @@ func UserProfileFormHandler(c *gin.Context) {
templates.UserProfileEdit(c, userProfile, userForm, availableLanguages)
}
// UserRegisterPostHandler : Post Registration controller, we do some check on the form here, the rest on user service
func UserRegisterPostHandler(c *gin.Context) {
b := userValidator.RegistrationForm{}
messages := msg.GetMessages(c)
if !captcha.Authenticate(captcha.Extract(c)) {
messages.AddErrorT("errors", "bad_captcha")
}
if !messages.HasErrors() {
if len(c.PostForm("email")) > 0 {
if !userValidator.EmailValidation(c.PostForm("email")) {
messages.AddErrorT("email", "email_not_valid")
}
}
if !userValidator.ValidateUsername(c.PostForm("username")) {
messages.AddErrorT("username", "username_illegal")
}
if !messages.HasErrors() {
c.Bind(&b)
validator.ValidateForm(&b, messages)
if !messages.HasErrors() {
user, _ := users.CreateUser(c)
if !messages.HasErrors() {
_, err := cookies.SetLogin(c, user)
if err != nil {
messages.Error(err)
}
if b.Email != "" {
email.SendVerificationToUser(user, b.Email)
}
if !messages.HasErrors() {
templates.Static(c, "site/static/signup_success.jet.html")
}
}
}
}
}
if messages.HasErrors() {
UserRegisterFormHandler(c)
}
}
// UserVerifyEmailHandler : Controller when verifying email, needs a token
func UserVerifyEmailHandler(c *gin.Context) {
token := c.Param("token")
messages := msg.GetMessages(c)
_, errEmail := email.EmailVerification(token, c)
if errEmail != nil {
messages.ImportFromError("errors", errEmail)
}
templates.Static(c, "site/static/verify_success.jet.html")
}
// UserLoginPostHandler : Post Login controller
func UserLoginPostHandler(c *gin.Context) {
b := userValidator.LoginForm{}
c.Bind(&b)
messages := msg.GetMessages(c)
validator.ValidateForm(&b, messages)
if !messages.HasErrors() {
_, _, errorUser := cookies.CreateUserAuthentication(c, &b)
if errorUser == nil {
url := c.DefaultPostForm("redirectTo", "/")
c.Redirect(http.StatusSeeOther, url)
return
}
messages.ErrorT(errorUser)
}
UserLoginFormHandler(c)
}
// UserLogoutHandler : Controller to logout users
func UserLogoutHandler(c *gin.Context) {
logout := c.PostForm("logout")
if logout != "" {
cookies.Clear(c)
url := c.DefaultPostForm("redirectTo", "/")
c.Redirect(http.StatusSeeOther, url)
} else {
NotFoundHandler(c)
}
}
// UserFollowHandler : Controller to follow/unfollow users, need user id to follow
func UserFollowHandler(c *gin.Context) {
var followAction string
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
currentUser := getUser(c)
user, _, errorUser := users.FindForAdmin(uint(id))
if errorUser == nil && user.ID > 0 {
if !currentUser.IsFollower(user) {
followAction = "followed"
currentUser.SetFollow(user)
} else {
followAction = "unfollowed"
currentUser.RemoveFollow(user)
}
}
url := "/user/" + strconv.Itoa(int(user.ID)) + "/" + user.Username + "?" + followAction
c.Redirect(http.StatusSeeOther, url)
}
// UserNotificationsHandler : Controller to show user notifications
func UserNotificationsHandler(c *gin.Context) {
currentUser := getUser(c)
currentUser := router.GetUser(c)
if currentUser.ID > 0 {
messages := msg.GetMessages(c)
if c.Request.URL.Query()["clear"] != nil {
@ -293,19 +160,19 @@ func UserNotificationsHandler(c *gin.Context) {
}
templates.UserProfileNotifications(c, currentUser)
} else {
NotFoundHandler(c)
c.Status(http.StatusNotFound)
}
}
// UserAPIKeyResetHandler : Controller to reset user api key
func UserAPIKeyResetHandler(c *gin.Context) {
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
currentUser := getUser(c)
currentUser := router.GetUser(c)
messages := msg.GetMessages(c)
userProfile, _, errorUser := users.FindForAdmin(uint(id))
if errorUser != nil || !currentUser.CurrentOrAdmin(userProfile.ID) || userProfile.ID == 0 {
NotFoundHandler(c)
c.Status(http.StatusNotFound)
return
}
userProfile.APIToken, _ = crypto.GenerateRandomToken32()

72
controllers/user/register.go Fichier normal
Voir le fichier

@ -0,0 +1,72 @@
package userController
import (
"net/http"
"github.com/NyaaPantsu/nyaa/models/users"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/captcha"
"github.com/NyaaPantsu/nyaa/utils/cookies"
"github.com/NyaaPantsu/nyaa/utils/email"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/validator"
"github.com/NyaaPantsu/nyaa/utils/validator/user"
"github.com/gin-gonic/gin"
)
// UserRegisterFormHandler : Getting View User Registration
func UserRegisterFormHandler(c *gin.Context) {
_, _, errorUser := cookies.CurrentUser(c)
// User is already connected, redirect to home
if errorUser == nil {
c.Redirect(http.StatusSeeOther, "/")
return
}
registrationForm := userValidator.RegistrationForm{}
c.Bind(&registrationForm)
registrationForm.CaptchaID = captcha.GetID()
templates.Form(c, "site/user/register.jet.html", registrationForm)
}
// UserRegisterPostHandler : Post Registration controller, we do some check on the form here, the rest on user service
func UserRegisterPostHandler(c *gin.Context) {
b := userValidator.RegistrationForm{}
messages := msg.GetMessages(c)
if !captcha.Authenticate(captcha.Extract(c)) {
messages.AddErrorT("errors", "bad_captcha")
}
if !messages.HasErrors() {
if len(c.PostForm("email")) > 0 {
if !userValidator.EmailValidation(c.PostForm("email")) {
messages.AddErrorT("email", "email_not_valid")
}
}
if !userValidator.ValidateUsername(c.PostForm("username")) {
messages.AddErrorT("username", "username_illegal")
}
if !messages.HasErrors() {
c.Bind(&b)
validator.ValidateForm(&b, messages)
if !messages.HasErrors() {
user, _ := users.CreateUser(c)
if !messages.HasErrors() {
_, err := cookies.SetLogin(c, user)
if err != nil {
messages.Error(err)
}
if b.Email != "" {
email.SendVerificationToUser(user, b.Email)
}
if !messages.HasErrors() {
templates.Static(c, "site/static/signup_success.jet.html")
}
}
}
}
}
if messages.HasErrors() {
UserRegisterFormHandler(c)
}
}

35
controllers/user/router.go Fichier normal
Voir le fichier

@ -0,0 +1,35 @@
package userController
import "github.com/NyaaPantsu/nyaa/controllers/router"
import "github.com/NyaaPantsu/nyaa/controllers/feed"
func init() {
// Login
router.Get().POST("/login", UserLoginPostHandler)
router.Get().GET("/login", UserLoginFormHandler)
// Register
router.Get().GET("/register", UserRegisterFormHandler)
router.Get().POST("/register", UserRegisterPostHandler)
// Logout
router.Get().POST("/logout", UserLogoutHandler)
// Notifications
router.Get().GET("/notifications", UserNotificationsHandler)
// Verify Email
router.Get().Any("/verify/email/:token", UserVerifyEmailHandler)
// User Profile specific routes
userRoutes := router.Get().Group("/user")
{
userRoutes.GET("/:id/:username", UserProfileHandler)
userRoutes.GET("/:id/:username/follow", UserFollowHandler)
userRoutes.GET("/:id/:username/edit", UserDetailsHandler)
userRoutes.POST("/:id/:username/edit", UserProfileFormHandler)
userRoutes.GET("/:id/:username/apireset", UserAPIKeyResetHandler)
userRoutes.GET("/:id/:username/feed/*page", feedController.RSSHandler)
}
}

20
controllers/user/verify.go Fichier normal
Voir le fichier

@ -0,0 +1,20 @@
package userController
import (
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/email"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/gin-gonic/gin"
)
// UserVerifyEmailHandler : Controller when verifying email, needs a token
func UserVerifyEmailHandler(c *gin.Context) {
token := c.Param("token")
messages := msg.GetMessages(c)
_, errEmail := email.EmailVerification(token, c)
if errEmail != nil {
messages.ImportFromError("errors", errEmail)
}
templates.Static(c, "site/static/verify_success.jet.html")
}

Voir le fichier

@ -1,288 +0,0 @@
package controllers
import (
"errors"
"fmt"
"io"
"net/http"
"strconv"
"strings"
"os"
"github.com/NyaaPantsu/nyaa/config"
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/activities"
"github.com/NyaaPantsu/nyaa/models/comments"
"github.com/NyaaPantsu/nyaa/models/notifications"
"github.com/NyaaPantsu/nyaa/models/reports"
"github.com/NyaaPantsu/nyaa/models/torrents"
"github.com/NyaaPantsu/nyaa/templates"
"github.com/NyaaPantsu/nyaa/utils/captcha"
"github.com/NyaaPantsu/nyaa/utils/filelist"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/sanitize"
"github.com/NyaaPantsu/nyaa/utils/search/structs"
"github.com/NyaaPantsu/nyaa/utils/upload"
"github.com/NyaaPantsu/nyaa/utils/validator/torrent"
"github.com/gin-gonic/gin"
)
// ViewHandler : Controller for displaying a torrent
func ViewHandler(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 32)
messages := msg.GetMessages(c)
user := getUser(c)
if c.Request.URL.Query()["success"] != nil {
messages.AddInfoT("infos", "torrent_uploaded")
}
if c.Request.URL.Query()["badcaptcha"] != nil {
messages.AddErrorT("errors", "bad_captcha")
}
if c.Request.URL.Query()["reported"] != nil {
messages.AddInfoTf("infos", "report_msg", id)
}
torrent, err := torrents.FindByID(uint(id))
if c.Request.URL.Query()["notif"] != nil {
notifications.ToggleReadNotification(torrent.Identifier(), user.ID)
}
if err != nil {
NotFoundHandler(c)
return
}
b := torrent.ToJSON()
folder := filelist.FileListToFolder(torrent.FileList, "root")
captchaID := ""
if user.NeedsCaptcha() {
captchaID = captcha.GetID()
}
templates.Torrent(c, b, folder, captchaID)
}
// ViewHeadHandler : Controller for checking a torrent
func ViewHeadHandler(c *gin.Context) {
id, err := strconv.ParseInt(c.Param("id"), 10, 32)
if err != nil {
return
}
_, err = torrents.FindRawByID(uint(id))
if err != nil {
NotFoundHandler(c)
return
}
c.AbortWithStatus(http.StatusOK)
}
// PostCommentHandler : Controller for posting a comment
func PostCommentHandler(c *gin.Context) {
id, _ := strconv.ParseInt(c.Param("id"), 10, 32)
torrent, err := torrents.FindByID(uint(id))
if err != nil {
NotFoundHandler(c)
return
}
currentUser := getUser(c)
messages := msg.GetMessages(c)
if currentUser.NeedsCaptcha() {
userCaptcha := captcha.Extract(c)
if !captcha.Authenticate(userCaptcha) {
messages.AddErrorT("errors", "bad_captcha")
}
}
content := sanitize.Sanitize(c.PostForm("comment"), "comment")
if strings.TrimSpace(content) == "" {
messages.AddErrorT("errors", "comment_empty")
}
if len(content) > config.Get().CommentLength {
messages.AddErrorT("errors", "comment_toolong")
}
if !messages.HasErrors() {
_, err := comments.Create(content, torrent, currentUser)
if err != nil {
messages.Error(err)
}
}
url := "/view/" + strconv.FormatUint(uint64(torrent.ID), 10)
c.Redirect(302, url)
}
// ReportTorrentHandler : Controller for sending a torrent report
func ReportTorrentHandler(c *gin.Context) {
fmt.Println("report")
id, _ := strconv.ParseInt(c.Param("id"), 10, 32)
messages := msg.GetMessages(c)
captchaError := "?reported"
currentUser := getUser(c)
if currentUser.NeedsCaptcha() {
userCaptcha := captcha.Extract(c)
if !captcha.Authenticate(userCaptcha) {
captchaError = "?badcaptcha"
messages.AddErrorT("errors", "bad_captcha")
}
}
torrent, err := torrents.FindByID(uint(id))
if err != nil {
messages.Error(err)
}
if !messages.HasErrors() {
_, err := reports.Create(c.PostForm("report_type"), torrent, currentUser)
messages.AddInfoTf("infos", "report_msg", id)
if err != nil {
messages.ImportFromError("errors", err)
}
c.Redirect(http.StatusSeeOther, "/view/"+strconv.Itoa(int(torrent.ID))+captchaError)
} else {
ReportViewTorrentHandler(c)
}
}
// ReportTorrentHandler: Controller for sending a torrent report
func ReportViewTorrentHandler(c *gin.Context) {
type Report struct {
ID uint
CaptchaID string
}
id, _ := strconv.ParseInt(c.Param("id"), 10, 32)
messages := msg.GetMessages(c)
currentUser := getUser(c)
if currentUser.ID > 0 {
torrent, err := torrents.FindByID(uint(id))
if err != nil {
messages.Error(err)
}
captchaID := ""
if currentUser.NeedsCaptcha() {
captchaID = captcha.GetID()
}
templates.Form(c, "site/torrents/report.jet.html", Report{torrent.ID, captchaID})
} else {
c.Status(404)
}
}
// TorrentEditUserPanel : Controller for editing a user torrent by a user, after GET request
func TorrentEditUserPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
torrent, _ := torrents.FindByID(uint(id))
currentUser := getUser(c)
if currentUser.CurrentOrAdmin(torrent.UploaderID) {
uploadForm := torrentValidator.TorrentRequest{}
uploadForm.Name = torrent.Name
uploadForm.Category = strconv.Itoa(torrent.Category) + "_" + strconv.Itoa(torrent.SubCategory)
uploadForm.Remake = torrent.Status == models.TorrentStatusRemake
uploadForm.WebsiteLink = string(torrent.WebsiteLink)
uploadForm.Description = string(torrent.Description)
uploadForm.Hidden = torrent.Hidden
uploadForm.Languages = torrent.Languages
templates.Form(c, "site/torrents/edit.jet.html", uploadForm)
} else {
NotFoundHandler(c)
}
}
// TorrentPostEditUserPanel : Controller for editing a user torrent by a user, after post request
func TorrentPostEditUserPanel(c *gin.Context) {
var uploadForm torrentValidator.UpdateRequest
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
uploadForm.ID = uint(id)
messages := msg.GetMessages(c)
torrent, _ := torrents.FindByID(uint(id))
currentUser := getUser(c)
if torrent.ID > 0 && currentUser.CurrentOrAdmin(torrent.UploaderID) {
errUp := upload.ExtractEditInfo(c, &uploadForm.Update)
if errUp != nil {
messages.AddErrorT("errors", "fail_torrent_update")
}
if !messages.HasErrors() {
upload.UpdateTorrent(&uploadForm, torrent, currentUser).Update(currentUser.HasAdmin())
messages.AddInfoT("infos", "torrent_updated")
}
templates.Form(c, "site/torrents/edit.jet.html", uploadForm.Update)
} else {
NotFoundHandler(c)
}
}
// TorrentDeleteUserPanel : Controller for deleting a user torrent by a user
func TorrentDeleteUserPanel(c *gin.Context) {
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
currentUser := getUser(c)
torrent, _ := torrents.FindByID(uint(id))
if currentUser.CurrentOrAdmin(torrent.UploaderID) {
_, _, err := torrent.Delete(false)
if err == nil {
if torrent.Uploader == nil {
torrent.Uploader = &models.User{}
}
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
if currentUser.HasAdmin() { // We hide username on log activity if user is not admin and torrent is hidden
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, currentUser.Username)
} else {
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, username)
}
//delete reports of torrent
whereParams := structs.CreateWhereParams("torrent_id = ?", id)
torrentReports, _, _ := reports.FindOrderBy(&whereParams, "", 0, 0)
for _, report := range torrentReports {
report.Delete(false)
}
}
c.Redirect(http.StatusSeeOther, "/?deleted")
} else {
NotFoundHandler(c)
}
}
// DownloadTorrent : Controller for downloading a torrent
func DownloadTorrent(c *gin.Context) {
hash := c.Param("hash")
if hash == "" && len(config.Get().Torrents.FileStorage) == 0 {
//File not found, send 404
c.AbortWithError(http.StatusNotFound, errors.New("File not found"))
return
}
//Check if file exists and open
Openfile, err := os.Open(fmt.Sprintf("%s%c%s.torrent", config.Get().Torrents.FileStorage, os.PathSeparator, hash))
if err != nil {
//File not found, send 404
c.AbortWithError(http.StatusNotFound, errors.New("File not found"))
return
}
defer Openfile.Close() //Close after function return
//Get the file size
FileStat, _ := Openfile.Stat() //Get info from file
FileSize := strconv.FormatInt(FileStat.Size(), 10) //Get file size as a string
torrent, err := torrents.FindRawByHash(hash)
if err != nil {
//File not found, send 404
c.AbortWithError(http.StatusNotFound, errors.New("File not found"))
return
}
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.torrent\"", torrent.Name))
c.Header("Content-Type", "application/x-bittorrent")
c.Header("Content-Length", FileSize)
//Send the file
// We reset the offset to 0
Openfile.Seek(0, 0)
io.Copy(c.Writer, Openfile) //'Copy' the file to the client
}