Possibility to add tags from edit panel + upload
Cette révision appartient à :
Parent
bd959764f3
révision
0db143d685
21 fichiers modifiés avec 417 ajouts et 34 suppressions
|
@ -358,6 +358,7 @@ func APIUpdateHandler(c *gin.Context) {
|
|||
if !messages.HasErrors() {
|
||||
c.Bind(&update)
|
||||
torrent, err := torrents.FindByID(update.ID)
|
||||
torrent.LoadTags()
|
||||
if err != nil {
|
||||
messages.AddErrorTf("errors", "torrent_not_exist", strconv.Itoa(int(update.ID)))
|
||||
}
|
||||
|
|
|
@ -70,6 +70,7 @@ func TorrentsListPanel(c *gin.Context) {
|
|||
func TorrentEditModPanel(c *gin.Context) {
|
||||
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
|
||||
torrent, _ := torrents.FindUnscopeByID(uint(id))
|
||||
torrent.LoadTags()
|
||||
|
||||
torrentJSON := torrent.ToJSON()
|
||||
uploadForm := upload.NewTorrentRequest()
|
||||
|
@ -80,6 +81,7 @@ func TorrentEditModPanel(c *gin.Context) {
|
|||
uploadForm.WebsiteLink = string(torrentJSON.WebsiteLink)
|
||||
uploadForm.Description = string(torrentJSON.Description)
|
||||
uploadForm.Languages = torrent.Languages
|
||||
uploadForm.Tags = torrent.Tags.ToJSON(true)
|
||||
|
||||
templates.Form(c, "admin/paneltorrentedit.jet.html", uploadForm)
|
||||
}
|
||||
|
@ -90,6 +92,7 @@ func TorrentPostEditModPanel(c *gin.Context) {
|
|||
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
|
||||
messages := msg.GetMessages(c)
|
||||
torrent, _ := torrents.FindUnscopeByID(uint(id))
|
||||
torrent.LoadTags()
|
||||
currentUser := router.GetUser(c)
|
||||
if torrent.ID > 0 {
|
||||
errUp := upload.ExtractEditInfo(c, &uploadForm.Update)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package torrentController
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"fmt"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/controllers/router"
|
||||
"github.com/NyaaPantsu/nyaa/models"
|
||||
|
@ -19,8 +19,9 @@ import (
|
|||
func TorrentEditUserPanel(c *gin.Context) {
|
||||
id, _ := strconv.ParseInt(c.Query("id"), 10, 32)
|
||||
torrent, _ := torrents.FindByID(uint(id))
|
||||
torrent.LoadTags()
|
||||
currentUser := router.GetUser(c)
|
||||
if currentUser.CurrentOrAdmin(torrent.UploaderID) && torrent.ID > 0 {
|
||||
if currentUser.CurrentOrAdmin(torrent.UploaderID) && torrent.ID > 0 {
|
||||
uploadForm := torrentValidator.TorrentRequest{}
|
||||
uploadForm.Name = torrent.Name
|
||||
uploadForm.Category = strconv.Itoa(torrent.Category) + "_" + strconv.Itoa(torrent.SubCategory)
|
||||
|
@ -29,6 +30,7 @@ func TorrentEditUserPanel(c *gin.Context) {
|
|||
uploadForm.Description = string(torrent.Description)
|
||||
uploadForm.Hidden = torrent.Hidden
|
||||
uploadForm.Languages = torrent.Languages
|
||||
uploadForm.Tags = torrent.Tags.ToJSON(true)
|
||||
templates.Form(c, "site/torrents/edit.jet.html", uploadForm)
|
||||
} else {
|
||||
c.AbortWithStatus(http.StatusNotFound)
|
||||
|
@ -42,6 +44,7 @@ func TorrentPostEditUserPanel(c *gin.Context) {
|
|||
uploadForm.ID = uint(id)
|
||||
messages := msg.GetMessages(c)
|
||||
torrent, _ := torrents.FindByID(uint(id))
|
||||
torrent.LoadTags()
|
||||
currentUser := router.GetUser(c)
|
||||
if torrent.ID > 0 && currentUser.CurrentOrAdmin(torrent.UploaderID) {
|
||||
errUp := upload.ExtractEditInfo(c, &uploadForm.Update)
|
||||
|
|
|
@ -40,7 +40,7 @@ func postTag(c *gin.Context, torrent *models.Torrent, user *models.User) *models
|
|||
}
|
||||
|
||||
tag, _ := tags.Create(tagForm.Tag, tagForm.Type, torrent, user) // Add a tag to the db
|
||||
tags.Filter(tagForm.Tag, tagForm.Type, torrent.ID) // Check if we have a tag reaching the maximum weight, if yes, deletes every tag and add only the one accepted
|
||||
tags.Filter(tagForm.Tag, tagForm.Type, torrent) // Check if we have a tag reaching the maximum weight, if yes, deletes every tag and add only the one accepted
|
||||
return tag
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/utils/log"
|
||||
"github.com/fatih/structs"
|
||||
)
|
||||
|
||||
|
@ -52,6 +54,28 @@ func (ts Tags) Contains(tag Tag) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// HasType check if the tag map has the same tag type in it and returns its index
|
||||
func (ts Tags) HasType(tagtype string) int {
|
||||
for i, ta := range ts {
|
||||
if ta.Type == tagtype {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// DeleteType remove all tags from the map that have the same tag type in it
|
||||
func (ts *Tags) DeleteType(tagtype string) {
|
||||
var newTs Tags
|
||||
for _, ta := range *ts {
|
||||
if ta.Type == tagtype {
|
||||
continue
|
||||
}
|
||||
newTs = append(newTs, ta)
|
||||
}
|
||||
ts = &newTs
|
||||
}
|
||||
|
||||
// HasAccepted check if a tag has been accepted in the tags map
|
||||
func (ts Tags) HasAccepted() bool {
|
||||
for _, tag := range ts {
|
||||
|
@ -61,3 +85,32 @@ func (ts Tags) HasAccepted() bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Replace a tag in map of tags
|
||||
func (ts Tags) Replace(index int, tag *Tag) {
|
||||
if index >= 0 && index < len(ts) {
|
||||
ts[index].Delete()
|
||||
ts[index] = *tag
|
||||
ts[index].Update()
|
||||
}
|
||||
}
|
||||
|
||||
// ToJSON convert tags map to a json map and can exclud non accepted tags
|
||||
func (ts Tags) ToJSON(onlyAccepted bool) string {
|
||||
var toParse Tags
|
||||
if onlyAccepted {
|
||||
for _, tag := range ts {
|
||||
if tag.Accepted {
|
||||
toParse = append(toParse, tag)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
toParse = ts
|
||||
}
|
||||
b, err := json.Marshal(toParse)
|
||||
if err != nil {
|
||||
log.Infof("Couldn't parse to json the tags %v", toParse)
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Create a new tag based on string inputs
|
||||
func Create(tag string, tagType string, torrent *models.Torrent, user *models.User) (*models.Tag, error) {
|
||||
newTag := &models.Tag{
|
||||
Tag: tag,
|
||||
|
@ -15,13 +16,17 @@ func Create(tag string, tagType string, torrent *models.Torrent, user *models.Us
|
|||
Weight: user.Pantsu,
|
||||
Accepted: false,
|
||||
}
|
||||
return New(newTag, torrent)
|
||||
}
|
||||
|
||||
// New is the low level functions that actually create a tag in db
|
||||
func New(tag *models.Tag, torrent *models.Torrent) (*models.Tag, error) {
|
||||
if torrent.ID == 0 {
|
||||
return newTag, errors.New("Can't add a tag to no torrents")
|
||||
return tag, errors.New("Can't add a tag to no torrents")
|
||||
}
|
||||
if err := models.ORM.Create(newTag).Error; err != nil {
|
||||
return newTag, err
|
||||
if err := models.ORM.Create(tag).Error; err != nil {
|
||||
return tag, err
|
||||
}
|
||||
cache.C.Delete(torrent.Identifier())
|
||||
return newTag, nil
|
||||
return tag, nil
|
||||
}
|
||||
|
|
|
@ -3,8 +3,6 @@ package tags
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/models/torrents"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/models"
|
||||
"github.com/NyaaPantsu/nyaa/models/users"
|
||||
|
@ -12,15 +10,15 @@ import (
|
|||
)
|
||||
|
||||
// Filter check if a tag type has reached the maximal votes and removes the other tag of the same type
|
||||
func Filter(tag string, tagType string, torrentID uint) bool {
|
||||
if torrentID == 0 || tagType == "" || tag == "" {
|
||||
func Filter(tag string, tagType string, torrent *models.Torrent) bool {
|
||||
if torrent.ID == 0 || tagType == "" || tag == "" {
|
||||
return false
|
||||
}
|
||||
tagSum := models.Tag{}
|
||||
if err := models.ORM.Select("torrent_id, tag, type, accepted, SUM(weight) as total").Where("torrent_id = ? AND tag = ? AND type = ?", torrentID, tag, tagType).Group("type, tag").Find(&tagSum).Error; err == nil {
|
||||
if err := models.ORM.Select("torrent_id, tag, type, accepted, SUM(weight) as total").Where("torrent_id = ? AND tag = ? AND type = ?", torrent.ID, tag, tagType).Group("type, tag").Find(&tagSum).Error; err == nil {
|
||||
fmt.Println(tagSum)
|
||||
if tagSum.Total > config.Get().Torrents.Tags.MaxWeight {
|
||||
tags, err := FindAll(tagType, torrentID)
|
||||
tags, err := FindAll(tagType, torrent.ID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
@ -39,28 +37,25 @@ func Filter(tag string, tagType string, torrentID uint) bool {
|
|||
}
|
||||
toDelete.Delete()
|
||||
}
|
||||
/* err := DeleteAllType(tagType, torrentID) // We can also delete them in batch
|
||||
/* err := DeleteAllType(tagType, torrent.ID) // We can also delete them in batch
|
||||
log.CheckError(err) */
|
||||
tagSum.Accepted = true
|
||||
tagSum.UserID = 0 // System ID
|
||||
tagSum.Weight = config.Get().Torrents.Tags.MaxWeight // Overriden to the maximal value
|
||||
models.ORM.Save(&tagSum) // We only add back the tag accepted
|
||||
callbackOnType(&tagSum)
|
||||
callbackOnType(&tagSum, torrent)
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func callbackOnType(tag *models.Tag) {
|
||||
func callbackOnType(tag *models.Tag, torrent *models.Torrent) {
|
||||
switch tag.Type {
|
||||
case "anidbid", "vndbid":
|
||||
if tag.Accepted && tag.TorrentID > 0 {
|
||||
torrent, err := torrents.FindByID(tag.TorrentID)
|
||||
if err == nil {
|
||||
torrent.DbID = tag.Tag
|
||||
torrent.Update(false)
|
||||
}
|
||||
if tag.Accepted && tag.TorrentID > 0 && torrent.ID > 0 {
|
||||
torrent.DbID = tag.Tag
|
||||
torrent.Update(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
package torrents
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/models/tag"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/models"
|
||||
"github.com/NyaaPantsu/nyaa/utils/log"
|
||||
"github.com/NyaaPantsu/nyaa/utils/validator/torrent"
|
||||
)
|
||||
|
||||
// Create a new torrent based on the uploadform request struct
|
||||
func Create(user *models.User, uploadForm *torrentValidator.TorrentRequest) (*models.Torrent, error) {
|
||||
torrent := models.Torrent{
|
||||
Name: uploadForm.Name,
|
||||
|
@ -51,5 +55,17 @@ func Create(user *models.User, uploadForm *torrentValidator.TorrentRequest) (*mo
|
|||
models.ORM.Create(&file)
|
||||
}
|
||||
}
|
||||
|
||||
var tagsReq models.Tags
|
||||
json.Unmarshal([]byte(uploadForm.Tags), &tagsReq)
|
||||
for _, tag := range tagsReq {
|
||||
tag.Accepted = true
|
||||
tag.TorrentID = torrent.ID
|
||||
tag.Weight = config.Get().Torrents.Tags.MaxWeight
|
||||
tags.New(&tag, &torrent) // We create new tags
|
||||
torrent.Tags = append(torrent.Tags) // Finally we append it to the torrent
|
||||
}
|
||||
user.IncreasePantsu()
|
||||
|
||||
return &torrent, nil
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ var Modal = {
|
|||
// Get the button that opens the modal
|
||||
if (!btn) {
|
||||
btn = document.getElementById("modal_btn_" + modal.id)
|
||||
} else if (btn instanceof String && btn.match(/^#/)) {
|
||||
} else if (typeof(btn) == "string" && btn.match(/^#/)) {
|
||||
btn = document.getElementById(btn.substr(1));
|
||||
} else if (btn instanceof String && btn.match(/^\./)) {
|
||||
} else if (typeof(btn) == "string" && btn.match(/^\./)) {
|
||||
btn = document.getElementsByClassName(btn.substr(1));
|
||||
isBtnArray = true;
|
||||
} else if (btn instanceof Array) {
|
||||
|
|
|
@ -48,11 +48,77 @@
|
|||
<p class="help-block">{{ T("description_markdown_notice")}}</p>
|
||||
<textarea name="desc" id="desc" class="form-input up-input" rows="10">{{Form.Description}}</textarea>
|
||||
</div>
|
||||
<h3>{{ T("torrent_tags")}}</h3>
|
||||
<span id="tags_list"></span>
|
||||
<a id="tagPopup" href="#" class="add-tag">{{ T("add") }}</a>
|
||||
<input type="hidden" name="tags" id="tags" value="{{ Form.Tags }}">
|
||||
{{ yield errors(name="tags")}}
|
||||
<button type="submit" class="form-input up-input btn-green">{{ T("save_changes")}}</button>
|
||||
</form>
|
||||
</div>
|
||||
{{end}} {{ block footer_js()}}
|
||||
{{ include "layouts/partials/modal_tags" }}
|
||||
{{end}}
|
||||
{{ block footer_js()}}
|
||||
<script type="text/javascript" src="/js/translation.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/template.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/modal.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/simplemde.min.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript">
|
||||
// {{ range _, type := Config.Torrents.Tags.Types }}
|
||||
T.Add("tagtype_{{ type }}", '{{ T("tagtype_" + type) }}')
|
||||
// {{ end }}
|
||||
|
||||
Templates.Add("tag", function(tag) {
|
||||
return `<span data-name="` + tag.type + `_` + tag.tag + `" class="tag accepted" title="Tag: ` + tag.type + `({{ T("accepted") }} )">
|
||||
<span class="tag-text votable">
|
||||
` + T.r("tagtype_" + tag.type) + `: ` + tag.tag + `
|
||||
</span>
|
||||
</span>`
|
||||
})
|
||||
|
||||
// Modal initialization
|
||||
Modal.Init({
|
||||
elements: document.getElementsByClassName("modal"),
|
||||
// order of apparition of the modals
|
||||
button: "#tagPopup"
|
||||
});
|
||||
var tags = []
|
||||
document.querySelector("#modal_tag_form form").addEventListener("submit", function(e) {
|
||||
var form = e.target
|
||||
var newTag = {type: form.querySelector("select#type").value, tag: form.querySelector("input#tag").value}
|
||||
|
||||
var replaced = false
|
||||
var len = tags.length
|
||||
for(var i = 0; i < len; i++) {
|
||||
if (tags[i].type == newTag.type) {
|
||||
var oldTag = document.querySelector("span[data-name='"+ tags[i].type + "_" + tags[i].tag + "']")
|
||||
oldTag.parentElement.removeChild(oldTag)
|
||||
tags[i] = newTag
|
||||
replaced = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!replaced) tags.push(newTag)
|
||||
var tagHTml = Templates.Render("tag", newTag)
|
||||
document.getElementById("tags_list").innerHTML += tagHTml
|
||||
document.getElementById("tags").value = JSON.stringify(tags)
|
||||
Modal.CloseActive()
|
||||
e.preventDefault()
|
||||
})
|
||||
function renderTagsJSON() {
|
||||
tagsIn = document.getElementById("tags").value
|
||||
if (tagsIn == "") return
|
||||
var jsonFromTags = JSON.parse(tagsIn)
|
||||
if (jsonFromTags instanceof Array) {
|
||||
for (var i = 0; i < jsonFromTags.length; i++) {
|
||||
tags.push(jsonFromTags[i])
|
||||
var tagHTml = Templates.Render("tag", jsonFromTags[i])
|
||||
document.getElementById("tags_list").innerHTML += tagHTml
|
||||
}
|
||||
}
|
||||
}
|
||||
renderTagsJSON()
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
new SimpleMDE({
|
||||
element: document.getElementById("desc"),
|
||||
|
|
36
templates/layouts/partials/modal_tags.jet.html
Fichier normal
36
templates/layouts/partials/modal_tags.jet.html
Fichier normal
|
@ -0,0 +1,36 @@
|
|||
<!-- Modal to add a tag -->
|
||||
<div id="modal_tag_form" class="modal">
|
||||
<!-- Modal content -->
|
||||
<div class="modal-content">
|
||||
<form method="post" action="#">
|
||||
<div class="modal-header">
|
||||
<span class="close">×</span>
|
||||
<h2>{{ T("add_tag") }}</h2>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h4>{{ T("add_tag") }}</h4>
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="tag">{{ T("tag")}}</label>
|
||||
<input type="text" id="tag" name="tag" class="form-input up-input" value="" required/>
|
||||
{{ yield errors(name="Tag")}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="input-label" for="type">{{ T("tagtype")}}</label>
|
||||
<select name="type" id="type" class="form-input up-input">
|
||||
{{ range _, type := Config.Torrents.Tags.Types }}
|
||||
<option value="{{ type }}">{{T("tagtype_" + type) }}</option>
|
||||
{{ end }}
|
||||
</select>
|
||||
{{ yield errors(name="Type")}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<span>
|
||||
<button id="confirm_changes" type="submit">{{ T("add")}}</button>
|
||||
<button class="close" onclick="Modal.CloseActive();">{{ T("close")}}</button>
|
||||
</span>
|
||||
<h3>{{ T("are_you_sure") }} </h3>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
|
@ -29,8 +29,8 @@ Templates.Add("torrents.item", function(torrent) {
|
|||
// {{end}}
|
||||
var languages = ""
|
||||
var colspan = (torrent.comments.length == 0 ? ` colspan="2"` : "" )
|
||||
var commentTd = ((torrent.comments.length > 0) ? '<td class="tr-cs home-td"><span>' + torrent.comments.length + '</span></td>' : "")
|
||||
var dlLink = (torrent.torrent != "" ? ' <a href="` + torrent.torrent + `" title="{{ T("torrent_file") }}"><div class="icon-floppy"></div></a>' : "")
|
||||
var commentTd = ((torrent.comments.length > 0) ? `<td class="tr-cs home-td"><span>` + torrent.comments.length + `</span></td>` : "")
|
||||
var dlLink = (torrent.torrent != "" ? ` <a href="` + torrent.torrent + `" title="{{ T("torrent_file") }}"><div class="icon-floppy"></div></a>` : "")
|
||||
|
||||
if (torrent.languages[0] != "") {
|
||||
var flagClass = (torrent.languages.length == 1) ? Templates.FlagCode(torrent.languages[0]) : "multiple"
|
||||
|
@ -56,7 +56,7 @@ Templates.Add("torrents.item", function(torrent) {
|
|||
<a href="` + torrent.magnet + `" title="{{ T("magnet_link") }}">
|
||||
<div class="icon-magnet"></div>
|
||||
</a>`+ dlLink +`
|
||||
</td>"+
|
||||
</td>
|
||||
<td class="tr-size home-td hide-xs">` + humanFileSize(torrent.filesize) + `</td>
|
||||
<td class="tr-se home-td hide-smol">` + torrent.seeders + `</td>
|
||||
<td class="tr-le home-td hide-smol">` + torrent.leechers + `</td>
|
||||
|
|
|
@ -47,7 +47,7 @@ Templates.Add("torrents.item", function(torrent) {
|
|||
<a title="{{ T("magnet_link") }}">
|
||||
<div class="icon-magnet"></div>
|
||||
</a>`+ dlLink +`
|
||||
</td>"+
|
||||
</td>
|
||||
<td class="tr-size home-td hide-xs">` + humanFileSize(torrent.filesize) + `</td>
|
||||
<td class="tr-se home-td hide-smol">` + torrent.seeders + `</td>
|
||||
<td class="tr-le home-td hide-smol">` + torrent.leechers + `</td>
|
||||
|
|
|
@ -52,13 +52,78 @@
|
|||
<p class="help-block">{{ T("description_markdown_notice")}}</p>
|
||||
<textarea style="height: 10rem;" id="desc" name="desc" class="form-input up-input" rows="10">{{Form.Description}}</textarea>
|
||||
</div>
|
||||
<h3>{{ T("torrent_tags")}}</h3>
|
||||
<span id="tags_list"></span>
|
||||
<a id="tagPopup" href="#" class="add-tag">{{ T("add") }}</a>
|
||||
<input type="hidden" name="tags" id="tags" value="{{ Form.Tags }}">
|
||||
{{ yield errors(name="tags")}}
|
||||
<button type="submit" class="form-input up-input">{{ T("save_changes")}}</button>
|
||||
<br/>
|
||||
<br/>
|
||||
</form>
|
||||
</div>
|
||||
{{ include "layouts/partials/modal_tags" }}
|
||||
{{end}}
|
||||
{{ block footer_js()}}
|
||||
<script type="text/javascript" src="/js/translation.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/template.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/modal.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript">
|
||||
// {{ range _, type := Config.Torrents.Tags.Types }}
|
||||
T.Add("tagtype_{{ type }}", '{{ T("tagtype_" + type) }}')
|
||||
// {{ end }}
|
||||
|
||||
Templates.Add("tag", function(tag) {
|
||||
return `<span data-name="` + tag.type + `_` + tag.tag + `" class="tag accepted" title="Tag: ` + tag.type + `({{ T("accepted") }} )">
|
||||
<span class="tag-text votable">
|
||||
` + T.r("tagtype_" + tag.type) + `: ` + tag.tag + `
|
||||
</span>
|
||||
</span>`
|
||||
})
|
||||
|
||||
// Modal initialization
|
||||
Modal.Init({
|
||||
elements: document.getElementsByClassName("modal"),
|
||||
// order of apparition of the modals
|
||||
button: "#tagPopup"
|
||||
});
|
||||
var tags = []
|
||||
document.querySelector("#modal_tag_form form").addEventListener("submit", function(e) {
|
||||
var form = e.target
|
||||
var newTag = {type: form.querySelector("select#type").value, tag: form.querySelector("input#tag").value}
|
||||
|
||||
var replaced = false
|
||||
var len = tags.length
|
||||
for(var i = 0; i < len; i++) {
|
||||
if (tags[i].type == newTag.type) {
|
||||
var oldTag = document.querySelector("span[data-name='"+ tags[i].type + "_" + tags[i].tag + "']")
|
||||
oldTag.parentElement.removeChild(oldTag)
|
||||
tags[i] = newTag
|
||||
replaced = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!replaced) tags.push(newTag)
|
||||
var tagHTml = Templates.Render("tag", newTag)
|
||||
document.getElementById("tags_list").innerHTML += tagHTml
|
||||
document.getElementById("tags").value = JSON.stringify(tags)
|
||||
Modal.CloseActive()
|
||||
e.preventDefault()
|
||||
})
|
||||
function renderTagsJSON() {
|
||||
tagsIn = document.getElementById("tags").value
|
||||
if (tagsIn == "") return
|
||||
var jsonFromTags = JSON.parse(tagsIn)
|
||||
if (jsonFromTags instanceof Array) {
|
||||
for (var i = 0; i < jsonFromTags.length; i++) {
|
||||
tags.push(jsonFromTags[i])
|
||||
var tagHTml = Templates.Render("tag", jsonFromTags[i])
|
||||
document.getElementById("tags_list").innerHTML += tagHTml
|
||||
}
|
||||
}
|
||||
}
|
||||
renderTagsJSON()
|
||||
</script>
|
||||
<script type="text/javascript" src="/js/simplemde.min.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript">new SimpleMDE({ element: document.getElementById("desc"), spellChecker: false, showIcons: [ "strikethrough", "code", "table", "horizontal-rule" ] });</script>
|
||||
{{end}}
|
||||
|
|
|
@ -152,6 +152,7 @@
|
|||
</p>
|
||||
{{ yield errors(name="hidden")}}
|
||||
{{ end }}
|
||||
|
||||
<h3>{{ T("website_link")}}</h3>
|
||||
<input name="website_link" id="website_link" class="form-input up-input" type="text" value="{{Form.WebsiteLink}}"/>
|
||||
{{ yield errors(name="website_link")}}
|
||||
|
@ -159,7 +160,12 @@
|
|||
<h3>{{ T("torrent_description")}}</h3>
|
||||
<p>{{ T("description_markdown_notice")}}</p>
|
||||
<textarea name="desc" id="desc" class="form-input up-input" style="height: 10rem;">{{Form.Description}}</textarea>
|
||||
{{ yield errors(name="desc")}}
|
||||
|
||||
<h3>{{ T("torrent_tags")}}</h3>
|
||||
<span id="tags_list"></span>
|
||||
<a id="tagPopup" href="#" class="add-tag">{{ T("add") }}</a>
|
||||
<input type="hidden" name="tags" id="tags" value="{{ Form.Tags }}">
|
||||
{{ yield errors(name="tags")}}
|
||||
<div style="width: 240px">
|
||||
{{yield captcha(captchaid=Form.CaptchaID)}}
|
||||
</div>
|
||||
|
@ -168,11 +174,13 @@
|
|||
<button type="submit" class="form-input up-btn">{{ T("upload")}}</button>
|
||||
</form>
|
||||
</div>
|
||||
{{ include "layouts/partials/modal_tags" }}
|
||||
{{end}}
|
||||
{{ block footer_js()}}
|
||||
<script type="text/javascript" src="/js/query.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/translation.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/template.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/modal.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/kilo.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
<script type="text/javascript" src="/js/simplemde.min.js?v={{ Config.Version}}{{ Config.Build }}"></script>
|
||||
{{ include "layouts/partials/torrent_item_upload" }}
|
||||
|
@ -190,6 +198,62 @@
|
|||
listContext: true
|
||||
})
|
||||
preview.render()
|
||||
</script>
|
||||
<script type="text/javascript">new SimpleMDE({ element: document.getElementById("desc"), spellChecker: false, showIcons: [ "strikethrough", "code", "table", "horizontal-rule" ] });</script>
|
||||
{{end}}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
// {{ range _, type := Config.Torrents.Tags.Types }}
|
||||
T.Add("tagtype_{{ type }}", '{{ T("tagtype_" + type) }}')
|
||||
// {{ end }}
|
||||
|
||||
Templates.Add("tag", function(tag) {
|
||||
return `<span data-name="` + tag.type + `_` + tag.tag + `" class="tag accepted" title="Tag: ` + tag.type + `({{ T("accepted") }} )">
|
||||
<span class="tag-text votable">
|
||||
` + T.r("tagtype_" + tag.type) + `: ` + tag.tag + `
|
||||
</span>
|
||||
</span>`
|
||||
})
|
||||
|
||||
// Modal initialization
|
||||
Modal.Init({
|
||||
elements: document.getElementsByClassName("modal"),
|
||||
// order of apparition of the modals
|
||||
button: "#tagPopup"
|
||||
});
|
||||
var tags = []
|
||||
document.querySelector("#modal_tag_form form").addEventListener("submit", function(e) {
|
||||
var form = e.target
|
||||
var newTag = {type: form.querySelector("select#type").value, tag: form.querySelector("input#tag").value}
|
||||
|
||||
var replaced = false
|
||||
var len = tags.length
|
||||
for(var i = 0; i < len; i++) {
|
||||
if (tags[i].type == newTag.type) {
|
||||
var oldTag = document.querySelector("span[data-name='"+ tags[i].type + "_" + tags[i].tag + "']")
|
||||
oldTag.parentElement.removeChild(oldTag)
|
||||
tags[i] = newTag
|
||||
replaced = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!replaced) tags.push(newTag)
|
||||
var tagHTml = Templates.Render("tag", newTag)
|
||||
document.getElementById("tags_list").innerHTML += tagHTml
|
||||
document.getElementById("tags").value = JSON.stringify(tags)
|
||||
Modal.CloseActive()
|
||||
e.preventDefault()
|
||||
})
|
||||
function renderTagsJSON() {
|
||||
tagsIn = document.getElementById("tags").value
|
||||
if (tagsIn == "") return
|
||||
var jsonFromTags = JSON.parse(tagsIn)
|
||||
if (jsonFromTags instanceof Array) {
|
||||
for (var i = 0; i < jsonFromTags.length; i++) {
|
||||
tags.push(jsonFromTags[i])
|
||||
var tagHTml = Templates.Render("tag", jsonFromTags[i])
|
||||
document.getElementById("tags_list").innerHTML += tagHTml
|
||||
}
|
||||
}
|
||||
}
|
||||
renderTagsJSON()
|
||||
</script>
|
||||
<script type="text/javascript">new SimpleMDE({ element: document.getElementById("desc"), spellChecker: false, showIcons: [ "strikethrough", "code", "table", "horizontal-rule" ] });</script>
|
||||
{{end}}
|
||||
|
|
|
@ -58,7 +58,7 @@ func walkDirTest(dir string, t *testing.T) {
|
|||
fakeActivity := &models.Activity{1, "t", "e", "s", 1, fakeUser}
|
||||
fakeDB := &models.DatabaseDump{time.Now(), 3, "test", "test"}
|
||||
fakeLanguage := &publicSettings.Language{"English", "en", "en-us"}
|
||||
fakeTorrentRequest := &torrentValidator.TorrentRequest{Name: "test", Magnet: "", Category: "", Remake: false, Description: "", Status: 1, Hidden: false, CaptchaID: "", WebsiteLink: "", SubCategory: 0, Languages: nil, Infohash: "", SubCategoryID: 0, CategoryID: 0, Filesize: 0, Filepath: "", FileList: nil, Trackers: nil}
|
||||
fakeTorrentRequest := &torrentValidator.TorrentRequest{Name: "test", Magnet: "", Category: "", Remake: false, Description: "", Status: 1, Hidden: false, CaptchaID: "", WebsiteLink: "", SubCategory: 0, Languages: nil, Infohash: "", SubCategoryID: 0, CategoryID: 0, Filesize: 0, Filepath: "", FileList: nil, Trackers: nil, Tags: ""}
|
||||
fakeLogin := &userValidator.LoginForm{"test", "test", "/"}
|
||||
fakeRegistration := &userValidator.RegistrationForm{"test", "", "test", "test", "xxxx", "1"}
|
||||
fakeReport := &models.TorrentReport{1, "test", 1, 1, time.Now(), fakeTorrent, fakeUser}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package upload
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -9,6 +10,8 @@ import (
|
|||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/models/tag"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/models"
|
||||
"github.com/NyaaPantsu/nyaa/utils/sanitize"
|
||||
|
@ -86,6 +89,8 @@ func ExtractEditInfo(c *gin.Context, r *torrentValidator.TorrentRequest) error {
|
|||
// ExtractBasicValue : takes an http request and computes all basic fields for this form
|
||||
func ExtractBasicValue(c *gin.Context, r *torrentValidator.TorrentRequest) error {
|
||||
c.Bind(r)
|
||||
r.Tags = c.PostForm("tags")
|
||||
|
||||
// trim whitespace
|
||||
r.Name = strings.TrimSpace(r.Name)
|
||||
r.Description = sanitize.Sanitize(strings.TrimSpace(r.Description), "default")
|
||||
|
@ -102,6 +107,8 @@ func ExtractBasicValue(c *gin.Context, r *torrentValidator.TorrentRequest) error
|
|||
return err
|
||||
}
|
||||
|
||||
r.ValidateTags() // Tags should only be filtered, don't stop the errors from uploading
|
||||
|
||||
err = r.ValidateWebsiteLink()
|
||||
return err
|
||||
}
|
||||
|
@ -179,6 +186,20 @@ func UpdateTorrent(r *torrentValidator.UpdateRequest, t *models.Torrent, current
|
|||
|
||||
t.Hidden = r.Update.Hidden
|
||||
|
||||
// This part of the code check that we have only one tag of the same type
|
||||
var tagsReq models.Tags
|
||||
json.Unmarshal([]byte(r.Update.Tags), &tagsReq)
|
||||
for _, tag := range tagsReq {
|
||||
tag.Accepted = true
|
||||
tag.TorrentID = t.ID
|
||||
tag.UserID = 0 // 0 so we don't increase pantsu points for every tag for the actual user (would be too much increase)
|
||||
tag.Weight = config.Get().Torrents.Tags.MaxWeight + 1
|
||||
tags.New(&tag, t) // We create new tags with the user id
|
||||
tags.Filter(tag.Tag, tag.Type, t) // We filter out every tags and increase/decrease pantsu for already sent tags
|
||||
t.Tags.DeleteType(tag.Type) // We cleanup the map from the other tags
|
||||
t.Tags = append(t.Tags) // Finally we append ours to the torrent
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
|
|
|
@ -12,3 +12,4 @@ var errTorrentPrivate = errors.New("torrent_private")
|
|||
var errTorrentNoTrackers = errors.New("torrent_no_working_trackers")
|
||||
var errTorrentAndMagnet = errors.New("torrent_plus_magnet")
|
||||
var errTorrentHashInvalid = errors.New("torrent_hash_invalid")
|
||||
var errTorrentTagsInvalid = errors.New("torrent_tags_invalid")
|
||||
|
|
|
@ -22,6 +22,7 @@ type TorrentRequest struct {
|
|||
Filepath string `json:"-"`
|
||||
FileList []uploadedFile `json:"filelist,omitempty"`
|
||||
Trackers []string `json:"trackers,omitempty"`
|
||||
Tags string `json:"tags,omitempty" form:"tags"`
|
||||
}
|
||||
|
||||
// UpdateRequest struct
|
||||
|
|
|
@ -3,6 +3,7 @@ package torrentValidator
|
|||
import (
|
||||
"encoding/base32"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/url"
|
||||
|
@ -14,9 +15,11 @@ import (
|
|||
"github.com/NyaaPantsu/nyaa/utils/categories"
|
||||
"github.com/NyaaPantsu/nyaa/utils/cookies"
|
||||
"github.com/NyaaPantsu/nyaa/utils/format"
|
||||
"github.com/NyaaPantsu/nyaa/utils/log"
|
||||
msg "github.com/NyaaPantsu/nyaa/utils/messages"
|
||||
"github.com/NyaaPantsu/nyaa/utils/metainfo"
|
||||
"github.com/NyaaPantsu/nyaa/utils/torrentLanguages"
|
||||
"github.com/NyaaPantsu/nyaa/utils/validator/tag"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/zeebo/bencode"
|
||||
)
|
||||
|
@ -29,6 +32,34 @@ func (r *TorrentRequest) ValidateName() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (r *TorrentRequest) ValidateTags() error {
|
||||
// We need to parse it to json
|
||||
var tags []tagsValidator.CreateForm
|
||||
err := json.Unmarshal([]byte(r.Tags), &tags)
|
||||
if err != nil {
|
||||
r.Tags = ""
|
||||
return errTorrentTagsInvalid
|
||||
}
|
||||
// and filter out multiple tags with the same type (only keep the first one)
|
||||
var index config.ArrayString
|
||||
var filteredTags []tagsValidator.CreateForm
|
||||
for _, tag := range tags {
|
||||
if index.Contains(tag.Type) {
|
||||
continue
|
||||
}
|
||||
filteredTags = append(filteredTags, tag)
|
||||
index = append(index, tag.Type)
|
||||
}
|
||||
b, err := json.Marshal(filteredTags)
|
||||
if err != nil {
|
||||
r.Tags = ""
|
||||
log.Infof("Couldn't parse to json the tags %v", filteredTags)
|
||||
return errTorrentTagsInvalid
|
||||
}
|
||||
r.Tags = string(b)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *TorrentRequest) ValidateDescription() error {
|
||||
if len(r.Description) > config.Get().DescriptionLength {
|
||||
return errTorrentDescInvalid
|
||||
|
|
|
@ -172,3 +172,25 @@ func TestExtractLanguage(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateTags(t *testing.T) {
|
||||
r := TorrentRequest{}
|
||||
tests := []struct {
|
||||
Test string
|
||||
Expected error
|
||||
}{
|
||||
{"", errTorrentTagsInvalid},
|
||||
{`{"":"","":""}`, errTorrentTagsInvalid},
|
||||
{`{"tag":"xD","type":"lol"}`, errTorrentTagsInvalid},
|
||||
{`[{"tag":"xD","type":"lol"}]`, nil},
|
||||
{`[{"tag":"xD","type":"lol"},{"tag":"xD","type":"lol"}]`, nil},
|
||||
}
|
||||
for _, test := range tests {
|
||||
r.Tags = test.Test
|
||||
err := r.ValidateTags()
|
||||
if err != test.Expected {
|
||||
t.Errorf("Validation of torrent hash for '%s' doesn't give the expected result, have '%v', wants '%v'", test.Test, err, test.Expected)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Référencer dans un nouveau ticket