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

Adding tag post controller

Cette révision appartient à :
akuma06 2017-07-28 20:43:22 +02:00
Parent 742dfa84fd
révision 62ea1aaf10
9 fichiers modifiés avec 129 ajouts et 4 suppressions

Voir le fichier

@ -126,6 +126,9 @@ torrents:
order: torrent_id
# TorrentSort : Default sorting order for torrents
sort: DESC
tags:
# Torrent Tag Max weight for automatic system approval
max_weight: 100.00
users:
default_notifications_settings: {"new_torrent": true, "new_torrent_email": false, "new_comment": true, "new_comment_email": false, "new_responses": false, "new_responses_email": false, "new_follower": false, "new_follower_email": false, "followed": false, "followed_email": false}
navigation:

Voir le fichier

@ -46,6 +46,10 @@ type Config struct {
Models ModelsConfig `yaml:"models,flow,omitempty"`
}
type Tags struct {
MaxWeight float64 `yaml:"max_weight,omitempty"`
}
// WebAddressConfig : Config struct for web addresses
type WebAddressConfig struct {
Nyaa string `yaml:"nyaa,omitempty"`
@ -119,6 +123,7 @@ type TorrentsConfig struct {
Trackers TrackersConfig `yaml:"trackers,flow,omitempty"`
Order string `yaml:"order,omitempty"`
Sort string `yaml:"sort,omitempty"`
Tags Tags `yaml:"tags,omitempty"`
}
// UsersConfig : Config struct for Users

27
controllers/torrent/tag.go Fichier normal
Voir le fichier

@ -0,0 +1,27 @@
package torrentController
import (
"github.com/NyaaPantsu/nyaa/models"
"github.com/NyaaPantsu/nyaa/models/tags"
msg "github.com/NyaaPantsu/nyaa/utils/messages"
"github.com/NyaaPantsu/nyaa/utils/validator"
"github.com/NyaaPantsu/nyaa/utils/validator/tags"
"github.com/gin-gonic/gin"
)
func postTag(c *gin.Context, torrent *models.Torrent, user *models.User) {
messages := msg.GetMessages(c)
tagForm := &tagsValidator.CreateForm{}
c.Bind(tagForm)
validator.ValidateForm(tagForm, messages)
for _, tag := range user.Tags {
if tag.Tag == tagForm.Tag {
return // already a tag by the user, don't add one more
}
}
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
}

Voir le fichier

@ -20,35 +20,57 @@ func ViewHandler(c *gin.Context) {
messages := msg.GetMessages(c)
user := router.GetUser(c)
// Display success message on upload
if c.Request.URL.Query()["success"] != nil {
messages.AddInfoT("infos", "torrent_uploaded")
}
// Display success message on edit
if c.Request.URL.Query()["success_edit"] != nil {
messages.AddInfoT("infos", "torrent_updated")
}
// Display wrong captcha error message
if c.Request.URL.Query()["badcaptcha"] != nil {
messages.AddErrorT("errors", "bad_captcha")
}
// Display reported successful message
if c.Request.URL.Query()["reported"] != nil {
messages.AddInfoTf("infos", "report_msg", id)
}
// Retrieve the torrent
torrent, err := torrents.FindByID(uint(id))
if c.Request.URL.Query()["notif"] != nil {
// If come from notification, toggle the notification as read
if c.Request.URL.Query()["notif"] != nil && user.ID > 0 {
notifications.ToggleReadNotification(torrent.Identifier(), user.ID)
}
// If torrent not found, display 404
if err != nil {
c.Status(http.StatusNotFound)
return
}
// We load tags for user and torrents
user.LoadTags(torrent)
torrent.LoadTags()
// We add a tag if posted
if c.PostForm("tag") != "" && user.ID > 0 {
postTag(c, torrent, user)
}
// Convert torrent to the JSON Model used to display a torrent
// Since many datas need to be parsed from a simple torrent model to the actual display
b := torrent.ToJSON()
// Get the folder root for the filelist view
folder := filelist.FileListToFolder(torrent.FileList, "root")
captchaID := ""
//Generate a captcha
if user.NeedsCaptcha() {
captchaID = captcha.GetID()
}
// Display finally the view
templates.Torrent(c, b, folder, captchaID)
}

Voir le fichier

@ -106,5 +106,9 @@ func GormInit(conf *config.Config, logger Logger) (*gorm.DB, error) {
if db.Error != nil {
return db, db.Error
}
db.AutoMigrate(&Tag{})
if db.Error != nil {
return db, db.Error
}
return db, nil
}

Voir le fichier

@ -1,5 +1,12 @@
package models
import (
"errors"
"net/http"
"github.com/fatih/structs"
)
// Tag model for a torrent vote system
type Tag struct {
TorrentID uint `gorm:"column:torrent_id"`
@ -8,4 +15,27 @@ type Tag struct {
Type string `gorm:"column:type"`
Weight float64 `gorm:"column:weight"`
Accepted bool `gorm:"column:accepted"`
Total float64 `gorm:"-"`
}
// Update a tag
func (ta *Tag) Update() (int, error) {
if ORM.Model(ta).UpdateColumn(ta.toMap()).Error != nil {
return http.StatusInternalServerError, errors.New("Tag was not updated")
}
return http.StatusOK, nil
}
// Delete : delete a tag based on id
func (ta *Tag) Delete() (int, error) {
if ORM.Delete(ta).Error != nil {
return http.StatusInternalServerError, errors.New("tag_not_deleted")
}
return http.StatusOK, nil
}
// toMap : convert the model to a map of interface
func (ta *Tag) toMap() map[string]interface{} {
return structs.Map(ta)
}

Voir le fichier

@ -98,6 +98,7 @@ type TorrentJSON struct {
Completed uint32 `json:"completed"`
LastScrape time.Time `json:"last_scrape"`
FileList []FileJSON `json:"file_list"`
Tags []Tag `json:"-"` // not needed in json to reduce db calls
}
// Size : Returns the total size of memory recursively allocated for this struct
@ -347,6 +348,7 @@ func (t *Torrent) ToJSON() TorrentJSON {
Completed: scrape.Completed,
LastScrape: scrape.LastScrape,
FileList: fileListJSON,
Tags: t.Tags,
}
return res
@ -365,7 +367,6 @@ func TorrentsToJSON(t []Torrent) []TorrentJSON {
// Update : Update a torrent based on model
func (t *Torrent) Update(unscope bool) (int, error) {
cache.C.Delete(t.Identifier())
db := ORM
if unscope {
db = ORM.Unscoped()
@ -385,6 +386,8 @@ func (t *Torrent) Update(unscope bool) (int, error) {
log.Errorf("Unable to update torrent to ES index: %s", err)
}
}
// We only flush cache after update
cache.C.Delete(t.Identifier())
return http.StatusOK, nil
}
@ -394,9 +397,8 @@ func (t *Torrent) UpdateUnscope() (int, error) {
return t.Update(true)
}
// DeleteTorrent : delete a torrent based on id
// Delete : delete a torrent based on id
func (t *Torrent) Delete(definitely bool) (*Torrent, int, error) {
cache.C.Flush()
db := ORM
if definitely {
db = ORM.Unscoped()
@ -413,6 +415,8 @@ func (t *Torrent) Delete(definitely bool) (*Torrent, int, error) {
log.Errorf("Unable to delete torrent to ES index: %s", err)
}
}
// We flush cache only after delete
cache.C.Flush()
return t, http.StatusOK, nil
}
@ -426,3 +430,13 @@ func (t *Torrent) DefinitelyDelete() (*Torrent, int, error) {
func (t *Torrent) toMap() map[string]interface{} {
return structs.Map(t)
}
// LoadTags : load all the unique tags with summed up weight from the database in torrent
func (t *Torrent) LoadTags() {
// Only load if necessary
if len(t.Tags) == 0 {
// Should output a query like this: SELECT tag, type, accepted, SUM(weight) as total FROM tags WHERE torrent_id=923000 GROUP BY type, tag ORDER BY type, total DESC
err := ORM.Select("tag, type, accepted, SUM(weight) as total").Where("torrent_id = ?", t.ID).Group("type, tag").Order("type ASC, total DESC").Find(&t.Tags).Error
log.CheckErrorWithMessage(err, "LOAD_TAGS_ERROR: Couldn't load tags!")
}
}

Voir le fichier

@ -59,6 +59,7 @@ type User struct {
UnreadNotifications int `gorm:"-"` // We don't want to loop every notifications when accessing user unread notif
Settings UserSettings `gorm:"-"` // We don't want to load settings everytime, stock it as a string, parse it when needed
Tags []Tag `gorm:"-"` // We load tags only when viewing a torrent
}
// UserJSON : User model conversion in JSON
@ -406,3 +407,13 @@ func (u *User) IncreasePantsu() {
func (u *User) DecreasePantsu() {
u.Pantsu = 0.8 * u.Pantsu // You lose 20% of your pantsu points each wrong vote
}
func (u *User) LoadTags(torrent *Torrent) {
if u.ID == 0 {
return
}
if err := ORM.Where("torrent_id = ? AND user_id = ?", torrent.ID, u.ID).Find(&u.Tags).Error; err != nil {
log.CheckErrorWithMessage(err, "LOAD_TAGS_ERROR: Couldn't load tags!")
return
}
}

Voir le fichier

@ -105,6 +105,15 @@ func FindByID(id uint) (*models.User, int, error) {
return user, http.StatusOK, nil
}
// FindRawByID retrieves a user by ID without anything.
func FindRawByID(id uint) (*models.User, int, error) {
var user = &models.User{}
if models.ORM.Last(user, id).RecordNotFound() {
return user, http.StatusNotFound, errors.New("user_not_found")
}
return user, http.StatusOK, nil
}
func SessionByID(id uint) (*models.User, int, error) {
var user = &models.User{}
if models.ORM.Preload("Notifications").Where("user_id = ?", id).First(user).RecordNotFound() { // We only load unread notifications