Merge branch 'master' of https://github.com/ewhal/nyaa into search-caching
Cette révision appartient à :
révision
5d40d02820
11 fichiers modifiés avec 220 ajouts et 11 suppressions
|
@ -4,7 +4,7 @@ import (
|
||||||
"github.com/ewhal/nyaa/config"
|
"github.com/ewhal/nyaa/config"
|
||||||
"github.com/ewhal/nyaa/model"
|
"github.com/ewhal/nyaa/model"
|
||||||
"github.com/ewhal/nyaa/util/log"
|
"github.com/ewhal/nyaa/util/log"
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/azhao12345/gorm"
|
||||||
_ "github.com/jinzhu/gorm/dialects/postgres"
|
_ "github.com/jinzhu/gorm/dialects/postgres"
|
||||||
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
_ "github.com/jinzhu/gorm/dialects/sqlite"
|
||||||
)
|
)
|
||||||
|
@ -30,7 +30,7 @@ func GormInit(conf *config.Config) (*gorm.DB, error) {
|
||||||
// TODO: Enable Gorm initialization for non-development builds
|
// TODO: Enable Gorm initialization for non-development builds
|
||||||
if config.Environment == "DEVELOPMENT" {
|
if config.Environment == "DEVELOPMENT" {
|
||||||
db.LogMode(true)
|
db.LogMode(true)
|
||||||
db.AutoMigrate(&model.Torrent{}, &model.UserFollows{}, &model.User{}, &model.Comment{}, &model.OldComment{})
|
db.AutoMigrate(&model.Torrent{}, &model.UserFollows{}, &model.User{}, &model.Comment{}, &model.OldComment{}, &model.TorrentReport{})
|
||||||
}
|
}
|
||||||
|
|
||||||
return db, nil
|
return db, nil
|
||||||
|
|
|
@ -61,6 +61,20 @@ func (t Torrent) Size() (s int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Add field to specify kind of reports
|
||||||
|
// TODO Add CreatedAt field
|
||||||
|
// INFO User can be null (anonymous reports)
|
||||||
|
// FIXME can't preload field Torrents for model.TorrentReport
|
||||||
|
type TorrentReport struct {
|
||||||
|
ID uint `gorm:"column:torrent_report_id;primary_key"`
|
||||||
|
Description string `gorm:"column:type"`
|
||||||
|
TorrentID uint
|
||||||
|
UserID uint
|
||||||
|
Torrent Torrent `gorm:"AssociationForeignKey:TorrentID;ForeignKey:ID"`
|
||||||
|
User User `gorm:"AssociationForeignKey:UserID;ForeignKey:ID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need a JSON object instead of a Gorm structure because magnet URLs are
|
/* We need a JSON object instead of a Gorm structure because magnet URLs are
|
||||||
|
@ -97,6 +111,20 @@ type TorrentJSON struct {
|
||||||
TorrentLink template.URL `json:"torrent"`
|
TorrentLink template.URL `json:"torrent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TorrentReportJson struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Torrent TorrentJSON `json:"torrent"`
|
||||||
|
User string
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Model Conversion to Json */
|
||||||
|
|
||||||
|
func (report *TorrentReport) ToJson() TorrentReportJson {
|
||||||
|
json := TorrentReportJson{report.ID, report.Description, report.Torrent.ToJSON(), report.User.Username}
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
// ToJSON converts a model.Torrent to its equivalent JSON structure
|
// ToJSON converts a model.Torrent to its equivalent JSON structure
|
||||||
func (t *Torrent) ToJSON() TorrentJSON {
|
func (t *Torrent) ToJSON() TorrentJSON {
|
||||||
magnet := util.InfoHashToMagnet(strings.TrimSpace(t.Hash), t.Name, config.Trackers...)
|
magnet := util.InfoHashToMagnet(strings.TrimSpace(t.Hash), t.Name, config.Trackers...)
|
||||||
|
@ -149,3 +177,11 @@ func TorrentsToJSON(t []Torrent) []TorrentJSON { // TODO: Convert to singular ve
|
||||||
}
|
}
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TorrentReportsToJSON(reports []TorrentReport) []TorrentReportJson {
|
||||||
|
json := make([]TorrentReportJson, len(reports))
|
||||||
|
for i := range reports {
|
||||||
|
json[i] = reports[i].ToJson()
|
||||||
|
}
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ func init() {
|
||||||
gzipUserFollowHandler := handlers.CompressHandler(http.HandlerFunc(UserFollowHandler))
|
gzipUserFollowHandler := handlers.CompressHandler(http.HandlerFunc(UserFollowHandler))
|
||||||
gzipUserProfileFormHandler := handlers.CompressHandler(http.HandlerFunc(UserProfileFormHandler))
|
gzipUserProfileFormHandler := handlers.CompressHandler(http.HandlerFunc(UserProfileFormHandler))
|
||||||
|
|
||||||
|
|
||||||
gzipIndexModPanel := handlers.CompressHandler(http.HandlerFunc(IndexModPanel))
|
gzipIndexModPanel := handlers.CompressHandler(http.HandlerFunc(IndexModPanel))
|
||||||
gzipTorrentsListPanel := handlers.CompressHandler(http.HandlerFunc(TorrentsListPanel))
|
gzipTorrentsListPanel := handlers.CompressHandler(http.HandlerFunc(TorrentsListPanel))
|
||||||
gzipUsersListPanel := handlers.CompressHandler(http.HandlerFunc(UsersListPanel))
|
gzipUsersListPanel := handlers.CompressHandler(http.HandlerFunc(UsersListPanel))
|
||||||
|
@ -49,7 +48,10 @@ func init() {
|
||||||
gzipCommentDeleteModPanel := handlers.CompressHandler(http.HandlerFunc(CommentDeleteModPanel))
|
gzipCommentDeleteModPanel := handlers.CompressHandler(http.HandlerFunc(CommentDeleteModPanel))
|
||||||
gzipTorrentDeleteModPanel := handlers.CompressHandler(http.HandlerFunc(TorrentDeleteModPanel))
|
gzipTorrentDeleteModPanel := handlers.CompressHandler(http.HandlerFunc(TorrentDeleteModPanel))
|
||||||
|
|
||||||
|
gzipGetTorrentReportHandler := handlers.CompressHandler(http.HandlerFunc(GetTorrentReportHandler))
|
||||||
|
//gzipTorrentReportCreateHandler := handlers.CompressHandler(http.HandlerFunc(CreateTorrentReportHandler))
|
||||||
|
//gzipTorrentReportDeleteHandler := handlers.CompressHandler(http.HandlerFunc(DeleteTorrentReportHandler))
|
||||||
|
//gzipTorrentDeleteHandler := handlers.CompressHandler(http.HandlerFunc(DeleteTorrentHandler))
|
||||||
|
|
||||||
Router = mux.NewRouter()
|
Router = mux.NewRouter()
|
||||||
|
|
||||||
|
@ -91,8 +93,16 @@ func init() {
|
||||||
Router.Handle("/mod/torrent/delete", gzipTorrentDeleteModPanel).Name("mod_tdelete")
|
Router.Handle("/mod/torrent/delete", gzipTorrentDeleteModPanel).Name("mod_tdelete")
|
||||||
Router.Handle("/mod/comment/delete", gzipCommentDeleteModPanel).Name("mod_cdelete")
|
Router.Handle("/mod/comment/delete", gzipCommentDeleteModPanel).Name("mod_cdelete")
|
||||||
|
|
||||||
|
//reporting a torrent
|
||||||
|
Router.HandleFunc("/report/{id}", ReportTorrentHandler).Methods("POST").Name("post_comment")
|
||||||
|
|
||||||
Router.PathPrefix("/captcha").Methods("GET").HandlerFunc(captcha.ServeFiles)
|
Router.PathPrefix("/captcha").Methods("GET").HandlerFunc(captcha.ServeFiles)
|
||||||
|
|
||||||
|
//Router.Handle("/report/create", gzipTorrentReportCreateHandler).Name("torrent_report_create").Methods("POST")
|
||||||
|
// TODO Allow only moderators to access /moderation/*
|
||||||
|
//Router.Handle("/moderation/report/delete", gzipTorrentReportDeleteHandler).Name("torrent_report_delete").Methods("POST")
|
||||||
|
//Router.Handle("/moderation/torrent/delete", gzipTorrentDeleteHandler).Name("torrent_delete").Methods("POST")
|
||||||
|
Router.Handle("/moderation/report", gzipGetTorrentReportHandler ).Name("torrent_report").Methods("GET")
|
||||||
|
|
||||||
Router.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
|
Router.NotFoundHandler = http.HandlerFunc(NotFoundHandler)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
var TemplateDir = "templates"
|
var TemplateDir = "templates"
|
||||||
|
|
||||||
var homeTemplate, searchTemplate, faqTemplate, uploadTemplate, viewTemplate, viewRegisterTemplate, viewLoginTemplate, viewRegisterSuccessTemplate, viewVerifySuccessTemplate, viewProfileTemplate, viewProfileEditTemplate, viewUserDeleteTemplate, notFoundTemplate *template.Template
|
var torrentReportTemplate, homeTemplate, searchTemplate, faqTemplate, uploadTemplate, viewTemplate, viewRegisterTemplate, viewLoginTemplate, viewRegisterSuccessTemplate, viewVerifySuccessTemplate, viewProfileTemplate, viewProfileEditTemplate, viewUserDeleteTemplate, notFoundTemplate *template.Template
|
||||||
|
|
||||||
type templateLoader struct {
|
type templateLoader struct {
|
||||||
templ **template.Template
|
templ **template.Template
|
||||||
|
@ -18,6 +18,11 @@ type templateLoader struct {
|
||||||
// ReloadTemplates reloads templates on runtime
|
// ReloadTemplates reloads templates on runtime
|
||||||
func ReloadTemplates() {
|
func ReloadTemplates() {
|
||||||
templs := []templateLoader{
|
templs := []templateLoader{
|
||||||
|
templateLoader{
|
||||||
|
templ: &torrentReportTemplate,
|
||||||
|
name: "torrent_report",
|
||||||
|
file: "torrent_report.html",
|
||||||
|
},
|
||||||
templateLoader{
|
templateLoader{
|
||||||
templ: &homeTemplate,
|
templ: &homeTemplate,
|
||||||
name: "home",
|
name: "home",
|
||||||
|
|
|
@ -132,6 +132,10 @@ type PanelTorrentEdVbs struct {
|
||||||
Torrent model.Torrent
|
Torrent model.Torrent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ViewTorrentReportsVariables struct {
|
||||||
|
Torrents []model.TorrentReportJson
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Variables used by the upper ones
|
* Variables used by the upper ones
|
||||||
*/
|
*/
|
||||||
|
|
78
router/torrentReportHandler.go
Fichier normal
78
router/torrentReportHandler.go
Fichier normal
|
@ -0,0 +1,78 @@
|
||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/ewhal/nyaa/model"
|
||||||
|
"github.com/ewhal/nyaa/service/moderation"
|
||||||
|
"github.com/ewhal/nyaa/service/user/permission"
|
||||||
|
)
|
||||||
|
/*
|
||||||
|
func SanitizeTorrentReport(torrentReport *model.TorrentReport) {
|
||||||
|
// TODO unescape html ?
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidTorrentReport() bool {
|
||||||
|
// TODO Validate, see if user_id already reported, see if torrent exists
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Only allow moderators for each action in this file
|
||||||
|
func CreateTorrentReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var torrentReport model.TorrentReport
|
||||||
|
var err error
|
||||||
|
|
||||||
|
modelHelper.BindValueForm(&torrentReport, r)
|
||||||
|
if IsValidTorrentReport() {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
SanitizeTorrentReport(&torrentReport)
|
||||||
|
_, err = moderationService.CreateTorrentReport(torrentReport)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteTorrentReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// TODO Figure out how to get torrent report id from form
|
||||||
|
var id int
|
||||||
|
var err error
|
||||||
|
_, err = moderationService.DeleteTorrentReport(id)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
func GetTorrentReportHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
currentUser := GetUser(r)
|
||||||
|
if userPermission.HasAdmin(currentUser) {
|
||||||
|
|
||||||
|
torrentReports, err := moderationService.GetTorrentReports()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = torrentReportTemplate.ExecuteTemplate(w, "torrent_report.html", ViewTorrentReportsVariables{model.TorrentReportsToJSON(torrentReports)})
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http.Error(w, "admins only", http.StatusForbidden)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
|
||||||
|
func DeleteTorrentHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// TODO Figure out how to get torrent report id from form
|
||||||
|
var err error
|
||||||
|
var id string
|
||||||
|
_, err = torrentService.DeleteTorrent(id)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}*/
|
|
@ -63,3 +63,32 @@ err = db.ORM.Create(&comment).Error
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReportTorrentHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
vars := mux.Vars(r)
|
||||||
|
id := vars["id"]
|
||||||
|
|
||||||
|
userCaptcha := captcha.Extract(r)
|
||||||
|
if !captcha.Authenticate(userCaptcha) {
|
||||||
|
http.Error(w, "bad captcha", 403)
|
||||||
|
}
|
||||||
|
currentUser := GetUser(r)
|
||||||
|
|
||||||
|
idNum, err := strconv.Atoi(id)
|
||||||
|
|
||||||
|
userID := currentUser.ID
|
||||||
|
report := model.TorrentReport{Description: r.FormValue("report_type"), TorrentID: uint(idNum), UserID: userID}
|
||||||
|
|
||||||
|
err = db.ORM.Create(&report).Error
|
||||||
|
if err != nil {
|
||||||
|
util.SendError(w, err, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
url, err := Router.Get("view_torrent").URL("id", id)
|
||||||
|
if err == nil {
|
||||||
|
http.Redirect(w, r, url.String(), 302)
|
||||||
|
} else {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
38
service/moderation/torrent_report.go
Fichier normal
38
service/moderation/torrent_report.go
Fichier normal
|
@ -0,0 +1,38 @@
|
||||||
|
package moderationService
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/ewhal/nyaa/db"
|
||||||
|
"github.com/ewhal/nyaa/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Return torrentReport in case we did modified it (ie: CreatedAt field)
|
||||||
|
func CreateTorrentReport(torrentReport model.TorrentReport) (model.TorrentReport, error) {
|
||||||
|
if db.ORM.Create(&torrentReport).Error != nil {
|
||||||
|
return torrentReport, errors.New("TorrentReport was not created")
|
||||||
|
}
|
||||||
|
return torrentReport, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteTorrentReport(id int) (int, error) {
|
||||||
|
var torrentReport model.TorrentReport
|
||||||
|
if db.ORM.First(&torrentReport, id).RecordNotFound() {
|
||||||
|
return http.StatusNotFound, errors.New("Trying to delete a torrent report that does not exists.")
|
||||||
|
}
|
||||||
|
if db.ORM.Delete(&torrentReport).Error != nil {
|
||||||
|
return http.StatusInternalServerError, errors.New("User is not deleted.")
|
||||||
|
}
|
||||||
|
return http.StatusOK, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Add WhereParams to filter the torrent reports (ie: searching description)
|
||||||
|
// TODO Use limit, offset
|
||||||
|
func GetTorrentReports() ([]model.TorrentReport, error) {
|
||||||
|
var torrentReports []model.TorrentReport
|
||||||
|
if db.ORM.Preload("User").Preload("Torrent").Find(&torrentReports).Error != nil {
|
||||||
|
return nil, errors.New("Problem finding all torrent reports.")
|
||||||
|
}
|
||||||
|
return torrentReports, nil
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/ewhal/nyaa/config"
|
"github.com/ewhal/nyaa/config"
|
||||||
"github.com/ewhal/nyaa/db"
|
"github.com/ewhal/nyaa/db"
|
||||||
"github.com/ewhal/nyaa/model"
|
"github.com/ewhal/nyaa/model"
|
||||||
|
|
8
templates/torrent_report.html
Fichier exécutable
8
templates/torrent_report.html
Fichier exécutable
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<table>
|
||||||
|
{{ range .Torrents}}
|
||||||
|
<tr><td><a href="{{ genRoute "mod_tedit" }}?id={{.Torrent.ID}}">{{ .Torrent.Name }}</a></td><td>{{.User}}</td><td>{{.Description}}</td><td><a href="{{ genRoute "mod_tdelete" }}?id={{ .Torrent.ID }}">Delete</a></td></tr>
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
</html>
|
|
@ -92,17 +92,17 @@
|
||||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||||
<h4 class="modal-title">Report Torrent #{{.ID}}</h4>
|
<h4 class="modal-title">Report Torrent #{{.ID}}</h4>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<b>Report type:</b>
|
<b>Report type:</b>
|
||||||
<form action="">
|
<form method="post" action="/report/{{.ID}}">
|
||||||
<input type="radio" name="report" value="illegal"> Illegal content <br/>
|
<input type="radio" name="report_type" value="illegal"> Illegal content <br/>
|
||||||
<input type="radio" name="report" value="spam"> Spam / garbage
|
<input type="radio" name="report_type" value="spam"> Spam / garbage
|
||||||
</form> <br />
|
{{end}}
|
||||||
{{with .Captcha}} {{block "captcha" .}}{{end}} {{end}}
|
{{with .Captcha}} {{block "captcha" .}}{{end}} {{end}}
|
||||||
|
<button type="submit" class="btn btn-default">Report!</button>
|
||||||
|
</form> <br />
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="submit" class="btn btn-default">Report!</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Référencer dans un nouveau ticket