Albirew/nyaa-pantsu
Archivé
1
0
Bifurcation 0

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 à :
akuma06 2017-06-15 04:44:46 +02:00 révisé par ewhal
Parent 02c3474b3e
révision 93364dac77
20 fichiers modifiés avec 319 ajouts et 53 suppressions

Voir le fichier

@ -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"

Voir le fichier

@ -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

Voir le fichier

@ -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
Voir le fichier

@ -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
Voir le fichier

@ -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)
}

Voir le fichier

@ -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)
}

Voir le fichier

@ -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)

Voir le fichier

@ -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")

Voir le fichier

@ -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")

Voir le fichier

@ -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)
},
}

Voir le fichier

@ -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
Voir le fichier

@ -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
}

Voir le fichier

@ -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
}

Voir le fichier

@ -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

Voir le fichier

@ -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

Voir le fichier

@ -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
Voir le fichier

@ -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}}

Voir le fichier

@ -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}}

Voir le fichier

@ -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}}

Voir le fichier

@ -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"
}
]