Merge pull request #653 from NyaaPantsu/torrent-weblink
Torrent weblink
Cette révision appartient à :
révision
41b57edfe3
|
@ -365,13 +365,13 @@ func torrentManyAction(r *http.Request) {
|
|||
messages := msg.GetMessages(r) // new util for errors and infos
|
||||
|
||||
if action == "" {
|
||||
messages.AddError(r, "errors", "You have to tell what you want to do with your selection!")
|
||||
messages.AddError("errors", "You have to tell what you want to do with your selection!")
|
||||
}
|
||||
if action == "move" && r.FormValue("moveto") == "" { // We need to check the form value, not the int one because hidden is 0
|
||||
messages.AddError(r, "errors", "Thou has't to telleth whither thee wanteth to moveth thy selection!")
|
||||
messages.AddError("errors", "Thou has't to telleth whither thee wanteth to moveth thy selection!")
|
||||
}
|
||||
if len(torrentsSelected) == 0 {
|
||||
messages.AddError(r, "errors", "You need to select at least 1 element!")
|
||||
messages.AddError("errors", "You need to select at least 1 element!")
|
||||
}
|
||||
if !messages.HasErrors() {
|
||||
for _, torrent_id := range torrentsSelected {
|
||||
|
@ -382,22 +382,22 @@ func torrentManyAction(r *http.Request) {
|
|||
if config.TorrentStatus[moveTo] {
|
||||
torrent.Status = moveTo
|
||||
db.ORM.Save(&torrent)
|
||||
messages.AddInfof(r, "infos", "Torrent %s moved!", torrent.Name)
|
||||
messages.AddInfof("infos", "Torrent %s moved!", torrent.Name)
|
||||
} else {
|
||||
messages.AddErrorf(r, "errors", "No such status %d exist!", moveTo)
|
||||
messages.AddErrorf("errors", "No such status %d exist!", moveTo)
|
||||
}
|
||||
case "delete":
|
||||
_, err := torrentService.DeleteTorrent(torrent_id)
|
||||
if err != nil {
|
||||
messages.ImportFromError(r, "errors", err)
|
||||
messages.ImportFromError("errors", err)
|
||||
} else {
|
||||
messages.AddInfof(r, "infos", "Torrent %s deleted!", torrent.Name)
|
||||
messages.AddInfof("infos", "Torrent %s deleted!", torrent.Name)
|
||||
}
|
||||
default:
|
||||
messages.AddErrorf(r, "errors", "No such action %s exist!", action)
|
||||
messages.AddErrorf("errors", "No such action %s exist!", action)
|
||||
}
|
||||
} else {
|
||||
messages.AddErrorf(r, "errors", "Torrent with ID %s doesn't exist!", torrent_id)
|
||||
messages.AddErrorf("errors", "Torrent with ID %s doesn't exist!", torrent_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ type NotFoundTemplateVariables struct {
|
|||
type ViewTemplateVariables struct {
|
||||
Torrent model.TorrentJSON
|
||||
CaptchaID string
|
||||
FormErrors map[string][]string
|
||||
Infos map[string][]string
|
||||
Search SearchForm
|
||||
Navigation Navigation
|
||||
User *model.User
|
||||
|
@ -116,6 +118,7 @@ type DatabaseDumpTemplateVariables struct {
|
|||
|
||||
type UploadTemplateVariables struct {
|
||||
Upload UploadForm
|
||||
FormErrors map[string][]string
|
||||
Search SearchForm
|
||||
Navigation Navigation
|
||||
User *model.User
|
||||
|
|
|
@ -40,6 +40,7 @@ type UploadForm struct {
|
|||
Description string
|
||||
Status int
|
||||
CaptchaID string
|
||||
WebsiteLink string
|
||||
|
||||
Infohash string
|
||||
CategoryID int
|
||||
|
@ -58,25 +59,29 @@ const UploadFormMagnet = "magnet"
|
|||
const UploadFormCategory = "c"
|
||||
const UploadFormRemake = "remake"
|
||||
const UploadFormDescription = "desc"
|
||||
const UploadFormWebsiteLink = "website_link"
|
||||
const UploadFormStatus = "status"
|
||||
|
||||
// error indicating that you can't send both a magnet link and torrent
|
||||
var ErrTorrentPlusMagnet = errors.New("upload either a torrent file or magnet link, not both")
|
||||
var ErrTorrentPlusMagnet = errors.New("Upload either a torrent file or magnet link, not both")
|
||||
|
||||
// error indicating a torrent is private
|
||||
var ErrPrivateTorrent = errors.New("torrent is private")
|
||||
var ErrPrivateTorrent = errors.New("Torrent is private")
|
||||
|
||||
// error indicating a problem with its trackers
|
||||
var ErrTrackerProblem = errors.New("torrent does not have any (working) trackers: https://" + config.WebAddress + "/faq#trackers")
|
||||
var ErrTrackerProblem = errors.New("Torrent does not have any (working) trackers: https://" + config.WebAddress + "/faq#trackers")
|
||||
|
||||
// error indicating a torrent's name is invalid
|
||||
var ErrInvalidTorrentName = errors.New("torrent name is invalid")
|
||||
var ErrInvalidTorrentName = errors.New("Torrent name is invalid")
|
||||
|
||||
// error indicating a torrent's description is invalid
|
||||
var ErrInvalidTorrentDescription = errors.New("torrent description is invalid")
|
||||
var ErrInvalidTorrentDescription = errors.New("Torrent description is invalid")
|
||||
|
||||
// error indicating a torrent's description is invalid
|
||||
var ErrInvalidWebsiteLink = errors.New("Website url or IRC link is invalid")
|
||||
|
||||
// error indicating a torrent's category is invalid
|
||||
var ErrInvalidTorrentCategory = errors.New("torrent category is invalid")
|
||||
var ErrInvalidTorrentCategory = errors.New("Torrent category is invalid")
|
||||
|
||||
var p = bluemonday.UGCPolicy()
|
||||
|
||||
|
@ -88,6 +93,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
f.Name = r.FormValue(UploadFormName)
|
||||
f.Category = r.FormValue(UploadFormCategory)
|
||||
f.Description = r.FormValue(UploadFormDescription)
|
||||
f.WebsiteLink = r.FormValue(UploadFormWebsiteLink)
|
||||
f.Status, _ = strconv.Atoi(r.FormValue(UploadFormStatus))
|
||||
f.Magnet = r.FormValue(UploadFormMagnet)
|
||||
f.Remake = r.FormValue(UploadFormRemake) == "on"
|
||||
|
@ -95,6 +101,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
// trim whitespace
|
||||
f.Name = util.TrimWhitespaces(f.Name)
|
||||
f.Description = p.Sanitize(util.TrimWhitespaces(f.Description))
|
||||
f.WebsiteLink = util.TrimWhitespaces(f.WebsiteLink)
|
||||
f.Magnet = util.TrimWhitespaces(f.Magnet)
|
||||
cache.Impl.ClearAll()
|
||||
|
||||
|
@ -116,6 +123,12 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
return ErrInvalidTorrentCategory
|
||||
}
|
||||
|
||||
// WebsiteLink
|
||||
urlRegexp, _ := regexp.Compile(`^(https?:\/\/|irc:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$`)
|
||||
if !urlRegexp.MatchString(f.WebsiteLink) {
|
||||
return ErrInvalidWebsiteLink
|
||||
}
|
||||
|
||||
// first: parse torrent file (if any) to fill missing information
|
||||
tfile, _, err := r.FormFile(UploadFormTorrent)
|
||||
if err == nil {
|
||||
|
@ -175,7 +188,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
}
|
||||
xt := magnetUrl.Query().Get("xt")
|
||||
if !strings.HasPrefix(xt, "urn:btih:") {
|
||||
return errors.New("incorrect magnet")
|
||||
return errors.New("Incorrect magnet")
|
||||
}
|
||||
xt = strings.SplitAfter(xt, ":")[2]
|
||||
f.Infohash = strings.ToUpper(strings.Split(xt, "&")[0])
|
||||
|
@ -189,7 +202,7 @@ func (f *UploadForm) ExtractInfo(r *http.Request) error {
|
|||
return err
|
||||
}
|
||||
if !isBase16 {
|
||||
return errors.New("incorrect hash")
|
||||
return errors.New("Incorrect hash")
|
||||
}
|
||||
} else {
|
||||
//convert to base16
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
@ -12,6 +11,7 @@ import (
|
|||
"github.com/NyaaPantsu/nyaa/service/upload"
|
||||
"github.com/NyaaPantsu/nyaa/service/user/permission"
|
||||
"github.com/NyaaPantsu/nyaa/util/languages"
|
||||
msg "github.com/NyaaPantsu/nyaa/util/messages"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
|
@ -24,31 +24,28 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
if r.Method == "POST" {
|
||||
UploadPostHandler(w, r)
|
||||
} else if r.Method == "GET" {
|
||||
UploadGetHandler(w, r)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
UploadGetHandler(w, r)
|
||||
}
|
||||
|
||||
func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var uploadForm UploadForm
|
||||
defer r.Body.Close()
|
||||
user := GetUser(r)
|
||||
messages := msg.GetMessages(r) // new util for errors and infos
|
||||
|
||||
if userPermission.NeedsCaptcha(user) {
|
||||
userCaptcha := captcha.Extract(r)
|
||||
if !captcha.Authenticate(userCaptcha) {
|
||||
http.Error(w, captcha.ErrInvalidCaptcha.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
messages.AddError("errors", captcha.ErrInvalidCaptcha.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// validation is done in ExtractInfo()
|
||||
err := uploadForm.ExtractInfo(r)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
messages.AddError("errors", err.Error())
|
||||
}
|
||||
status := model.TorrentStatusNormal
|
||||
if uploadForm.Remake { // overrides trusted
|
||||
|
@ -59,7 +56,11 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
var sameTorrents int
|
||||
db.ORM.Model(&model.Torrent{}).Where("torrent_hash = ?", uploadForm.Infohash).Count(&sameTorrents)
|
||||
if sameTorrents == 0 {
|
||||
if sameTorrents > 0 {
|
||||
messages.AddError("errors", "Torrent already in database !")
|
||||
}
|
||||
|
||||
if !messages.HasErrors() {
|
||||
// add to db and redirect
|
||||
torrent := model.Torrent{
|
||||
Name: uploadForm.Name,
|
||||
|
@ -70,6 +71,7 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||
Date: time.Now(),
|
||||
Filesize: uploadForm.Filesize,
|
||||
Description: uploadForm.Description,
|
||||
WebsiteLink: uploadForm.WebsiteLink,
|
||||
UploaderID: user.ID}
|
||||
db.ORM.Create(&torrent)
|
||||
|
||||
|
@ -79,8 +81,7 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||
file := model.File{TorrentID: torrent.ID, Filesize: uploadedFile.Filesize}
|
||||
err := file.SetPath(uploadedFile.Path)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
messages.AddError("errors", err.Error())
|
||||
}
|
||||
db.ORM.Create(&file)
|
||||
}
|
||||
|
@ -91,18 +92,16 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) {
|
|||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, url.String(), 302)
|
||||
} else {
|
||||
err = fmt.Errorf("Torrent already in database!")
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
http.Redirect(w, r, url.String()+"?success", 302)
|
||||
}
|
||||
}
|
||||
|
||||
func UploadGetHandler(w http.ResponseWriter, r *http.Request) {
|
||||
languages.SetTranslationFromRequest(uploadTemplate, r)
|
||||
messages := msg.GetMessages(r) // new util for errors and infos
|
||||
|
||||
var uploadForm UploadForm
|
||||
_ = uploadForm.ExtractInfo(r)
|
||||
user := GetUser(r)
|
||||
if userPermission.NeedsCaptcha(user) {
|
||||
uploadForm.CaptchaID = captcha.GetID()
|
||||
|
@ -112,6 +111,7 @@ func UploadGetHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
utv := UploadTemplateVariables{
|
||||
Upload: uploadForm,
|
||||
FormErrors: messages.GetAllErrors(),
|
||||
Search: NewSearchForm(),
|
||||
Navigation: NewNavigation(),
|
||||
User: GetUser(r),
|
||||
|
|
|
@ -14,12 +14,18 @@ import (
|
|||
"github.com/NyaaPantsu/nyaa/util"
|
||||
"github.com/NyaaPantsu/nyaa/util/languages"
|
||||
"github.com/NyaaPantsu/nyaa/util/log"
|
||||
msg "github.com/NyaaPantsu/nyaa/util/messages"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func ViewHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
id := vars["id"]
|
||||
messages := msg.GetMessages(r)
|
||||
|
||||
if (r.URL.Query()["success"] != nil) {
|
||||
messages.AddInfo("infos", "Torrent uploaded successfully!")
|
||||
}
|
||||
|
||||
torrent, err := torrentService.GetTorrentById(id)
|
||||
if err != nil {
|
||||
|
@ -32,7 +38,7 @@ func ViewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
if userPermission.NeedsCaptcha(user) {
|
||||
captchaID = captcha.GetID()
|
||||
}
|
||||
htv := ViewTemplateVariables{b, captchaID, NewSearchForm(), NewNavigation(), user, r.URL, mux.CurrentRoute(r)}
|
||||
htv := ViewTemplateVariables{b, captchaID, messages.GetAllErrors(), messages.GetAllInfos(), NewSearchForm(), NewNavigation(), user, r.URL, mux.CurrentRoute(r)}
|
||||
|
||||
languages.SetTranslationFromRequest(viewTemplate, r)
|
||||
err = viewTemplate.ExecuteTemplate(w, "index.html", htv)
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
{{with .Upload}}
|
||||
<hr>
|
||||
<form enctype="multipart/form-data" role="upload" method="POST">
|
||||
|
||||
{{ range (index $.FormErrors "errors")}}
|
||||
<div class="alert alert-danger"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-exclamation-sign"></i> {{ . }}</div>
|
||||
{{end}}
|
||||
<div class="form-group">
|
||||
<label for="name">{{T "name"}}</label>
|
||||
<input type="text" name="name" id="name" class="form-control" placeholder="{{T "file_name"}}" value="{{.Name}}" autofocus required>
|
||||
|
@ -69,7 +71,11 @@
|
|||
<div class="form-group">
|
||||
<label for="desc">{{T "torrent_description"}}</label>
|
||||
<p class="help-block">{{T "description_markdown_notice"}}</p>
|
||||
<textarea name="desc" id="desc" class="form-contro torrent-desc" rows="15">{{.Description}}</textarea>
|
||||
<textarea name="desc" id="desc" class="form-control torrent-desc" rows="15">{{.Description}}</textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="website_link">{{T "website_link"}}</label>
|
||||
<input name="website_link" id="website_link" class="form-control" type="text" value="{{.WebsiteLink}}">
|
||||
</div>
|
||||
|
||||
{{block "captcha" .}}{{end}}
|
||||
|
|
|
@ -4,6 +4,12 @@
|
|||
<div class="blockBody">
|
||||
{{with .Torrent}}
|
||||
<hr>
|
||||
{{ range (index $.FormErrors "errors")}}
|
||||
<div class="alert alert-danger"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-exclamation-sign"></i> {{ . }}</div>
|
||||
{{end}}
|
||||
{{ range (index $.Infos "infos")}}
|
||||
<div class="alert alert-danger"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-exclamation-sign"></i> {{ . }}</div>
|
||||
{{end}}
|
||||
<div class="content" style="margin-bottom: 2em;">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
|
|
@ -10,6 +10,7 @@ const MessagesKey = "messages"
|
|||
type Messages struct {
|
||||
Errors map[string][]string
|
||||
Infos map[string][]string
|
||||
r *http.Request
|
||||
}
|
||||
|
||||
func GetMessages(r *http.Request) Messages {
|
||||
|
@ -17,64 +18,65 @@ func GetMessages(r *http.Request) Messages {
|
|||
return rv.(Messages)
|
||||
} else {
|
||||
context.Set(r, MessagesKey, Messages{})
|
||||
return Messages{make(map[string][]string),make(map[string][]string)}
|
||||
return Messages{make(map[string][]string),make(map[string][]string), r}
|
||||
}
|
||||
}
|
||||
|
||||
func (mes Messages) AddError(r *http.Request, name string, msg string) {
|
||||
func (mes Messages) AddError(name string, msg string) {
|
||||
mes.Errors[name] = append(mes.Errors[name], msg)
|
||||
mes.setMessagesInContext(r)
|
||||
mes.setMessagesInContext()
|
||||
}
|
||||
func (mes Messages) AddErrorf( name string, msg string, args ...interface{}) {
|
||||
mes.AddError(name, fmt.Sprintf(msg, args...))
|
||||
}
|
||||
func (mes Messages) ImportFromError(name string, err error) {
|
||||
mes.AddError(name, err.Error())
|
||||
}
|
||||
|
||||
func (mes Messages) ImportFromError(r *http.Request, name string, err error) {
|
||||
mes.AddError(r, name, err.Error())
|
||||
}
|
||||
|
||||
func (mes Messages) AddInfo(r *http.Request, name string, msg string) {
|
||||
func (mes Messages) AddInfo(name string, msg string) {
|
||||
mes.Infos[name] = append(mes.Infos[name], msg)
|
||||
mes.setMessagesInContext(r)
|
||||
mes.setMessagesInContext()
|
||||
}
|
||||
func (mes Messages) AddInfof(name string, msg string, args ...interface{}) {
|
||||
mes.AddInfo(name, fmt.Sprintf(msg, args...))
|
||||
}
|
||||
|
||||
func (mes Messages) AddErrorf(r *http.Request, name string, msg string, args ...interface{}) {
|
||||
mes.Errors[name] = append(mes.Errors[name], fmt.Sprintf(msg, args...))
|
||||
mes.setMessagesInContext(r)
|
||||
}
|
||||
|
||||
func (mes Messages) AddInfof(r *http.Request, name string, msg string, args ...interface{}) {
|
||||
mes.Infos[name] = append(mes.Infos[name], fmt.Sprintf(msg, args...))
|
||||
mes.setMessagesInContext(r)
|
||||
}
|
||||
|
||||
func (mes Messages) ClearInfos(r *http.Request) {
|
||||
mes.Errors = nil
|
||||
mes.setMessagesInContext(r)
|
||||
}
|
||||
|
||||
func (mes Messages) ClearErrors(r *http.Request) {
|
||||
func (mes Messages) ClearErrors() {
|
||||
mes.Infos = nil
|
||||
mes.setMessagesInContext(r)
|
||||
mes.setMessagesInContext()
|
||||
}
|
||||
func (mes Messages) ClearInfos() {
|
||||
mes.Errors = nil
|
||||
mes.setMessagesInContext()
|
||||
}
|
||||
|
||||
func (mes Messages) GetInfos(name string) []string {
|
||||
return mes.Infos[name]
|
||||
}
|
||||
func (mes Messages) GetErrors(name string) []string {
|
||||
return mes.Errors[name]
|
||||
}
|
||||
func (mes Messages) GetAllInfos() map[string][]string {
|
||||
return mes.Infos
|
||||
}
|
||||
func (mes Messages) GetAllErrors() map[string][]string {
|
||||
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
|
||||
return mes.Errors
|
||||
}
|
||||
func (mes Messages) GetErrors(name string) []string {
|
||||
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
|
||||
return mes.Errors[name]
|
||||
}
|
||||
|
||||
func (mes Messages) setMessagesInContext(r *http.Request) {
|
||||
context.Set(r, MessagesKey, mes)
|
||||
func (mes Messages) GetAllInfos() map[string][]string {
|
||||
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
|
||||
return mes.Infos
|
||||
}
|
||||
func (mes Messages) GetInfos(name string) []string {
|
||||
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
|
||||
return mes.Infos[name]
|
||||
}
|
||||
|
||||
func (mes Messages) HasErrors() bool {
|
||||
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
|
||||
return len(mes.Errors) > 0
|
||||
}
|
||||
func (mes Messages) HasInfos() bool {
|
||||
mes = GetMessages(mes.r) // We need to look if any new errors from other functions has updated context
|
||||
return len(mes.Infos) > 0
|
||||
}
|
||||
|
||||
func (mes Messages) setMessagesInContext() {
|
||||
context.Set(mes.r, MessagesKey, mes)
|
||||
}
|
Référencer dans un nouveau ticket