activity log for users (#1002)
List Torrent delete log Torrent edit log Comment delete log And every other logged activities Can be filtered out by a filter tag ("edit" or "delete" supported) Pages navigation Can be accessed by /activities Added some translation string Fixed hidden username on api request Fixed comments username on modpanel New Activity model New Activity handler New Activity Service Fixed some updating issue for ES when moderating torrents Be aware deleting torrents and comments return the model now!
Cette révision appartient à :
Parent
02c3474b3e
révision
93364dac77
20 fichiers modifiés avec 319 ajouts et 53 suppressions
|
@ -181,6 +181,8 @@ models:
|
|||
files_table_name: files
|
||||
# NotificationTableName : Name of notifications table in DB
|
||||
notifications_table_name: notifications
|
||||
# ActivitiesTableName : Name of activitis log table in DB
|
||||
activities_table_name: activities
|
||||
# for sukebei:
|
||||
# LastOldTorrentID = 2303945
|
||||
# TorrentsTableName = "sukebei_torrents"
|
||||
|
|
|
@ -180,6 +180,7 @@ type ModelsConfig struct {
|
|||
UploadsOldTableName string `yaml:"uploads_old_table_name,omitempty"`
|
||||
FilesTableName string `yaml:"files_table_name,omitempty"`
|
||||
NotificationsTableName string `yaml:"notifications_table_name,omitempty"`
|
||||
ActivityTableName string `yaml:"activities_table_name,omitempty"`
|
||||
}
|
||||
|
||||
// SearchConfig : Config struct for search
|
||||
|
|
|
@ -82,7 +82,7 @@ func GormInit(conf *config.Config, logger Logger) (*gorm.DB, error) {
|
|||
db.SetLogger(logger)
|
||||
}
|
||||
|
||||
db.AutoMigrate(&model.User{}, &model.UserFollows{}, &model.UserUploadsOld{}, &model.Notification{})
|
||||
db.AutoMigrate(&model.User{}, &model.UserFollows{}, &model.UserUploadsOld{}, &model.Notification{}, &model.Activity{})
|
||||
if db.Error != nil {
|
||||
return db, db.Error
|
||||
}
|
||||
|
|
27
model/activity.go
Fichier normal
27
model/activity.go
Fichier normal
|
@ -0,0 +1,27 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
)
|
||||
|
||||
// Activity model
|
||||
type Activity struct {
|
||||
ID uint
|
||||
Content string
|
||||
Identifier string
|
||||
Filter string
|
||||
UserID uint
|
||||
User *User
|
||||
}
|
||||
|
||||
// NewActivity : Create a new activity log
|
||||
func NewActivity(identifier string, filter string, c ...string) Activity {
|
||||
return Activity{Identifier: identifier, Content: strings.Join(c, ","), Filter: filter}
|
||||
}
|
||||
|
||||
// TableName : Return the name of activity table
|
||||
func (a *Activity) TableName() string {
|
||||
return config.Conf.Models.ActivityTableName
|
||||
}
|
53
router/activity_handler.go
Fichier normal
53
router/activity_handler.go
Fichier normal
|
@ -0,0 +1,53 @@
|
|||
package router
|
||||
|
||||
import (
|
||||
"html"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/service/activity"
|
||||
"github.com/NyaaPantsu/nyaa/service/user/permission"
|
||||
"github.com/NyaaPantsu/nyaa/util/log"
|
||||
msg "github.com/NyaaPantsu/nyaa/util/messages"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// ActivityListHandler : Show a list of activity
|
||||
func ActivityListHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
page := vars["page"]
|
||||
pagenum := 1
|
||||
offset := 100
|
||||
userid := r.URL.Query().Get("userid")
|
||||
filter := r.URL.Query().Get("filter")
|
||||
defer r.Body.Close()
|
||||
var err error
|
||||
messages := msg.GetMessages(r)
|
||||
currentUser := getUser(r)
|
||||
if page != "" {
|
||||
pagenum, err = strconv.Atoi(html.EscapeString(page))
|
||||
if !log.CheckError(err) {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
var conditions []string
|
||||
var values []interface{}
|
||||
if userid != "" && userPermission.HasAdmin(currentUser) {
|
||||
conditions = append(conditions, "user_id = ?")
|
||||
values = append(values, userid)
|
||||
}
|
||||
if filter != "" {
|
||||
conditions = append(conditions, "filter = ?")
|
||||
values = append(values, filter)
|
||||
}
|
||||
|
||||
activities, nbActivities := activity.GetAllActivities(offset, (pagenum-1)*offset, strings.Join(conditions, " AND "), values...)
|
||||
common := newCommonVariables(r)
|
||||
common.Navigation = navigation{nbActivities, offset, pagenum, "activity_list"}
|
||||
htv := modelListVbs{common, activities, messages.GetAllErrors(), messages.GetAllInfos()}
|
||||
err = activityList.ExecuteTemplate(w, "index.html", htv)
|
||||
log.CheckError(err)
|
||||
}
|
|
@ -269,7 +269,7 @@ func APIUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
|||
messages.ImportFromError("errors", apiService.ErrRights)
|
||||
}
|
||||
update.UpdateTorrent(&torrent, user)
|
||||
torrentService.UpdateTorrent(torrent)
|
||||
torrentService.UpdateTorrent(&torrent)
|
||||
}
|
||||
apiResponseHandler(w, r)
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/NyaaPantsu/nyaa/db"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
"github.com/NyaaPantsu/nyaa/service"
|
||||
"github.com/NyaaPantsu/nyaa/service/activity"
|
||||
"github.com/NyaaPantsu/nyaa/service/api"
|
||||
"github.com/NyaaPantsu/nyaa/service/comment"
|
||||
"github.com/NyaaPantsu/nyaa/service/report"
|
||||
|
@ -310,9 +311,12 @@ func TorrentPostEditModPanel(w http.ResponseWriter, r *http.Request) {
|
|||
torrent.WebsiteLink = uploadForm.WebsiteLink
|
||||
torrent.Description = uploadForm.Description
|
||||
torrent.Language = uploadForm.Language
|
||||
// torrent.Uploader = nil // GORM will create a new user otherwise (wtf?!)
|
||||
db.ORM.Model(&torrent).UpdateColumn(&torrent)
|
||||
_, err := torrentService.UpdateUnscopeTorrent(&torrent)
|
||||
messages.AddInfoT("infos", "torrent_updated")
|
||||
if err == nil { // We only log edit torrent for admins
|
||||
_, username := torrentService.HideTorrentUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
|
||||
activity.Log(&model.User{}, torrent.Identifier(), "edit", "torrent_edited_by", strconv.Itoa(int(torrent.ID)), username, getUser(r).Username)
|
||||
}
|
||||
}
|
||||
}
|
||||
htv := formTemplateVariables{newPanelCommonVariables(r), uploadForm, messages.GetAllErrors(), messages.GetAllInfos()}
|
||||
|
@ -325,7 +329,10 @@ func CommentDeleteModPanel(w http.ResponseWriter, r *http.Request) {
|
|||
id := r.URL.Query().Get("id")
|
||||
|
||||
defer r.Body.Close()
|
||||
_, _ = commentService.DeleteComment(id)
|
||||
comment, _, err := commentService.DeleteComment(id)
|
||||
if err == nil {
|
||||
activity.Log(&model.User{}, comment.Identifier(), "delete", "comment_deleted_by", strconv.Itoa(int(comment.ID)), comment.User.Username, getUser(r).Username)
|
||||
}
|
||||
url, _ := Router.Get("mod_clist").URL()
|
||||
http.Redirect(w, r, url.String()+"?deleted", http.StatusSeeOther)
|
||||
}
|
||||
|
@ -336,8 +343,10 @@ func TorrentDeleteModPanel(w http.ResponseWriter, r *http.Request) {
|
|||
definitely := r.URL.Query()["definitely"]
|
||||
defer r.Body.Close()
|
||||
var returnRoute string
|
||||
var err error
|
||||
var torrent *model.Torrent
|
||||
if definitely != nil {
|
||||
_, _ = torrentService.DefinitelyDeleteTorrent(id)
|
||||
torrent, _, err = torrentService.DefinitelyDeleteTorrent(id)
|
||||
|
||||
//delete reports of torrent
|
||||
whereParams := serviceBase.CreateWhereParams("torrent_id = ?", id)
|
||||
|
@ -347,7 +356,7 @@ func TorrentDeleteModPanel(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
returnRoute = "mod_tlist_deleted"
|
||||
} else {
|
||||
_, _ = torrentService.DeleteTorrent(id)
|
||||
torrent, _, err = torrentService.DeleteTorrent(id)
|
||||
|
||||
//delete reports of torrent
|
||||
whereParams := serviceBase.CreateWhereParams("torrent_id = ?", id)
|
||||
|
@ -357,6 +366,10 @@ func TorrentDeleteModPanel(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
returnRoute = "mod_tlist"
|
||||
}
|
||||
if err == nil {
|
||||
_, username := torrentService.HideTorrentUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
|
||||
activity.Log(&model.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, getUser(r).Username)
|
||||
}
|
||||
url, _ := Router.Get(returnRoute).URL()
|
||||
http.Redirect(w, r, url.String()+"?deleted", http.StatusSeeOther)
|
||||
}
|
||||
|
@ -367,8 +380,12 @@ func TorrentReportDeleteModPanel(w http.ResponseWriter, r *http.Request) {
|
|||
defer r.Body.Close()
|
||||
fmt.Println(id)
|
||||
idNum, _ := strconv.ParseUint(id, 10, 64)
|
||||
_, _ = reportService.DeleteTorrentReport(uint(idNum))
|
||||
|
||||
_, _, _ = reportService.DeleteTorrentReport(uint(idNum))
|
||||
/* If we need to log report delete activity
|
||||
if err == nil {
|
||||
activity.Log(&model.User{}, torrent.Identifier(), "delete", "torrent_report_deleted_by", strconv.Itoa(int(report.ID)), getUser(r).Username)
|
||||
}
|
||||
*/
|
||||
url, _ := Router.Get("mod_trlist").URL()
|
||||
http.Redirect(w, r, url.String()+"?deleted", http.StatusSeeOther)
|
||||
}
|
||||
|
@ -500,8 +517,7 @@ func DeletedTorrentsPostPanel(w http.ResponseWriter, r *http.Request) {
|
|||
func TorrentBlockModPanel(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
id := r.URL.Query().Get("id")
|
||||
torrent, _, _ := torrentService.ToggleBlockTorrent(id)
|
||||
|
||||
torrent, _, err := torrentService.ToggleBlockTorrent(id)
|
||||
var returnRoute, action string
|
||||
if torrent.IsDeleted() {
|
||||
returnRoute = "mod_tlist_deleted"
|
||||
|
@ -513,6 +529,10 @@ func TorrentBlockModPanel(w http.ResponseWriter, r *http.Request) {
|
|||
} else {
|
||||
action = "unblocked"
|
||||
}
|
||||
if err == nil {
|
||||
_, username := torrentService.HideTorrentUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
|
||||
activity.Log(&model.User{}, torrent.Identifier(), action, "torrent_"+action+"_by", strconv.Itoa(int(torrent.ID)), username, getUser(r).Username)
|
||||
}
|
||||
url, _ := Router.Get(returnRoute).URL()
|
||||
http.Redirect(w, r, url.String()+"?"+action, http.StatusSeeOther)
|
||||
}
|
||||
|
@ -616,18 +636,24 @@ func torrentManyAction(r *http.Request) {
|
|||
}
|
||||
|
||||
/* Changes are done, we save */
|
||||
db.ORM.Unscoped().Model(&torrent).UpdateColumn(&torrent)
|
||||
_, err := torrentService.UpdateUnscopeTorrent(&torrent)
|
||||
if err == nil {
|
||||
_, username := torrentService.HideTorrentUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
|
||||
activity.Log(&model.User{}, torrent.Identifier(), "edited", "torrent_edited_by", strconv.Itoa(int(torrent.ID)), username, getUser(r).Username)
|
||||
}
|
||||
} else if action == "delete" {
|
||||
if status == model.TorrentStatusBlocked { // Then we should lock torrents before deleting them
|
||||
torrent.Status = status
|
||||
messages.AddInfoTf("infos", "torrent_moved", torrent.Name)
|
||||
db.ORM.Unscoped().Model(&torrent).UpdateColumn(&torrent) // We must save it here and soft delete it after
|
||||
torrentService.UpdateUnscopeTorrent(&torrent)
|
||||
}
|
||||
_, err = torrentService.DeleteTorrent(torrentID)
|
||||
_, _, err = torrentService.DeleteTorrent(torrentID)
|
||||
if err != nil {
|
||||
messages.ImportFromError("errors", err)
|
||||
} else {
|
||||
messages.AddInfoTf("infos", "torrent_deleted", torrent.Name)
|
||||
_, username := torrentService.HideTorrentUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
|
||||
activity.Log(&model.User{}, torrent.Identifier(), "deleted", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, getUser(r).Username)
|
||||
}
|
||||
} else {
|
||||
messages.AddErrorTf("errors", "no_action_exist", action)
|
||||
|
|
|
@ -54,6 +54,7 @@ func init() {
|
|||
Router.HandleFunc("/search/{page}", SearchHandler).Name("search_page")
|
||||
Router.HandleFunc("/verify/email/{token}", UserVerifyEmailHandler).Name("user_verify").Methods("GET")
|
||||
Router.HandleFunc("/faq", FaqHandler).Name("faq")
|
||||
Router.HandleFunc("/activities", ActivityListHandler).Name("activity_list")
|
||||
Router.HandleFunc("/feed", RSSHandler).Name("feed")
|
||||
Router.HandleFunc("/feed/{page}", RSSHandler).Name("feed_page")
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ const ModeratorDir = "admin"
|
|||
var homeTemplate,
|
||||
searchTemplate,
|
||||
faqTemplate,
|
||||
activityList,
|
||||
uploadTemplate,
|
||||
viewTemplate,
|
||||
viewRegisterTemplate,
|
||||
|
@ -72,6 +73,11 @@ func ReloadTemplates() {
|
|||
name: "FAQ",
|
||||
file: "FAQ.html",
|
||||
},
|
||||
{
|
||||
templ: &activityList,
|
||||
name: "activityList",
|
||||
file: "activity_list.html",
|
||||
},
|
||||
{
|
||||
templ: &viewTemplate,
|
||||
name: "view",
|
||||
|
@ -132,7 +138,6 @@ func ReloadTemplates() {
|
|||
name: "change_settings",
|
||||
file: "public_settings.html",
|
||||
},
|
||||
|
||||
}
|
||||
for idx := range pubTempls {
|
||||
pubTempls[idx].indexFile = filepath.Join(TemplateDir, "index.html")
|
||||
|
|
|
@ -9,6 +9,8 @@ import (
|
|||
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
"github.com/NyaaPantsu/nyaa/service/activity"
|
||||
"github.com/NyaaPantsu/nyaa/service/torrent"
|
||||
"github.com/NyaaPantsu/nyaa/service/user/permission"
|
||||
"github.com/NyaaPantsu/nyaa/util"
|
||||
"github.com/NyaaPantsu/nyaa/util/categories"
|
||||
|
@ -257,18 +259,17 @@ var FuncMap = template.FuncMap{
|
|||
return string(T(d))
|
||||
},
|
||||
"genUploaderLink": func(uploaderID uint, uploaderName template.HTML, torrentHidden bool) template.HTML {
|
||||
|
||||
if torrentHidden {
|
||||
return template.HTML("れんちょん")
|
||||
}
|
||||
uploaderID, username := torrentService.HideTorrentUser(uploaderID, string(uploaderName), torrentHidden)
|
||||
if uploaderID == 0 {
|
||||
return template.HTML("れんちょん")
|
||||
return template.HTML(username)
|
||||
}
|
||||
url, err := Router.Get("user_profile").URL("id", strconv.Itoa(int(uploaderID)), "username", string(uploaderName))
|
||||
url, err := Router.Get("user_profile").URL("id", strconv.Itoa(int(uploaderID)), "username", username)
|
||||
if err != nil {
|
||||
return "error"
|
||||
}
|
||||
return template.HTML("<a href=\"" + url.String() + "\">" + string(uploaderName) + "</a>")
|
||||
|
||||
return template.HTML("<a href=\"" + url.String() + "\">" + username + "</a>")
|
||||
},
|
||||
"genActivityContent": func(a model.Activity, T publicSettings.TemplateTfunc) template.HTML {
|
||||
return activity.ToLocale(&a, T)
|
||||
},
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/NyaaPantsu/nyaa/db"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
"github.com/NyaaPantsu/nyaa/service"
|
||||
"github.com/NyaaPantsu/nyaa/service/activity"
|
||||
"github.com/NyaaPantsu/nyaa/service/api"
|
||||
"github.com/NyaaPantsu/nyaa/service/captcha"
|
||||
"github.com/NyaaPantsu/nyaa/service/notifier"
|
||||
|
@ -222,7 +223,6 @@ func TorrentPostEditUserPanel(w http.ResponseWriter, r *http.Request) {
|
|||
torrent.WebsiteLink = uploadForm.WebsiteLink
|
||||
torrent.Description = uploadForm.Description
|
||||
torrent.Language = uploadForm.Language
|
||||
// torrent.Uploader = nil // GORM will create a new user otherwise (wtf?!)
|
||||
db.ORM.Model(&torrent).UpdateColumn(&torrent)
|
||||
messages.AddInfoT("infos", "torrent_updated")
|
||||
}
|
||||
|
@ -241,8 +241,14 @@ func TorrentDeleteUserPanel(w http.ResponseWriter, r *http.Request) {
|
|||
currentUser := getUser(r)
|
||||
torrent, _ := torrentService.GetTorrentByID(id)
|
||||
if userPermission.CurrentOrAdmin(currentUser, torrent.UploaderID) {
|
||||
_, err := torrentService.DeleteTorrent(id)
|
||||
_, _, err := torrentService.DeleteTorrent(id)
|
||||
if err == nil {
|
||||
_, username := torrentService.HideTorrentUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
|
||||
if userPermission.HasAdmin(currentUser) { // We hide username on log activity if user is not admin and torrent is hidden
|
||||
activity.Log(&model.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, currentUser.Username)
|
||||
} else {
|
||||
activity.Log(&model.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, username)
|
||||
}
|
||||
//delete reports of torrent
|
||||
whereParams := serviceBase.CreateWhereParams("torrent_id = ?", id)
|
||||
reports, _, _ := reportService.GetTorrentReportsOrderBy(&whereParams, "", 0, 0)
|
||||
|
|
41
service/activity/activity.go
Fichier normal
41
service/activity/activity.go
Fichier normal
|
@ -0,0 +1,41 @@
|
|||
package activity
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
"strings"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/db"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
"github.com/NyaaPantsu/nyaa/util/publicSettings"
|
||||
)
|
||||
|
||||
// Log : log an activity from a user to his own id (System user id is 0)
|
||||
func Log(user *model.User, name string, filter string, msg ...string) {
|
||||
activity := model.NewActivity(name, filter, msg...)
|
||||
activity.UserID = user.ID
|
||||
db.ORM.Create(&activity)
|
||||
}
|
||||
|
||||
// DeleteAll : Erase aticities from a user (System user id is 0)
|
||||
func DeleteAll(id uint) {
|
||||
db.ORM.Where("user_id = ?", id).Delete(&model.Activity{})
|
||||
}
|
||||
|
||||
// ToLocale : Convert list of parameters to message in local language
|
||||
func ToLocale(a *model.Activity, T publicSettings.TemplateTfunc) template.HTML {
|
||||
c := strings.Split(a.Content, ",")
|
||||
d := make([]interface{}, len(c)-1)
|
||||
for i, s := range c[1:] {
|
||||
d[i] = s
|
||||
}
|
||||
return T(c[0], d...)
|
||||
}
|
||||
|
||||
// GetAllActivities : Get All activities
|
||||
func GetAllActivities(limit int, offset int, conditions string, values ...interface{}) ([]model.Activity, int) {
|
||||
var activities []model.Activity
|
||||
var nbActivities int
|
||||
db.ORM.Model(&activities).Where(conditions, values...).Count(&nbActivities)
|
||||
db.ORM.Preload("User").Limit(limit).Offset(offset).Order("id DESC").Where(conditions, values...).Find(&activities)
|
||||
return activities, nbActivities
|
||||
}
|
|
@ -13,19 +13,19 @@ func GetAllComments(limit int, offset int, conditions string, values ...interfac
|
|||
var comments []model.Comment
|
||||
var nbComments int
|
||||
db.ORM.Model(&comments).Where(conditions, values...).Count(&nbComments)
|
||||
db.ORM.Preload("User").Limit(limit).Offset(offset).Where(conditions, values...).Find(&comments)
|
||||
db.ORM.Limit(limit).Offset(offset).Where(conditions, values...).Preload("User").Find(&comments)
|
||||
return comments, nbComments
|
||||
}
|
||||
|
||||
// DeleteComment : Delete a comment
|
||||
// FIXME : move this to comment service
|
||||
func DeleteComment(id string) (int, error) {
|
||||
func DeleteComment(id string) (*model.Comment, int, error) {
|
||||
var comment model.Comment
|
||||
if db.ORM.First(&comment, id).RecordNotFound() {
|
||||
return http.StatusNotFound, errors.New("Comment is not found")
|
||||
if db.ORM.Where("comment_id = ?", id).Preload("User").Preload("Torrent").Find(&comment).RecordNotFound() {
|
||||
return &comment, http.StatusNotFound, errors.New("Comment is not found")
|
||||
}
|
||||
if db.ORM.Delete(&comment).Error != nil {
|
||||
return http.StatusInternalServerError, errors.New("Comment is not deleted")
|
||||
return &comment, http.StatusInternalServerError, errors.New("Comment is not deleted")
|
||||
}
|
||||
return http.StatusOK, nil
|
||||
return &comment, http.StatusOK, nil
|
||||
}
|
||||
|
|
|
@ -20,15 +20,15 @@ func CreateTorrentReport(torrentReport model.TorrentReport) error {
|
|||
}
|
||||
|
||||
// DeleteTorrentReport : Delete a torrent report by id
|
||||
func DeleteTorrentReport(id uint) (error, int) {
|
||||
func DeleteTorrentReport(id uint) (*model.TorrentReport, error, int) {
|
||||
var torrentReport model.TorrentReport
|
||||
if db.ORM.First(&torrentReport, id).RecordNotFound() {
|
||||
return errors.New("Trying to delete a torrent report that does not exists"), http.StatusNotFound
|
||||
return &torrentReport, errors.New("Trying to delete a torrent report that does not exists"), http.StatusNotFound
|
||||
}
|
||||
if err := db.ORM.Delete(&torrentReport).Error; err != nil {
|
||||
return err, http.StatusInternalServerError
|
||||
return &torrentReport, err, http.StatusInternalServerError
|
||||
}
|
||||
return nil, http.StatusOK
|
||||
return &torrentReport, nil, http.StatusOK
|
||||
}
|
||||
|
||||
// DeleteDefinitelyTorrentReport : Delete definitely a torrent report by id
|
||||
|
|
|
@ -41,10 +41,10 @@ func New(fetcherConfig *config.MetainfoFetcherConfig) (*MetainfoFetcher, error)
|
|||
|
||||
// Well, it seems this is the right way to convert speed -> rate.Limiter
|
||||
// https://github.com/anacrolix/torrent/blob/master/cmd/torrent/main.go
|
||||
const uploadBurst = 0x40000 // 256K
|
||||
const uploadBurst = 0x40000 // 256K
|
||||
const downloadBurst = 0x100000 // 1M
|
||||
uploadLimit := fetcherConfig.UploadRateLimitKiB*1024
|
||||
downloadLimit := fetcherConfig.DownloadRateLimitKiB*1024
|
||||
uploadLimit := fetcherConfig.UploadRateLimitKiB * 1024
|
||||
downloadLimit := fetcherConfig.DownloadRateLimitKiB * 1024
|
||||
if uploadLimit > 0 {
|
||||
limit := rate.Limit(uploadLimit)
|
||||
limiter := rate.NewLimiter(limit, uploadBurst)
|
||||
|
@ -170,7 +170,7 @@ func (fetcher *MetainfoFetcher) gotResult(r Result) {
|
|||
if r.operation.torrent.Filesize != r.info.TotalLength() {
|
||||
log.Infof("Got length %d for torrent TID: %d. Updating.", r.info.TotalLength(), r.operation.torrent.ID)
|
||||
r.operation.torrent.Filesize = r.info.TotalLength()
|
||||
_, err := torrentService.UpdateTorrent(r.operation.torrent)
|
||||
_, err := torrentService.UpdateTorrent(&r.operation.torrent)
|
||||
if err != nil {
|
||||
log.Infof("Failed to update torrent TID: %d with new filesize", r.operation.torrent.ID)
|
||||
lengthOK = false
|
||||
|
@ -217,7 +217,7 @@ func (fetcher *MetainfoFetcher) removeOldFailures() {
|
|||
// | 3 | 8 * base
|
||||
// integers inside fetcher.numFails are never less than or equal to zero
|
||||
mul := 1 << uint(fetcher.numFails[id]-1)
|
||||
cd := time.Duration(mul * fetcher.baseFailCooldown) * time.Second
|
||||
cd := time.Duration(mul*fetcher.baseFailCooldown) * time.Second
|
||||
if cd > max {
|
||||
cd = max
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package torrentService
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -11,6 +12,7 @@ import (
|
|||
"github.com/NyaaPantsu/nyaa/db"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
"github.com/NyaaPantsu/nyaa/service"
|
||||
"github.com/NyaaPantsu/nyaa/service/activity"
|
||||
"github.com/NyaaPantsu/nyaa/service/notifier"
|
||||
"github.com/NyaaPantsu/nyaa/service/user"
|
||||
"github.com/NyaaPantsu/nyaa/service/user/permission"
|
||||
|
@ -192,13 +194,13 @@ func GetAllTorrentsDB() ([]model.Torrent, int, error) {
|
|||
}
|
||||
|
||||
// DeleteTorrent : delete a torrent based on id
|
||||
func DeleteTorrent(id string) (int, error) {
|
||||
func DeleteTorrent(id string) (*model.Torrent, int, error) {
|
||||
var torrent model.Torrent
|
||||
if db.ORM.First(&torrent, id).RecordNotFound() {
|
||||
return http.StatusNotFound, errors.New("Torrent is not found")
|
||||
return &torrent, http.StatusNotFound, errors.New("Torrent is not found")
|
||||
}
|
||||
if db.ORM.Delete(&torrent).Error != nil {
|
||||
return http.StatusInternalServerError, errors.New("Torrent was not deleted")
|
||||
return &torrent, http.StatusInternalServerError, errors.New("Torrent was not deleted")
|
||||
}
|
||||
|
||||
if db.ElasticSearchClient != nil {
|
||||
|
@ -209,17 +211,17 @@ func DeleteTorrent(id string) (int, error) {
|
|||
log.Errorf("Unable to delete torrent to ES index: %s", err)
|
||||
}
|
||||
}
|
||||
return http.StatusOK, nil
|
||||
return &torrent, http.StatusOK, nil
|
||||
}
|
||||
|
||||
// DefinitelyDeleteTorrent : deletes definitely a torrent based on id
|
||||
func DefinitelyDeleteTorrent(id string) (int, error) {
|
||||
func DefinitelyDeleteTorrent(id string) (*model.Torrent, int, error) {
|
||||
var torrent model.Torrent
|
||||
if db.ORM.Unscoped().Model(&torrent).First(&torrent, id).RecordNotFound() {
|
||||
return http.StatusNotFound, errors.New("Torrent is not found")
|
||||
return &torrent, http.StatusNotFound, errors.New("Torrent is not found")
|
||||
}
|
||||
if db.ORM.Unscoped().Model(&torrent).Delete(&torrent).Error != nil {
|
||||
return http.StatusInternalServerError, errors.New("Torrent was not deleted")
|
||||
return &torrent, http.StatusInternalServerError, errors.New("Torrent was not deleted")
|
||||
}
|
||||
|
||||
if db.ElasticSearchClient != nil {
|
||||
|
@ -230,7 +232,7 @@ func DefinitelyDeleteTorrent(id string) (int, error) {
|
|||
log.Errorf("Unable to delete torrent to ES index: %s", err)
|
||||
}
|
||||
}
|
||||
return http.StatusOK, nil
|
||||
return &torrent, http.StatusOK, nil
|
||||
}
|
||||
|
||||
// ToggleBlockTorrent ; Lock/Unlock a torrent based on id
|
||||
|
@ -251,8 +253,27 @@ func ToggleBlockTorrent(id string) (model.Torrent, int, error) {
|
|||
}
|
||||
|
||||
// UpdateTorrent : Update a torrent based on model
|
||||
func UpdateTorrent(torrent model.Torrent) (int, error) {
|
||||
if db.ORM.Model(&torrent).UpdateColumn(&torrent).Error != nil {
|
||||
func UpdateTorrent(torrent *model.Torrent) (int, error) {
|
||||
if db.ORM.Model(torrent).UpdateColumn(torrent).Error != nil {
|
||||
return http.StatusInternalServerError, errors.New("Torrent was not updated")
|
||||
}
|
||||
|
||||
// TODO Don't create a new client for each request
|
||||
if db.ElasticSearchClient != nil {
|
||||
err := torrent.AddToESIndex(db.ElasticSearchClient)
|
||||
if err == nil {
|
||||
log.Infof("Successfully updated torrent to ES index.")
|
||||
} else {
|
||||
log.Errorf("Unable to update torrent to ES index: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return http.StatusOK, nil
|
||||
}
|
||||
|
||||
// UpdateUnscopeTorrent : Update a torrent based on model
|
||||
func UpdateUnscopeTorrent(torrent *model.Torrent) (int, error) {
|
||||
if db.ORM.Unscoped().Model(torrent).UpdateColumn(torrent).Error != nil {
|
||||
return http.StatusInternalServerError, errors.New("Torrent was not updated")
|
||||
}
|
||||
|
||||
|
@ -281,10 +302,11 @@ func ExistOrDelete(hash string, user *model.User) error {
|
|||
db.ORM.Unscoped().Model(&model.Torrent{}).Where("torrent_hash = ?", hash).First(&torrentIndb)
|
||||
if torrentIndb.ID > 0 {
|
||||
if userPermission.CurrentUserIdentical(user, torrentIndb.UploaderID) && torrentIndb.IsDeleted() && !torrentIndb.IsBlocked() { // if torrent is not locked and is deleted and the user is the actual owner
|
||||
_, err := DefinitelyDeleteTorrent(strconv.Itoa(int(torrentIndb.ID)))
|
||||
torrent, _, err := DefinitelyDeleteTorrent(strconv.Itoa(int(torrentIndb.ID)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
activity.Log(&model.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), torrent.Uploader.Username, user.Username)
|
||||
} else {
|
||||
return errors.New("Torrent already in database")
|
||||
}
|
||||
|
@ -312,3 +334,26 @@ func NewTorrentEvent(router *mux.Router, user *model.User, torrent *model.Torren
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HideTorrentUser : hides a torrent user for hidden torrents
|
||||
func HideTorrentUser(uploaderID uint, uploaderName string, torrentHidden bool) (uint, string) {
|
||||
if torrentHidden {
|
||||
return 0, "れんちょん"
|
||||
}
|
||||
if uploaderID == 0 {
|
||||
return 0, "れんちょん"
|
||||
}
|
||||
return uploaderID, uploaderName
|
||||
}
|
||||
|
||||
// TorrentsToAPI : Map Torrents for API usage without reallocations
|
||||
func TorrentsToAPI(t []model.Torrent) []model.TorrentJSON {
|
||||
json := make([]model.TorrentJSON, len(t))
|
||||
for i := range t {
|
||||
json[i] = t[i].ToJSON()
|
||||
uploaderID, username := HideTorrentUser(json[i].UploaderID, string(json[i].UploaderName), json[i].Hidden)
|
||||
json[i].UploaderName = template.HTML(username)
|
||||
json[i].UploaderID = uploaderID
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
|
22
templates/activity_list.html
Fichier normal
22
templates/activity_list.html
Fichier normal
|
@ -0,0 +1,22 @@
|
|||
{{define "title"}}{{ call $.T "activity_list" }}{{end}}
|
||||
{{define "contclass"}}cont-home{{end}}
|
||||
{{define "content"}}
|
||||
<div class="results box">
|
||||
<table>
|
||||
<thead class="torrent-info">
|
||||
<tr>
|
||||
<th class="tr-name">{{ call $.T "activities" }}</th>
|
||||
<th class="tr-size">{{ call $.T "filter" }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{ range .Models}}
|
||||
<tr>
|
||||
<td class="tr-name home-td"><a>{{ genActivityContent . $.T }}</a></td>
|
||||
<td class="tr-actions home-td"><a href="{{ genRoute "activity_list" }}?filter={{.Filter}}" class="form-input">{{ call $.T .Filter }}</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
|
@ -17,7 +17,7 @@
|
|||
<!-- TODO: add href="{{ genRoute "mod_cedit" }}?id={{.ID}}" for comment editing -->
|
||||
<td class="tr-name home-td"><a>{{ .Content }}</a></td>
|
||||
<td class="tr-size home-td"><a href="{{ genViewTorrentRoute .TorrentID }}">{{ .TorrentID }}</a></td>
|
||||
<td class="tr-size home-td">{{ .UserID }}</td>
|
||||
<td class="tr-size home-td">{{if .User }}{{ .User.Username }}{{else}}れんちょん{{end}}</td>
|
||||
<td class="tr-actions home-td"><a href="{{ genRoute "mod_cdelete" }}?id={{.ID}}" class="form-input btn-red" onclick="if (!confirm('{{ call $.T "are_you_sure" }}')) return false;"><i class="trash-icon"></i> {{ call $.T "delete" }}</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
{{range .Comments}}
|
||||
<tr>
|
||||
<td class="tr-name home-td"><a href="{{ genRoute "mod_cedit" }}?id={{.ID}}">{{ .Content }}</a></td>
|
||||
<td class="tr-size home-td"><a href="{{ genRoute "mod_cedit" }}?id={{.ID}}">{{.UserID}}</a></td>
|
||||
<td class="tr-size home-td"><a href="{{ genRoute "mod_cedit" }}?id={{.ID}}">{{if .User }}{{ .User.Username }}{{else}}れんちょん{{end}}</a></td>
|
||||
<td class="tr-size home-td"><a href="{{ genRoute "mod_cdelete" }}?id={{ .ID }}" class="form-input btn-red" onclick="if (!confirm('{{ call $.T "are_you_sure" }}')) return false;"><i class="trash-icon"></i> {{ call $.T "delete" }}</a></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
|
|
@ -859,6 +859,22 @@
|
|||
"id": "torrent_deleted",
|
||||
"translation": "Torrent %s deleted!"
|
||||
},
|
||||
{
|
||||
"id": "torrent_deleted_by",
|
||||
"translation": "Torrent #%s from %s has been deleted by %s."
|
||||
},
|
||||
{
|
||||
"id": "torrent_edited_by",
|
||||
"translation": "Torrent #%s from %s has been edited by %s."
|
||||
},
|
||||
{
|
||||
"id": "torrent_blocked_by",
|
||||
"translation": "Torrent #%s from %s has been locked by %s."
|
||||
},
|
||||
{
|
||||
"id": "torrent_blocked_by",
|
||||
"translation": "Torrent #%s from %s has been unlocked by %s."
|
||||
},
|
||||
{
|
||||
"id": "torrents_deleted",
|
||||
"translation": "Torrents Deleted"
|
||||
|
@ -871,6 +887,14 @@
|
|||
"id": "delete_report",
|
||||
"translation": "Delete Report"
|
||||
},
|
||||
{
|
||||
"id": "comment_deleted_by",
|
||||
"translation": "Comment #%s from %s has been deleted by %s."
|
||||
},
|
||||
{
|
||||
"id": "comment_edited_by",
|
||||
"translation": "Comment #%s from %s has been edited by %s."
|
||||
},
|
||||
{
|
||||
"id": "no_action_exist",
|
||||
"translation": "No such action %s exist!"
|
||||
|
@ -1334,5 +1358,17 @@
|
|||
{
|
||||
"id": "language_multiple_name",
|
||||
"translation": "Multiple Languages"
|
||||
},
|
||||
{
|
||||
"id": "activity_list",
|
||||
"translation": "Activity List"
|
||||
},
|
||||
{
|
||||
"id": "activities",
|
||||
"translation": "Activities"
|
||||
},
|
||||
{
|
||||
"id": "filter",
|
||||
"translation": "Filter"
|
||||
}
|
||||
]
|
||||
|
|
Référencer dans un nouveau ticket