Janitor (#1728)
* Fix "torrent is being generated" message showing up even when the torrent couldn't be generated * Add janitor user status * Remove usage of deprecated HasAdmin() function * Give Janitors access to mod panel * Stop using deprecated HasAdmin() function * Stop using deprecated HasAdmin() function * Update edit.go * Update profile.go * Rollback bad changes, remove redundant email check and stop using deprecated function * Show every userstatus (member, janitor, banned, mod) in comments * Return empty status if anonymous * Show no userstatus for anonymous profile * Show moderation link to janitors too * Stop using deprecated HasAdmin() function * Stop using deprecated HasAdmin() function * Stop using deprecated HasAdmin() function * Add Janitor to userstatus select in user edit * "Janitor" translation string * didnt mean to commit this change * rollback wrongfully comitted changes * rollback commit * Update CHANGELOG.md * Fix wrong id for translation * remove deprecated HasAdmin() function again * change name of variable used in comment loop for clarity purposes * visual cue for locked torrents in torrent listing for admins * add visual cues for hidden torrents in admin torrent listing * Dont show delete buttons for janitors * janitor cannot delete torrents * show block/unblock button in torrent list for janitors instead of delete button * fix function that didnt get executed * add ban buttons on userlist & visual cue for banned users * Fix "user successfully deleted" message showing even if user wasnt deleted * Add "ban" button, no "delete" button for jantiors * add "unban" and "ban" translation strings * add "unban" and "ban" translation strings * different <form> for ban button * Update index.jet.html * add userprofile ban route * add toggleBan() function, janitors dont need captcha either * fix panic error when deleting an anonymous comment * add user_banned_by and user_unbanned_by * add user_banned_by and user_unbanned_by * Make ToggleBan() return whether or not the user is now banned * Add handler for /ban route * change log filter * hide locked torrents from regular users * hide locked torrents from regular users * hide locked torrent from api search for regular users * change function to CurrentOrJanitor * change function to currentorjanitor * change function to currentorjanitor * add CurrentOrJanitor function * fix extra ( * fix extra ) and wrong variable name * Fix wrong value for janitor user status * Fix user edit that did not work because of "unique constraint user.emails" error * only immediately visually update user if user has been updated successfully * use FindAllForAdminsOrderBy in order to preload users * create FindAllForAdminsOrderBy that preloads users * Show username instead of ID in Uploader column in admin panel * Fix userprofile buttons overflowing at some specific resolutions * Mods can set users as janitors * Show ban/unban buttons on userprofile for janitors * Identical styling for usermenu links and buttons * dont show ban buttons on other staff * add ban message through get parameter * make toggleBan() trigger user update * Add "user_banned" and "user_unbanned" * add "user_banned" and "user_unbanned" * Visual cue for banned user * banned users can still log in * visual cue for banned user in badgemenu * locked status if banned user on upload * banned users cannot comment * Put "banned" text between () * add GetCategoryName() to template_test * add GetCategoryName() that returns full category name from full category string * Show search content in page title if it exists, or search category if it exists, otherwise shows "Home" * error message when user uploads an torrent & is banned * add torrent_uploaded_locked * add torrent_uploaded_locked * fix delete definitely button that never appeared * Show delete definitely button on admin panel index * admins can undelete a torrent by editing it's status * Trigger ViewHandler() directly instead of redirecting * Render the template directly instead of triggering torrent view handler * bigger usermenu buttons once responsive design kicks in * make btn-* class non-bold * Responsive notification page * visual cue for locked torrents in torrent listing * Update search.go * Update search.go * Update api.go * Update helpers.go * Update template.go * Update torrentParam.go * remove "hidden" class * Update search.go * fix an html error * Add files via upload * Update admin.jet.html * Update index.go * Update index.go * Update router.go * Update torrentParam_test.go * Update torrentParam_test.go * fix extra " * fix bad copypaste * Update CHANGELOG.md * Update guidelines.jet.html * Update CHANGELOG.md * add Guidelines and Moderation Guidelines * fix missing commas * Update torrentlist.jet.html * Update find.go * Update stats.go * Update view.jet.html * Update index.jet.html
Cette révision appartient à :
Parent
ca2f5d3c42
révision
5dcd30676f
|
@ -32,7 +32,7 @@ func ActivityListHandler(c *gin.Context) {
|
|||
}
|
||||
var conditions []string
|
||||
var values []interface{}
|
||||
if userid != "" && currentUser.HasAdmin() {
|
||||
if userid != "" && currentUser.IsModerator() {
|
||||
conditions = append(conditions, "user_id = ?")
|
||||
values = append(values, userid)
|
||||
}
|
||||
|
|
|
@ -433,7 +433,7 @@ func APISearchHandler(c *gin.Context) {
|
|||
userID = 0
|
||||
}
|
||||
|
||||
_, torrentSearch, nbTorrents, err := search.AuthorizedQuery(c, pagenum, currentUser.CurrentOrAdmin(uint(userID)))
|
||||
_, torrentSearch, nbTorrents, err := search.AuthorizedQuery(c, pagenum, currentUser.CurrentOrJanitor(uint(userID)), currentUser.CurrentOrJanitor(uint(userID)))
|
||||
|
||||
if err != nil {
|
||||
c.AbortWithError(http.StatusInternalServerError, err)
|
||||
|
|
|
@ -86,7 +86,7 @@ func getTorrentList(c *gin.Context) (torrents []models.Torrent, createdAsTime ti
|
|||
user = 0
|
||||
}
|
||||
|
||||
_, torrents, _, err = search.AuthorizedQuery(c, pagenum, currentUser.CurrentOrAdmin(uint(user)))
|
||||
_, torrents, _, err = search.AuthorizedQuery(c, pagenum, currentUser.CurrentOrJanitor(uint(user)), currentUser.CurrentOrJanitor(uint(user)))
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func ErrorMiddleware() gin.HandlerFunc {
|
|||
func ModMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
currentUser := router.GetUser(c)
|
||||
if !currentUser.HasAdmin() {
|
||||
if !currentUser.IsJanitor() {
|
||||
NotFoundHandler(c)
|
||||
}
|
||||
c.Next()
|
||||
|
|
|
@ -61,10 +61,19 @@ func CommentsListPanel(c *gin.Context) {
|
|||
|
||||
// CommentDeleteModPanel : Controller for deleting a comment
|
||||
func CommentDeleteModPanel(c *gin.Context) {
|
||||
id, _ := strconv.ParseInt(c.PostForm("id"), 10, 32)
|
||||
id, err := strconv.ParseInt(c.PostForm("id"), 10, 32)
|
||||
if err != nil {
|
||||
c.Redirect(http.StatusSeeOther, "/mod/comments")
|
||||
return
|
||||
}
|
||||
|
||||
comment, _, err := comments.Delete(uint(id))
|
||||
if err == nil {
|
||||
activities.Log(&models.User{}, comment.Identifier(), "delete", "comment_deleted_by", strconv.Itoa(int(comment.ID)), comment.User.Username, router.GetUser(c).Username)
|
||||
username := "れんちょん"
|
||||
if comment.UserID != 0 {
|
||||
username = comment.User.Username
|
||||
}
|
||||
activities.Log(&models.User{}, comment.Identifier(), "delete", "comment_deleted_by", strconv.Itoa(int(comment.ID)), username, router.GetUser(c).Username)
|
||||
}
|
||||
|
||||
c.Redirect(http.StatusSeeOther, "/mod/comments?deleted")
|
||||
|
|
|
@ -53,7 +53,7 @@ func torrentManyAction(c *gin.Context) {
|
|||
messages.AddErrorTf("errors", "no_status_exist", status)
|
||||
status = -1
|
||||
}
|
||||
if !currentUser.HasAdmin() {
|
||||
if !currentUser.IsModerator() {
|
||||
if c.PostForm("status") != "" { // Condition to check if a user try to change torrent status without having the right permission
|
||||
if (status == models.TorrentStatusTrusted && !currentUser.IsTrusted()) || status == models.TorrentStatusAPlus || status == 0 {
|
||||
status = models.TorrentStatusNormal
|
||||
|
@ -64,7 +64,7 @@ func torrentManyAction(c *gin.Context) {
|
|||
}
|
||||
withReport = false // Users should not be able to remove reports
|
||||
}
|
||||
if c.PostForm("owner") != "" && currentUser.HasAdmin() { // We check that the user given exist and if not we return an error
|
||||
if c.PostForm("owner") != "" && currentUser.IsModerator() { // We check that the user given exist and if not we return an error
|
||||
_, _, errorUser := users.FindForAdmin(uint(owner))
|
||||
if errorUser != nil {
|
||||
messages.AddErrorTf("errors", "no_user_found_id", owner)
|
||||
|
|
|
@ -13,10 +13,14 @@ import (
|
|||
// IndexModPanel : Controller for showing index page of Mod Panel
|
||||
func IndexModPanel(c *gin.Context) {
|
||||
offset := 10
|
||||
torrents, _, _ := torrents.FindAllOrderBy("torrent_id DESC", offset, 0)
|
||||
torrents, _, _ := torrents.FindAllForAdminsOrderBy("torrent_id DESC", offset, 0)
|
||||
users, _ := users.FindUsersForAdmin(offset, 0)
|
||||
comments, _ := comments.FindAll(offset, 0, "", "")
|
||||
torrentReports, _, _ := reports.GetAll(offset, 0)
|
||||
|
||||
templates.PanelAdmin(c, torrents, models.TorrentReportsToJSON(torrentReports), users, comments)
|
||||
}
|
||||
|
||||
func GuidelinesModPanel(c *gin.Context) {
|
||||
templates.Static(c, "admin/guidelines.jet.html")
|
||||
}
|
||||
|
|
|
@ -46,8 +46,11 @@ func init() {
|
|||
modRoutes.GET("/torrent", TorrentEditModPanel)
|
||||
modRoutes.POST("/torrent", TorrentPostEditModPanel)
|
||||
|
||||
/* Torrent delete routes */
|
||||
/* Torrent delete routs */
|
||||
modRoutes.POST("/torrent/delete", TorrentDeleteModPanel)
|
||||
|
||||
/* Guidelines route */
|
||||
modRoutes.Any("/guidelines", GuidelinesModPanel)
|
||||
|
||||
/* Announcement edit view */
|
||||
modRoutes.GET("/announcement/form", addAnnouncement)
|
||||
|
|
|
@ -120,38 +120,43 @@ func TorrentPostEditModPanel(c *gin.Context) {
|
|||
|
||||
// TorrentDeleteModPanel : Controller for deleting a torrent
|
||||
func TorrentDeleteModPanel(c *gin.Context) {
|
||||
id, _ := strconv.ParseInt(c.PostForm("id"), 10, 32)
|
||||
definitely := c.Request.URL.Query()["definitely"]
|
||||
|
||||
var returnRoute = "/mod/torrents"
|
||||
torrent, errFind := torrents.FindByID(uint(id))
|
||||
if errFind == nil {
|
||||
var err error
|
||||
if definitely != nil {
|
||||
_, _, err = torrent.DefinitelyDelete()
|
||||
returnRoute = "/mod/torrents/deleted"
|
||||
} else {
|
||||
_, _, err = torrent.Delete(false)
|
||||
}
|
||||
|
||||
//delete reports of torrent
|
||||
query := &search.Query{}
|
||||
query.Append("torrent_id", id)
|
||||
reports, _, _ := reports.FindOrderBy(query, "", 0, 0)
|
||||
for _, report := range reports {
|
||||
report.Delete()
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
if torrent.Uploader == nil {
|
||||
torrent.Uploader = &models.User{}
|
||||
currentUser := router.GetUser(c)
|
||||
|
||||
if currentUser.IsModerator() {
|
||||
id, _ := strconv.ParseInt(c.PostForm("id"), 10, 32)
|
||||
definitely := c.Request.URL.Query()["definitely"]
|
||||
|
||||
torrent, errFind := torrents.FindByID(uint(id))
|
||||
if errFind == nil {
|
||||
var err error
|
||||
if definitely != nil {
|
||||
_, _, err = torrent.DefinitelyDelete()
|
||||
returnRoute = "/mod/torrents/deleted"
|
||||
} else {
|
||||
_, _, err = torrent.Delete(false)
|
||||
}
|
||||
|
||||
//delete reports of torrent
|
||||
query := &search.Query{}
|
||||
query.Append("torrent_id", id)
|
||||
reports, _, _ := reports.FindOrderBy(query, "", 0, 0)
|
||||
for _, report := range reports {
|
||||
report.Delete()
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
if torrent.Uploader == nil {
|
||||
torrent.Uploader = &models.User{}
|
||||
}
|
||||
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
|
||||
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, currentUser.Username)
|
||||
}
|
||||
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
|
||||
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, router.GetUser(c).Username)
|
||||
}
|
||||
c.Redirect(http.StatusSeeOther, returnRoute+"?deleted")
|
||||
}
|
||||
|
||||
c.Redirect(http.StatusSeeOther, returnRoute+"?deleted")
|
||||
c.Redirect(http.StatusSeeOther, returnRoute)
|
||||
}
|
||||
|
||||
// DeleteTagsModPanel : Controller for deleting all torrent tags
|
||||
|
|
|
@ -76,7 +76,7 @@ func SearchHandler(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
searchParam, torrents, nbTorrents, err := search.AuthorizedQuery(c, pagenum, currentUser.CurrentOrAdmin(uint(userID)))
|
||||
searchParam, torrents, nbTorrents, err := search.AuthorizedQuery(c, pagenum, currentUser.CurrentOrJanitor(uint(userID)), currentUser.IsJanitor())
|
||||
if err != nil {
|
||||
c.AbortWithError(http.StatusInternalServerError, err)
|
||||
return
|
||||
|
|
|
@ -10,8 +10,10 @@ import (
|
|||
"github.com/NyaaPantsu/nyaa/models/comments"
|
||||
"github.com/NyaaPantsu/nyaa/models/torrents"
|
||||
"github.com/NyaaPantsu/nyaa/utils/captcha"
|
||||
"github.com/NyaaPantsu/nyaa/utils/filelist"
|
||||
msg "github.com/NyaaPantsu/nyaa/utils/messages"
|
||||
"github.com/NyaaPantsu/nyaa/utils/sanitize"
|
||||
"github.com/NyaaPantsu/nyaa/templates"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
|
@ -34,6 +36,9 @@ func PostCommentHandler(c *gin.Context) {
|
|||
messages.AddErrorT("errors", "bad_captcha")
|
||||
}
|
||||
}
|
||||
if currentUser.IsBanned() {
|
||||
messages.AddErrorT("errors", "account_banned")
|
||||
}
|
||||
content := sanitize.Sanitize(c.PostForm("comment"), "comment")
|
||||
|
||||
userID := currentUser.ID
|
||||
|
@ -54,6 +59,13 @@ func PostCommentHandler(c *gin.Context) {
|
|||
messages.Error(err)
|
||||
}
|
||||
}
|
||||
url := "/view/" + strconv.FormatUint(uint64(torrent.ID), 10)
|
||||
c.Redirect(302, url)
|
||||
|
||||
captchaID := ""
|
||||
//Generate a captcha
|
||||
if currentUser.NeedsCaptcha() {
|
||||
captchaID = captcha.GetID()
|
||||
}
|
||||
|
||||
folder := filelist.FileListToFolder(torrent.FileList, "root")
|
||||
templates.Torrent(c, torrent.ToJSON(), folder, captchaID)
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ func TorrentDeleteUserPanel(c *gin.Context) {
|
|||
torrent.Uploader = &models.User{}
|
||||
}
|
||||
_, username := torrents.HideUser(torrent.UploaderID, torrent.Uploader.Username, torrent.Hidden)
|
||||
if currentUser.HasAdmin() { // We hide username on log activity if user is not admin and torrent is hidden
|
||||
if currentUser.IsModerator() { // We hide username on log activity if user is not admin and torrent is hidden
|
||||
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, currentUser.Username)
|
||||
} else {
|
||||
activities.Log(&models.User{}, torrent.Identifier(), "delete", "torrent_deleted_by", strconv.Itoa(int(torrent.ID)), username, username)
|
||||
|
|
|
@ -52,7 +52,7 @@ func TorrentPostEditUserPanel(c *gin.Context) {
|
|||
messages.AddErrorT("errors", "fail_torrent_update")
|
||||
}
|
||||
if !messages.HasErrors() {
|
||||
upload.UpdateTorrent(&uploadForm, torrent, currentUser).Update(currentUser.HasAdmin())
|
||||
upload.UpdateTorrent(&uploadForm, torrent, currentUser).Update(currentUser.IsModerator())
|
||||
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/view/%d?success_edit", id))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -45,16 +45,16 @@ func GetStatsHandler(c *gin.Context) {
|
|||
if len(torrent.Trackers) > 3 {
|
||||
for _, line := range strings.Split(torrent.Trackers[3:], "&tr=") {
|
||||
tracker, error := url.QueryUnescape(line)
|
||||
if error == nil && strings.Contains(tracker, "udp://") {
|
||||
if error == nil && strings.HasPrefix(tracker, "udp") {
|
||||
Trackers = append(Trackers, tracker)
|
||||
}
|
||||
//Cannot scrape from http trackers so don't put them in the array
|
||||
}
|
||||
}
|
||||
|
||||
for _, line := range config.Get().Torrents.Trackers.Default {
|
||||
if !contains(Trackers, line) {
|
||||
Trackers = append(Trackers, line)
|
||||
for _, tracker := range config.Get().Torrents.Trackers.Default {
|
||||
if !contains(Trackers, tracker) && strings.HasPrefix(tracker, "udp") {
|
||||
Trackers = append(Trackers, tracker)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,23 +20,6 @@ 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))
|
||||
|
||||
|
@ -66,6 +49,27 @@ func ViewHandler(c *gin.Context) {
|
|||
captchaID = captcha.GetID()
|
||||
}
|
||||
|
||||
// Display success message on upload
|
||||
if c.Request.URL.Query()["success"] != nil {
|
||||
if torrent.IsBlocked() {
|
||||
messages.AddInfoT("infos", "torrent_uploaded_locked")
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
|
||||
if c.Request.URL.Query()["followed"] != nil {
|
||||
messages.AddInfoTf("infos", "user_followed_msg", b.UploaderName)
|
||||
}
|
||||
|
|
|
@ -58,6 +58,8 @@ func UploadPostHandler(c *gin.Context) {
|
|||
uploadForm.Status = models.TorrentStatusRemake
|
||||
} else if user.IsTrusted() {
|
||||
uploadForm.Status = models.TorrentStatusTrusted
|
||||
} else if user.IsBanned() {
|
||||
uploadForm.Status = models.TorrentStatusBlocked
|
||||
}
|
||||
|
||||
err = torrents.ExistOrDelete(uploadForm.Infohash, user)
|
||||
|
|
|
@ -7,9 +7,12 @@ import (
|
|||
|
||||
"net/http"
|
||||
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/controllers/router"
|
||||
"github.com/NyaaPantsu/nyaa/models/notifications"
|
||||
"github.com/NyaaPantsu/nyaa/models/activities"
|
||||
"github.com/NyaaPantsu/nyaa/models/users"
|
||||
"github.com/NyaaPantsu/nyaa/models"
|
||||
"github.com/NyaaPantsu/nyaa/templates"
|
||||
"github.com/NyaaPantsu/nyaa/utils/cookies"
|
||||
"github.com/NyaaPantsu/nyaa/utils/crypto"
|
||||
|
@ -33,8 +36,36 @@ func UserProfileDelete(c *gin.Context) {
|
|||
if err == nil && currentUser.CurrentUserIdentical(userProfile.ID) {
|
||||
cookies.Clear(c)
|
||||
}
|
||||
}
|
||||
templates.Static(c, "site/static/delete_success.jet.html")
|
||||
}
|
||||
} else {
|
||||
c.AbortWithStatus(http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
// UserProfileBan : Ban an User
|
||||
func UserProfileBan(c *gin.Context) {
|
||||
currentUser := router.GetUser(c)
|
||||
|
||||
if currentUser.IsJanitor() {
|
||||
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
|
||||
userProfile, _, errorUser := users.FindForAdmin(uint(id))
|
||||
if errorUser == nil && !userProfile.IsModerator() {
|
||||
action := "user_unbanned_by"
|
||||
message := "?unbanned"
|
||||
if userProfile.ToggleBan() {
|
||||
action = "user_banned_by"
|
||||
message = "?banned"
|
||||
}
|
||||
|
||||
activities.Log(&models.User{}, fmt.Sprintf("user_%d", id), "edit", action, userProfile.Username, strconv.Itoa(int(id)), currentUser.Username)
|
||||
c.Redirect(http.StatusSeeOther, fmt.Sprintf("/user/%d/%s", id, c.Param("username") + message))
|
||||
} else {
|
||||
c.AbortWithStatus(http.StatusNotFound)
|
||||
}
|
||||
} else {
|
||||
c.AbortWithStatus(http.StatusNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,7 +181,7 @@ func UserDetailsHandler(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// UserProfileFormHandler : Getting View User Profile Update
|
||||
// UserProfileFormHandler : Updating User Profile
|
||||
func UserProfileFormHandler(c *gin.Context) {
|
||||
id, _ := strconv.ParseUint(c.Param("id"), 10, 32)
|
||||
currentUser := router.GetUser(c)
|
||||
|
@ -178,21 +209,21 @@ func UserProfileFormHandler(c *gin.Context) {
|
|||
if !messages.HasErrors() {
|
||||
c.Bind(&userForm)
|
||||
c.Bind(&userSettingsForm)
|
||||
if !currentUser.HasAdmin() {
|
||||
if !currentUser.IsModerator() {
|
||||
userForm.Username = userProfile.Username
|
||||
userForm.Status = userProfile.Status
|
||||
} else {
|
||||
if userProfile.Status != userForm.Status && userForm.Status == 2 {
|
||||
if userProfile.Status != userForm.Status && (userForm.Status == 2){
|
||||
messages.AddErrorT("errors", "elevating_user_error")
|
||||
}
|
||||
}
|
||||
validator.ValidateForm(&userForm, messages)
|
||||
if !messages.HasErrors() {
|
||||
if userForm.Email != userProfile.Email {
|
||||
if currentUser.HasAdmin() {
|
||||
userProfile.Email = userForm.Email
|
||||
if currentUser.IsModerator() {
|
||||
userProfile.Email = userForm.Email // reset, it will be set when user clicks verification
|
||||
} else {
|
||||
email.SendVerificationToUser(currentUser, userForm.Email)
|
||||
email.SendVerificationToUser(userProfile, userForm.Email)
|
||||
messages.AddInfoTf("infos", "email_changed", userForm.Email)
|
||||
userForm.Email = userProfile.Email // reset, it will be set when user clicks verification
|
||||
}
|
||||
|
@ -201,10 +232,7 @@ func UserProfileFormHandler(c *gin.Context) {
|
|||
if err != nil {
|
||||
messages.Error(err)
|
||||
}
|
||||
if userForm.Email != user.Email {
|
||||
// send verification to new email and keep old
|
||||
email.SendVerificationToUser(user, userForm.Email)
|
||||
}
|
||||
|
||||
if !messages.HasErrors() {
|
||||
messages.AddInfoT("infos", "profile_updated")
|
||||
userProfile = user
|
||||
|
|
|
@ -38,6 +38,7 @@ func init() {
|
|||
userRoutes.GET("/:id/:username/feed", feedController.RSSHandler)
|
||||
userRoutes.GET("/:id/:username/feed/:page", feedController.RSSHandler)
|
||||
userRoutes.POST("/:id/:username/delete", UserProfileDelete)
|
||||
userRoutes.POST("/:id/:username/ban", UserProfileBan)
|
||||
}
|
||||
|
||||
router.Get().Any("/username", RedirectToUserSearch)
|
||||
|
|
|
@ -312,17 +312,7 @@ func (t *Torrent) ToJSON() TorrentJSON {
|
|||
}
|
||||
for _, c := range t.Comments {
|
||||
if c.User != nil {
|
||||
userStatus := ""
|
||||
if c.User.IsBanned() {
|
||||
userStatus = "userstatus_banned"
|
||||
}
|
||||
if c.User.HasAdmin() {
|
||||
userStatus = "userstatus_moderator"
|
||||
}
|
||||
if c.User.ID == t.ID {
|
||||
userStatus = "userstatus_uploader"
|
||||
}
|
||||
commentsJSON = append(commentsJSON, CommentJSON{Username: c.User.Username, UserID: int(c.User.ID), UserStatus: userStatus, Content: sanitize.MarkdownToHTML(c.Content), Date: c.CreatedAt.UTC(), UserAvatar: c.User.MD5})
|
||||
commentsJSON = append(commentsJSON, CommentJSON{Username: c.User.Username, UserID: int(c.User.ID), UserStatus: c.User.GetRole(), Content: sanitize.MarkdownToHTML(c.Content), Date: c.CreatedAt.UTC(), UserAvatar: c.User.MD5})
|
||||
} else {
|
||||
commentsJSON = append(commentsJSON, CommentJSON{})
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ func findOrderBy(parameters Query, orderBy string, limit int, offset int, countA
|
|||
dbQuery = dbQuery.Preload("Uploader")
|
||||
}
|
||||
if countAll {
|
||||
dbQuery = dbQuery.Preload("Comments")
|
||||
dbQuery = dbQuery.Preload("Comments").Preload("OldComments")
|
||||
}
|
||||
|
||||
if conditions != "" {
|
||||
|
@ -193,6 +193,11 @@ func FindAllOrderBy(orderBy string, limit int, offset int) ([]models.Torrent, in
|
|||
return FindOrderBy(nil, orderBy, limit, offset)
|
||||
}
|
||||
|
||||
// FindAllForAdminsOrderBy : Get all torrents ordered by parameters
|
||||
func FindAllForAdminsOrderBy(orderBy string, limit int, offset int) ([]models.Torrent, int, error) {
|
||||
return findOrderBy(nil, orderBy, limit, offset, true, true, false)
|
||||
}
|
||||
|
||||
// FindAll : Get all torrents without order
|
||||
func FindAll(limit int, offset int) ([]models.Torrent, int, error) {
|
||||
return FindOrderBy(nil, "", limit, offset)
|
||||
|
|
|
@ -29,6 +29,8 @@ const (
|
|||
UserStatusModerator = 2
|
||||
// UserStatusScraped : Int for User status scrapped
|
||||
UserStatusScraped = 3
|
||||
// UserStatusModerator : Int for User status moderator
|
||||
UserStatusJanitor = 4
|
||||
)
|
||||
|
||||
// User model
|
||||
|
@ -135,6 +137,11 @@ func (u *User) IsModerator() bool {
|
|||
return u.Status == UserStatusModerator
|
||||
}
|
||||
|
||||
// IsJanitor : Return true if user is janitor OR moderator
|
||||
func (u *User) IsJanitor() bool {
|
||||
return u.Status == UserStatusJanitor || u.Status == UserStatusModerator
|
||||
}
|
||||
|
||||
// IsScraped : Return true if user is a scrapped user
|
||||
func (u *User) IsScraped() bool {
|
||||
return u.Status == UserStatusScraped
|
||||
|
@ -152,11 +159,18 @@ func (u *User) GetUnreadNotifications() int {
|
|||
return u.UnreadNotifications
|
||||
}
|
||||
|
||||
// HasAdmin checks that user has an admin permission. Deprecated
|
||||
func (u *User) HasAdmin() bool {
|
||||
return u.IsModerator()
|
||||
// ToggleBan : Ban/Unban an user an user, return true if the user is now banned
|
||||
func (u *User) ToggleBan() bool {
|
||||
if u.IsBanned() {
|
||||
u.Status = UserStatusMember
|
||||
} else {
|
||||
u.Status = UserStatusBanned
|
||||
}
|
||||
u.Update()
|
||||
return u.IsBanned()
|
||||
}
|
||||
|
||||
|
||||
// CurrentOrAdmin check that user has admin permission or user is the current user.
|
||||
func (u *User) CurrentOrAdmin(userID uint) bool {
|
||||
if userID == 0 && !u.IsModerator() {
|
||||
|
@ -165,6 +179,14 @@ func (u *User) CurrentOrAdmin(userID uint) bool {
|
|||
log.Debugf("user.ID == userID %d %d %s", u.ID, userID, u.ID == userID)
|
||||
return (u.IsModerator() || u.ID == userID)
|
||||
}
|
||||
// CurrentOrJanitor check that user has janitor permission or user is the current user.
|
||||
func (u *User) CurrentOrJanitor(userID uint) bool {
|
||||
if userID == 0 && !u.IsJanitor() {
|
||||
return false
|
||||
}
|
||||
log.Debugf("user.ID == userID %d %d %s", u.ID, userID, u.ID == userID)
|
||||
return (u.IsJanitor() || u.ID == userID)
|
||||
}
|
||||
|
||||
// CurrentUserIdentical check that userID is same as current user's ID.
|
||||
// TODO: Inline this (won't go do this for us?)
|
||||
|
@ -175,7 +197,7 @@ func (u *User) CurrentUserIdentical(userID uint) bool {
|
|||
// NeedsCaptcha : Check if a user needs captcha
|
||||
func (u *User) NeedsCaptcha() bool {
|
||||
// Trusted members & Moderators don't
|
||||
return !(u.IsTrusted() || u.IsModerator())
|
||||
return !(u.IsTrusted() || u.IsJanitor())
|
||||
}
|
||||
|
||||
// CanUpload : Check if a user can upload or if upload is enabled in config
|
||||
|
@ -194,6 +216,9 @@ func (u *User) CanUpload() bool {
|
|||
|
||||
// GetRole : Get the status/role of a user
|
||||
func (u *User) GetRole() string {
|
||||
if u.ID == 0 {
|
||||
return ""
|
||||
}
|
||||
switch u.Status {
|
||||
case UserStatusBanned:
|
||||
return "userstatus_banned"
|
||||
|
@ -203,6 +228,8 @@ func (u *User) GetRole() string {
|
|||
return "userstatus_scraped"
|
||||
case UserStatusTrusted:
|
||||
return "userstatus_trusted"
|
||||
case UserStatusJanitor:
|
||||
return "userstatus_janitor"
|
||||
case UserStatusModerator:
|
||||
return "userstatus_moderator"
|
||||
}
|
||||
|
|
|
@ -44,10 +44,7 @@ func Exists(email string, pass string) (user *models.User, status int, err error
|
|||
status, err = http.StatusUnauthorized, errors.New("incorrect_password")
|
||||
return
|
||||
}
|
||||
if userExist.IsBanned() {
|
||||
status, err = http.StatusUnauthorized, errors.New("account_banned")
|
||||
return
|
||||
}
|
||||
|
||||
if userExist.IsScraped() {
|
||||
status, err = http.StatusUnauthorized, errors.New("account_need_activation")
|
||||
return
|
||||
|
|
|
@ -664,7 +664,7 @@ th {
|
|||
width: auto;
|
||||
}
|
||||
.website-nav table tr {
|
||||
background: none!important;
|
||||
background: none!important;
|
||||
}
|
||||
.website-nav #nav-category-list {
|
||||
width: 70%;
|
||||
|
@ -675,17 +675,17 @@ th {
|
|||
}
|
||||
.sub-category-list {
|
||||
padding-left: 16px;
|
||||
font-size: 12px;
|
||||
margin-bottom: 9px;
|
||||
font-size: 12px;
|
||||
margin-bottom: 9px;
|
||||
}
|
||||
.sub-category-list span{
|
||||
display: block;
|
||||
display: block;
|
||||
}
|
||||
.sub-category-list span:before {
|
||||
content: '-» ';
|
||||
content: '-» ';
|
||||
}
|
||||
.sub-category-list span:first-child:before {
|
||||
content: '';
|
||||
content: '';
|
||||
}
|
||||
textarea {
|
||||
max-width: 100%;
|
||||
|
@ -899,8 +899,8 @@ html, body {
|
|||
width: 100% !important;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.profile-panel .user-search {
|
||||
max-width: none;
|
||||
.profile-usermenu, .profile-panel .user-search {
|
||||
width: 200px!important;
|
||||
}
|
||||
.header .h-user {
|
||||
width: 46px;
|
||||
|
@ -939,6 +939,9 @@ html, body {
|
|||
.upload-form-table .table-input-label {
|
||||
width: 25%!important;
|
||||
}
|
||||
.notification-status {
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 750px),(max-width: 500px) {
|
||||
|
@ -1030,12 +1033,28 @@ html, body {
|
|||
.upload-form-table .table-input-label {
|
||||
display: none;
|
||||
}
|
||||
.torrent-view-data {
|
||||
display: table!important;
|
||||
}
|
||||
.torrent-view-data td, .torrent-view-data table {
|
||||
width: 100%!important;
|
||||
}
|
||||
.torrent-view-data {
|
||||
display: table!important;
|
||||
}
|
||||
.torrent-view-data td, .torrent-view-data table {
|
||||
width: 100%!important;
|
||||
}
|
||||
.notification-status {
|
||||
width: 41px!important;
|
||||
font-size: 0;
|
||||
}
|
||||
#clear-notification a {
|
||||
display: block;
|
||||
margin-left: 0px!important;
|
||||
float: none!important;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.notification-table {
|
||||
margin-bottom: 108px!important;
|
||||
}
|
||||
.notification-date {
|
||||
width: 100px!important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 440px) {
|
||||
|
@ -1062,7 +1081,7 @@ html, body {
|
|||
}
|
||||
|
||||
.profile-sidebar {
|
||||
display: inline-block;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.profile-usertitle {
|
||||
|
@ -1087,11 +1106,14 @@ html, body {
|
|||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.profile-usermenu {
|
||||
min-width: 170px;
|
||||
.profile-usermenu, .profile-panel .user-search {
|
||||
width: 170px;
|
||||
margin: 0 auto;
|
||||
max-width: calc(100% - 16px);
|
||||
}
|
||||
.profile-usermenu a {
|
||||
.profile-usermenu a, .profile-usermenu button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-bottom: 11px;
|
||||
}
|
||||
.profile-usermenu .icon-rss-squared {
|
||||
|
@ -1237,7 +1259,7 @@ html, body {
|
|||
}
|
||||
|
||||
.comment-content :first-child {
|
||||
margin-top: 8px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
.comment-content :last-child {
|
||||
margin-bottom: 2px;
|
||||
|
@ -1251,7 +1273,7 @@ html, body {
|
|||
}
|
||||
|
||||
.comment-form textarea {
|
||||
margin-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror {
|
||||
|
@ -1817,7 +1839,6 @@ input.filelist-checkbox:checked+table.table-filelist {
|
|||
}
|
||||
|
||||
[class^="btn-"] {
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
@ -1876,7 +1897,7 @@ summary:after {
|
|||
width: 12px;
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
outline: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
details[open] summary:after {
|
||||
|
@ -2124,32 +2145,32 @@ p.upload-rules a {
|
|||
}
|
||||
|
||||
.upload-form-table details {
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
#anidex-upload-info > div {
|
||||
height: auto;
|
||||
padding: 10px 6px;
|
||||
border-top: none;
|
||||
height: auto;
|
||||
padding: 10px 6px;
|
||||
border-top: none;
|
||||
}
|
||||
#anidex-upload-info p {
|
||||
margin-bottom: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
#anidex-upload-info p:first-child {
|
||||
margin-top: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
#anidex-upload-info > div > div {
|
||||
margin-left: 9px;
|
||||
margin-left: 9px;
|
||||
}
|
||||
|
||||
#anidex-upload-info > div input[type="text"], #anidex-upload-info > div select {
|
||||
margin-bottom: 4px;
|
||||
|
||||
margin-bottom: 4px;
|
||||
|
||||
}
|
||||
#anidex-upload-info > div select {
|
||||
width: calc(100% - 8px);
|
||||
width: calc(100% - 8px);
|
||||
}
|
||||
#anidex-upload-info > div select[name="anidex_form_category"] option{
|
||||
color: #000;
|
||||
color: #000;
|
||||
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3);
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
|
@ -2339,7 +2360,6 @@ table.multiple-upload {
|
|||
}
|
||||
.profile-panel .user-search {
|
||||
padding: 0;
|
||||
max-width: 170px;
|
||||
}
|
||||
|
||||
.user-search [type="text"] {
|
||||
|
@ -2423,49 +2443,49 @@ form.delete-form button.form-input.btn-red {
|
|||
bottom: 8px;
|
||||
right: 8px;
|
||||
position: absolute;
|
||||
width: calc(100% - 16px);
|
||||
width: calc(100% - 16px);
|
||||
}
|
||||
#clear-notification a {
|
||||
float: right;
|
||||
margin-left: 3px;
|
||||
float: right;
|
||||
margin-left: 3px;
|
||||
}
|
||||
.notification-table {
|
||||
margin-bottom: 44px;
|
||||
}
|
||||
.notification-table td {
|
||||
text-align: center;
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid;
|
||||
text-align: center;
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
.notification-table tr:hover td {
|
||||
filter: brightness(1.2);
|
||||
filter: brightness(1.2);
|
||||
}
|
||||
.notification-status {
|
||||
width: 140px;
|
||||
width: 140px;
|
||||
}
|
||||
.notification-event {
|
||||
text-align: left!important;
|
||||
padding: 6px 10px!important;
|
||||
text-align: left!important;
|
||||
padding: 6px 10px!important;
|
||||
}
|
||||
.notification-date {
|
||||
width: 195px;
|
||||
width: 195px;
|
||||
}
|
||||
td.notification-status {
|
||||
border: 1px solid black;
|
||||
border: 1px solid black;
|
||||
}
|
||||
td.notification-status {
|
||||
background-color: #e4e4e4;
|
||||
background-color: #e4e4e4;
|
||||
}
|
||||
td.notification-status.notification-unread {
|
||||
background-color: rgb(161, 211, 253);
|
||||
color: white;
|
||||
background-color: rgb(161, 211, 253);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.torrent-report-table td, .torrent-report-table th {
|
||||
width: 195px;
|
||||
width: 195px;
|
||||
}
|
||||
.td-report-message {
|
||||
width: auto!important;
|
||||
width: auto!important;
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
{{ extends "layouts/index_admin" }}
|
||||
{{block title()}}{{ T("moderation_guidelines") }}{{end}}
|
||||
{{ block content_body()}}
|
||||
<div class="results box">
|
||||
<h1>{{ T("moderation_guidelines") }}</h1>
|
||||
<img src="https://www.themarysue.com/wp-content/uploads/2016/09/harassment-guide.png">
|
||||
</div>
|
||||
{{end}}
|
|
@ -14,19 +14,26 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
{{range Torrents}}
|
||||
<tr>
|
||||
<tr {{ if .IsBlocked() }}class="locked"{{end}}>
|
||||
<td class="tr-name home-td">
|
||||
<a href="/view/{{.ID }}">{{ .Name }}</a>
|
||||
<a href="/mod/torrent?id={{.ID}}" class="form-input btn-blue float-right">{{ T("edit") }}</a>
|
||||
</td>
|
||||
<td class="tr-size home-td">
|
||||
<a href="/mod/torrents?userID={{.UploaderID}}">{{ .UploaderID }}</a>
|
||||
<a href="/mod/torrents?userID={{.UploaderID}}">{{ if .Uploader }}{{.Uploader.Username }}{{else}}れんちょん{{end}}</a>
|
||||
</td>
|
||||
<td class="tr-size home-td">
|
||||
<form method="POST" action="/mod/torrent/delete">
|
||||
<input type="hidden" name="id" value="{{ .ID }}">
|
||||
<button type="submit" class="form-input btn-red" onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"><i class="icon-trash"></i> {{ T("delete") }}</button>
|
||||
</form>
|
||||
{{ if User.IsModerator() }}
|
||||
<form method="POST" action="/mod/torrent/delete" class="delete-form">
|
||||
<input type="hidden" name="id" value="{{ .ID }}">
|
||||
{{ if .IsDeleted() }}<input type="hidden" name="definitely" value="true">{{ end }}
|
||||
<button type="submit" class="form-input btn-red" onclick="if (!confirm('{{ T("are_you_sure") }} {{ if !.IsDeleted() }}{{ T("delete") }}{{else}}{{ T("delete_definitely_torrent_warning ")}}{{end}}')) return false;"><i class="icon-trash"></i>{{ if .IsDeleted() }}{{ T("delete_definitely") }}{{else}}{{ T("delete") }}{{end}}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
<form method="POST" action="/mod/torrent/block" class="delete-form">
|
||||
<input type="hidden" name="id" value="{{ .ID }}">
|
||||
<button type="submit" class="form-input btn-orange" onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"><i class="icon-trash"></i>{{ if .IsBlocked() }}{{ T("torrent_unblock") }}{{else}}{{ T("torrent_block") }}{{end}}</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
@ -88,10 +95,16 @@
|
|||
<a href="/user/{{.ID}}/{{.Username }}">{{ .Username }}</a>
|
||||
</td>
|
||||
<td class="tr-size home-td">{{if .ID > 0}}
|
||||
<form method="POST" action="/user/{{.ID}}/{{.Username }}/delete" >
|
||||
{{ yield csrf_field()}}
|
||||
<button type="submit" class="form-input btn-red" onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"><i class="icon-trash"></i> {{ T("delete") }}</button>
|
||||
</form>
|
||||
{{ if User.IsModerator() }}
|
||||
<form method="POST" action="/user/{{.ID}}/{{.Username }}/delete" class="delete-form">
|
||||
{{ yield csrf_field()}}
|
||||
<button type="submit" class="form-input btn-red" onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"><i class="icon-trash"></i> {{ T("delete") }}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
<form method="POST" action="/user/{{.ID}}/{{.Username }}/ban" class="delete-form">
|
||||
{{ yield csrf_field()}}
|
||||
<button type="submit" class="form-input btn-orange" onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"><i class="icon-trash"></i>{{ if .IsBanned() }}{{ T("unban") }}{{else}}{{ T("ban") }}{{end}}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -38,12 +38,12 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
{{ range Models}}
|
||||
<tr>
|
||||
<tr {{ if .Status == 5}}class="locked hidden"{{end}}>
|
||||
<td class="tr-cb">
|
||||
<input type="checkbox" class="selectable" name="torrent_id" value="{{.ID }}" />
|
||||
</td>
|
||||
<td class="tr-name home-td">
|
||||
<a href="/view/{{ .ID }}">{{ .Name }}</a> {{ if !.IsDeleted }}
|
||||
<a href="/view/{{ .ID }}">{{ .Name }}</a> {{ if User.IsModerator() }}
|
||||
<a href="/mod/torrent?id={{.ID}}" class="form-input btn-blue float-right">
|
||||
{{ T("edit")}}
|
||||
</a> {{end}}
|
||||
|
@ -57,14 +57,15 @@
|
|||
<td class="tr-actions home-td"> <form></form>
|
||||
<form method="POST" action="/mod/torrent/block" class="delete-form">
|
||||
<input type="hidden" name="id" value="{{ .ID }}">
|
||||
<button type="submit" class="form-input btn-orange" onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"><i class="icon-trash"></i>{{ if .IsBlocked }}{{ T("torrent_unblock") }}{{else}}{{ T("torrent_block") }}{{end}}</button>
|
||||
<button type="submit" class="form-input btn-orange" {{ if !User.IsModerator() }}onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"{{end}}><i class="icon-trash"></i>{{ if .IsBlocked() }}{{ T("torrent_unblock") }}{{else}}{{ T("torrent_block") }}{{end}}</button>
|
||||
</form>
|
||||
{{ if User.IsModerator() }}
|
||||
<form method="POST" action="/mod/torrent/delete" class="delete-form">
|
||||
<input type="hidden" name="id" value="{{ .ID }}">
|
||||
{{ if .IsDeleted }}<input type="hidden" name="definitely" value="true">{{ end }}
|
||||
<button type="submit" class="form-input btn-red" onclick="if (!confirm('{{ T("are_you_sure") }} {{ if !.IsDeleted }}{{ T("delete") }}{{else}}{{ T("delete_definitely_torrent_warning ")}}{{end}}')) return false;"><i class="icon-trash"></i>{{ if .IsDeleted }}{{ T("delete_definitely") }}{{else}}{{ T("delete") }}{{end}}</button>
|
||||
{{ if .IsDeleted() }}<input type="hidden" name="definitely" value="true">{{ end }}
|
||||
<button type="submit" class="form-input btn-red" onclick="if (!confirm('{{ T("are_you_sure") }} {{ if !.IsDeleted() }}{{ T("delete") }}{{else}}{{ T("delete_definitely_torrent_warning ")}}{{end}}')) return false;"><i class="icon-trash"></i>{{ if .IsDeleted() }}{{ T("delete_definitely") }}{{else}}{{ T("delete") }}{{end}}</button>
|
||||
</form>
|
||||
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
{{ range Models}}
|
||||
<tr>
|
||||
<tr {{ if .IsBanned() }}class="locked hidden"{{end}}>
|
||||
<td class="tr-name home-td">
|
||||
<a href="/user/{{.ID}}/{{.Username }}">{{ .Username }}</a>
|
||||
</td>
|
||||
|
@ -21,7 +21,10 @@
|
|||
{{if .ID > 0}}
|
||||
<form method="POST" action="/user/{{.ID}}/{{.Username }}/delete">
|
||||
{{ yield csrf_field()}}
|
||||
{{ if User.IsModerator() }}
|
||||
<button type="submit" class="form-input btn-red" onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"><i class="icon-trash"></i> {{ T("delete") }}</button>
|
||||
{{end}}
|
||||
<button type="submit" class="form-input btn-orange" onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"><i class="icon-trash"></i> {{ if !.IsBanned() }}{{ T("ban") }}{{else}}{{ T("unban") }}{{end}}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</td>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<a href="{{magnet}}" class="form-input btn-green download" style="height: auto;">
|
||||
<div class="icon-magnet"></div>{{ T("magnet_link")}}
|
||||
</a>
|
||||
{{ if !isset(Errors[name])}}<br/><p>{{ T("pending_torrent") }}</p>{{end}}<br/><br/>
|
||||
{{ if !isset(Errors["errors"])}}<br/><p>{{ T("pending_torrent") }}</p>{{end}}<br/><br/>
|
||||
{{ end }}
|
||||
<img src="/img/no_torrent_file.jpg" alt="No torrent file"/>
|
||||
</div>
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
{{ import "csrf" }}
|
||||
{{block badge_user()}}
|
||||
<div class="h-user">
|
||||
<div class="h-user {{ if User.IsBanned() }}hidden{{end}}">
|
||||
{{if User.ID > 0 }}
|
||||
<button href="#" class="nav-btn">
|
||||
<div class="user-avatar small">
|
||||
<img src="{{getAvatar(User.MD5, 50)}}"/>
|
||||
{{if User.GetUnreadNotifications() > 0}}<span>{{User.GetUnreadNotifications()}}</span>{{end}}
|
||||
</div>
|
||||
<span class="user-info" title="{{ User.Username}}">
|
||||
<span class="user-info" title="{{ User.Username }}">
|
||||
<span class="hide-md">{{User.Username}}</span>
|
||||
</span>
|
||||
</button>
|
||||
<div class="user-menu">
|
||||
<a class="nav-btn" href="/user/{{ User.ID }}/{{ User.Username }}">{{ T("profile")}}</a>
|
||||
<a class="nav-btn" href="/user/{{ User.ID }}/{{ User.Username }}">{{ T("profile")}}{{ if User.IsBanned() }} ({{T("banned")}}){{end}}</a>
|
||||
<a class="nav-btn notif" href="/notifications">
|
||||
{{ T("my_notifications")}}
|
||||
{{if User.GetUnreadNotifications() > 0}}<span class="badge">({{ User.GetUnreadNotifications() }})</span>{{end}}
|
||||
|
@ -20,7 +20,7 @@
|
|||
<a class="nav-btn" href="/user/{{ User.ID }}/{{ User.Username }}/edit">
|
||||
{{ T("settings")}}
|
||||
</a>
|
||||
{{if User.HasAdmin()}}
|
||||
{{if User.IsJanitor()}}
|
||||
<a class="nav-btn" href="/mod">{{ T("moderation")}}</a>
|
||||
{{end}}
|
||||
<form action="/logout" method="POST">
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
{{ if _% 3 != 2}}{{ if _% 3 == 0}}<td></td>{{end}}<td></td>{{end}}
|
||||
</tr>{{end}}
|
||||
{{ end }}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{ if Search.Category != ""}}
|
||||
|
|
|
@ -7,4 +7,5 @@
|
|||
<a href="{{URL.Parse("/mod/announcement")}}" class="nav-btn{{if strcmp(URL.String(), "/mod/announcement", 17, 5) }} active{{end}}">{{ T("announcements")}}</a>
|
||||
<a href="{{URL.Parse("/mod/reports")}}" class="nav-btn{{if URL.String() == "/mod/reports"}} active{{end}}">{{ T("torrent_reports")}}</a>
|
||||
<a href="{{URL.Parse("/mod/reassign")}}" class="nav-btn{{if URL.String() == "/mod/reassign"}} active{{end}}">{{ T("torrent_reassign")}}</a>
|
||||
<a href="{{URL.Parse("/mod/guidelines")}}" class="nav-btn{{if URL.String() == "/mod/guidelines"}} active{{end}}">{{ T("guidelines")}}</a>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{{ import "layouts/partials/helpers/csrf" }}
|
||||
{{ block profile_menu(route="profile") }}
|
||||
<div class="profile-sidebar">
|
||||
<div class="profile-sidebar {{ if UserProfile.IsBanned() }} hidden{{end}}">
|
||||
<!-- SIDEBAR USERPIC -->
|
||||
<div class="profile-userpic">
|
||||
<img src="{{ getAvatar(UserProfile.MD5, 130) }}" alt="{{ UserProfile.Username }}"/>
|
||||
|
@ -10,9 +11,11 @@
|
|||
<p class="profile-usertitle-name">
|
||||
{{ UserProfile.Username}}
|
||||
</p>
|
||||
{{ if UserProfile.GetRole() != "" }}
|
||||
<p class="profile-usertitle-job">
|
||||
{{T(UserProfile.GetRole())}}
|
||||
</p>
|
||||
{{end}}
|
||||
<p class="profile-usertitle-uploadcount">{{T("followers")}}: <b>{{len(UserProfile.Followers)}}</b><br/>{{ T("torrents_uploaded") }}:<b>{{ NbTorrents[0] }}</b><br>{{T("size")}}: <b>{{fileSize(NbTorrents[1], T, false)}}</b></p>
|
||||
</div>
|
||||
<!-- END SIDEBAR USER TITLE -->
|
||||
|
@ -43,12 +46,19 @@
|
|||
{{ if User.CurrentUserIdentical(UserProfile.ID) }}
|
||||
<a class="form-input" href="/notifications">{{ T("my_notifications")}}</a>
|
||||
{{end}}
|
||||
{{if UserProfile.ID > 0 && User.CurrentOrAdmin(UserProfile.ID) }}
|
||||
<a class="form-input" href="/user/{{UserProfile.ID}}/{{UserProfile.Username}}/edit">
|
||||
{{ T("settings")}}
|
||||
</a>
|
||||
{{end}}
|
||||
{{if UserProfile.ID > 0}}
|
||||
{{ if User.CurrentOrAdmin(UserProfile.ID) }}
|
||||
<a class="form-input" href="/user/{{UserProfile.ID}}/{{UserProfile.Username}}/edit">
|
||||
{{ T("settings")}}
|
||||
</a>
|
||||
{{else if User.IsJanitor() && !UserProfile.IsJanitor() }}
|
||||
<form method="POST" action="/user/{{UserProfile.ID}}/{{UserProfile.Username}}/ban">
|
||||
{{ yield csrf_field()}}
|
||||
<button type="submit" class="form-input btn-blue" onclick="if (!confirm('{{ T("are_you_sure") }}')) return false;"><i class="icon-trash"></i>{{ if UserProfile.IsBanned() }}{{ T("unban") }}{{else}}{{ T("ban") }}{{end}}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
{{ if User.ID != UserProfile.ID }}
|
||||
<div class="user-search">
|
||||
|
|
|
@ -17,7 +17,7 @@ Templates.Add("torrents.item", function(torrent) {
|
|||
} else if (torrent.status == 4) {
|
||||
tr_class += " aplus"
|
||||
}
|
||||
// {{ if User.HasAdmin() }}
|
||||
// {{ if User.IsModerator() }}
|
||||
var cb_hide = (!TorrentsMod.enabled) ? " hide" : ""
|
||||
var cb_show = (TorrentsMod.enabled) ? ' style="display:table-cell;"' : ""
|
||||
// {{ end }}
|
||||
|
@ -43,7 +43,7 @@ Templates.Add("torrents.item", function(torrent) {
|
|||
}
|
||||
|
||||
return `<tr id="torrent_` + torrent.id + `" class="` + tr_class + `">
|
||||
{{ if User.HasAdmin() }}
|
||||
{{ if User.IsModerator() }}
|
||||
<td class="tr-cb` + cb_hide + `"` + cb_show + `>
|
||||
<input data-name="` + Templates.EncodeEntities(torrent.name) + `" type="checkbox" id="torrent_cb_` + torrent.id + `" name="torrent_id" value="` + torrent.id + `">
|
||||
</td>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{{ extends "layouts/index_site" }}
|
||||
{{ import "layouts/partials/helpers/search" }}
|
||||
{{block title()}}{{if Search.UserName == ""}}{{ T("home")}}{{else}}{{Search.UserName}}{{end}}{{end}}
|
||||
{{block contclass()}}{{if User.HasAdmin() }}content-admin{{end}}{{end}}
|
||||
{{block title()}}{{if Search.UserName != ""}}{{Search.UserName}}{{else if Search.NameLike != ""}}{{Search.NameLike}}{{else if Search.Category != ""}}{{T(GetCategoryName(Search.Category))}}{{else}}{{ T("home")}}{{end}}{{end}}
|
||||
{{block contclass()}}{{if User.IsModerator() }}content-admin{{end}}{{end}}
|
||||
{{block content_body()}}
|
||||
{{ if OldNav || Theme == "classic"}}
|
||||
{{ include "layouts/partials/helpers/oldNav" }}
|
||||
|
@ -11,7 +11,7 @@
|
|||
<table>
|
||||
<thead class="torrent-info">
|
||||
<tr>
|
||||
{{ if User.HasAdmin() }}
|
||||
{{ if User.IsModerator() }}
|
||||
<th class="tr-cb hide">
|
||||
<input type="checkbox" name="select_all" onchange="TorrentsMod.selectAll(this.checked)"/>
|
||||
</th>
|
||||
|
@ -55,8 +55,8 @@
|
|||
</thead>
|
||||
<tbody id="torrentListResults" {{if AltColors}}class="alt-colors"{{end}}>
|
||||
{{ range Models}}
|
||||
<tr id="torrent_{{ .ID }}" class="torrent-info {{if .Status == 2}}remake{{else if .Status == 3}}trusted{{else if .Status == 4}}aplus{{end}}" >
|
||||
{{ if User.HasAdmin() }}
|
||||
<tr id="torrent_{{ .ID }}" class="torrent-info {{if .Status == 2}}remake{{else if .Status == 3}}trusted{{else if .Status == 4}}aplus{{else if .Status == 5}}locked hidden{{end}}">
|
||||
{{ if User.IsModerator() }}
|
||||
<td class="tr-cb hide">
|
||||
<input data-name="{{ .Name }}" type="checkbox" id="torrent_cb_{{ .ID }}" name="torrent_id" value="{{ .ID }}"/>
|
||||
</td>
|
||||
|
@ -108,7 +108,7 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{ if User.HasAdmin() }}
|
||||
{{ if User.IsModerator() }}
|
||||
<div class="modtools">
|
||||
<button id="show_actions" class="form-input" data-toggle-text="{{ T("hide_mod_tools")}}">{{ T("show_mod_tools")}}</button>
|
||||
<span class="actions">
|
||||
|
@ -175,7 +175,7 @@
|
|||
<script type="text/javascript" src="{{ URL.Parse("/js/modal.js") }}"></script>
|
||||
<script type="text/javascript" src="{{ URL.Parse("/js/torrents.js") }}"></script>
|
||||
<script type="text/javascript" src="{{ URL.Parse("/js/translation.js") }}"></script>
|
||||
{{ if User.HasAdmin() }}
|
||||
{{ if User.IsModerator() }}
|
||||
<script type="text/javascript" src="{{ URL.Parse("/js/torrentsMod.js") }}"></script>
|
||||
<script type="text/javascript">
|
||||
// We add translations string
|
||||
|
|
|
@ -163,7 +163,7 @@
|
|||
</a>
|
||||
<a id="reportPopup" href="/report/{{Torrent.ID}}" class="form-input">{{ T("report_btn") }}</a>
|
||||
{{ if User.ID > 0}}
|
||||
{{ if User.HasAdmin()}}
|
||||
{{ if User.IsModerator()}}
|
||||
<form method="POST" action="/mod/torrent/delete" class="delete-form">
|
||||
{{ yield csrf_field()}}
|
||||
<input type="hidden" name="id" value="{{ Torrent.ID }}">
|
||||
|
@ -212,23 +212,23 @@
|
|||
{{idx := 1}}
|
||||
{{previousComment := ""}}
|
||||
{{previousUser := 0}}
|
||||
{{range index, element := Torrent.Comments}}
|
||||
{{if previousComment != element.Content || previousUser != element.UserID || element.UserID == 0}}
|
||||
{{range _, comment := Torrent.Comments}}
|
||||
{{if previousComment != comment.Content || previousUser != comment.UserID || comment.UserID == 0}}
|
||||
<div class="torrent-info-box comment-box">
|
||||
<span class="comment-index">
|
||||
<a href="#comment_{{idx}}">{{idx}}</a>
|
||||
<small style="padding-left: 4px;" class="date-full">{{formatDate(element.Date, false)}}</small>
|
||||
<small style="padding-left: 4px;" class="date-full">{{formatDate(comment.Date, false)}}</small>
|
||||
</span>
|
||||
<span class="comment-userinfo"><img src="{{ getAvatar(element.UserAvatar, 50) }}"/>
|
||||
{{if element.UserID > 0}}<a href="/user/{{element.UserID}}/{{element.Username}}" class="comment-user">{{element.Username}}</a>{{if element.UserStatus != ""}}<span class="user-status">{{T(element.UserStatus)}}</span>{{end}}{{else}}
|
||||
<span class="comment-user">れんちょん</span>{{end}}
|
||||
<span class="comment-userinfo"><img src="{{ getAvatar(comment.UserAvatar, 50) }}"/>
|
||||
{{if comment.UserID > 0}}<a href="/user/{{comment.UserID}}/{{comment.Username}}" class="comment-user">{{comment.Username}}</a>{{if comment.UserStatus != ""}}<span class="user-status">{{T(comment.UserStatus)}}</span>{{end}}{{else}}
|
||||
<span class="comment-user">{{ if comment.Username != ""}}{{comment.Username}}{{else}}れんちょん{{end}}</span>{{end}}
|
||||
</span>
|
||||
<div class="comment-content">{{element.Content|raw}}</div>
|
||||
<div class="comment-content">{{comment.Content|raw}}</div>
|
||||
</div>
|
||||
{{idx = idx + 1}}
|
||||
{{end}}
|
||||
{{previousComment = element.Content}}
|
||||
{{previousUser = element.UserID}}
|
||||
{{previousComment = comment.Content}}
|
||||
{{previousUser = comment.UserID}}
|
||||
{{end}}
|
||||
{{ if len(Torrent.Comments) == 0 }}
|
||||
<p id="no-comment-message">{{ T("torrent_no_comments") }}</p>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
{{ if !User.HasAdmin()}}
|
||||
{{ if !User.IsModerator()}}
|
||||
<tr>
|
||||
<td><label for="current_password">{{ T("current_password") }}</label></td>
|
||||
<td><input class="form-input up-input up-input" name="current_password" id="current_password" type="password"/></td>
|
||||
|
@ -51,7 +51,7 @@
|
|||
</table>
|
||||
{{ yield errors(name="Email")}}
|
||||
{{ yield errors(name="Language")}}
|
||||
{{ if !User.HasAdmin()}}
|
||||
{{ if !User.IsModerator()}}
|
||||
{{ yield errors(name="CurrentPassword")}}
|
||||
{{end}}
|
||||
{{ yield errors(name="Password")}}
|
||||
|
@ -228,7 +228,7 @@
|
|||
{{ yield errors(name="FollowedEmail")}}
|
||||
{{end}}
|
||||
|
||||
{{ if User.HasAdmin()}}
|
||||
{{ if User.IsModerator()}}
|
||||
<h2>{{ T("moderation")}}</h2>
|
||||
<table class="user-edit-table">
|
||||
<tbody>
|
||||
|
@ -243,8 +243,9 @@
|
|||
<option value="-1" {{ if UserProfile.Status == -1 }}selected{{end}}>{{ T("userstatus_banned")}}</option>
|
||||
<option value="0" {{ if UserProfile.Status == 0 }}selected{{end}}>{{ T("userstatus_member")}} ({{ T("default") }})</option>
|
||||
<option value="1" {{ if UserProfile.Status == 1 }}selected{{end}}>{{ T("userstatus_trusted")}}</option>
|
||||
{{ if UserProfile.Status == 2}}
|
||||
<option value="2" selected>{{ T("userstatus_moderator")}}</option>
|
||||
{{ if User.Status == 2}}
|
||||
<option value="4" {{ if UserProfile.Status == 4 }}selected{{end}}>{{ T("userstatus_janitor")}}</option>
|
||||
<option value="2" {{ if UserProfile.Status == 2 }}selected{{end}}>{{ T("userstatus_moderator")}}</option>
|
||||
{{end}}
|
||||
<option value="3" {{ if UserProfile.Status == 3 }}selected{{end}}>{{ T("userstatus_scraped")}}</option>
|
||||
</select>
|
||||
|
|
|
@ -168,10 +168,10 @@ func userProfileBase(c *gin.Context, templateName string, userProfile *models.Us
|
|||
query.Set("limit", "15")
|
||||
c.Request.URL.RawQuery = query.Encode()
|
||||
nbTorrents := 0
|
||||
if userProfile.ID > 0 && currentUser.CurrentOrAdmin(userProfile.ID) {
|
||||
_, userProfile.Torrents, nbTorrents, _ = search.ByQuery(c, 1, true, false, false)
|
||||
if userProfile.ID > 0 && currentUser.CurrentOrJanitor(userProfile.ID) {
|
||||
_, userProfile.Torrents, nbTorrents, _ = search.ByQuery(c, 1, true, false, false, true)
|
||||
} else {
|
||||
_, userProfile.Torrents, nbTorrents, _ = search.ByQuery(c, 1, true, false, true)
|
||||
_, userProfile.Torrents, nbTorrents, _ = search.ByQuery(c, 1, true, false, true, false)
|
||||
}
|
||||
|
||||
var uploadedSize int64
|
||||
|
|
|
@ -40,6 +40,7 @@ func templateFunctions(vars jet.VarMap) jet.VarMap {
|
|||
vars.Set("GetCategories", categories.GetSelect)
|
||||
vars.Set("GetCategory", getCategory)
|
||||
vars.Set("CategoryName", categoryName)
|
||||
vars.Set("GetCategoryName", GetCategoryName)
|
||||
vars.Set("GetTorrentLanguages", torrentLanguages.GetTorrentLanguages)
|
||||
vars.Set("LanguageName", languageName)
|
||||
vars.Set("LanguageNameFromCode", languageNameFromCode)
|
||||
|
@ -224,13 +225,16 @@ func getCategory(category string, keepParent bool) categories.Categories {
|
|||
return categoryRet
|
||||
}
|
||||
func categoryName(category string, subCategory string) string {
|
||||
s := category + "_" + subCategory
|
||||
return GetCategoryName( category + "_" + subCategory)
|
||||
}
|
||||
|
||||
if category, ok := categories.GetByID(s); ok {
|
||||
return category.Name
|
||||
func GetCategoryName(category string) string {
|
||||
if cat, ok := categories.GetByID(category); ok {
|
||||
return cat.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func languageName(lang publicSettings.Language, T publicSettings.TemplateTfunc) string {
|
||||
if strings.Contains(lang.Name, ",") {
|
||||
langs := strings.Split(lang.Name, ", ")
|
||||
|
|
|
@ -289,6 +289,37 @@ func TestCategoryName(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCategoryName2(t *testing.T) {
|
||||
var tests = []struct {
|
||||
TestCat string
|
||||
Expected string
|
||||
}{
|
||||
{
|
||||
TestCat: "_",
|
||||
Expected: "",
|
||||
},
|
||||
{
|
||||
TestCat: "d",
|
||||
Expected: "",
|
||||
},
|
||||
{
|
||||
TestCat: "3_",
|
||||
Expected: "anime",
|
||||
},
|
||||
{
|
||||
TestCat: "3_6",
|
||||
Expected: "anime_raw",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
value := GetCategoryName(test.TestCat)
|
||||
if value != test.Expected {
|
||||
t.Errorf("Unexpected value from the function categoryName, got '%s', wanted '%s' for '%s'", value, test.Expected, test.TestCat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLanguageName(t *testing.T) {
|
||||
var tests = []struct {
|
||||
TestLang publicSettings.Language
|
||||
|
|
|
@ -91,3 +91,15 @@
|
|||
## 2017/11/04
|
||||
* + nsfw_content
|
||||
* + generating_torrent_failed
|
||||
## 2017/11/09
|
||||
* + userstatus_janitor
|
||||
* + ban
|
||||
* + unban
|
||||
* + user_banned_by
|
||||
* + user_unbanned_by
|
||||
## 2017/11/10
|
||||
* + user_banned
|
||||
* + user_unbanned
|
||||
* + torrent_uploaded_locked
|
||||
* + moderation_guidelines
|
||||
* + guidelines
|
||||
|
|
|
@ -607,6 +607,10 @@
|
|||
"id": "current_password",
|
||||
"translation": "Current password"
|
||||
},
|
||||
{
|
||||
"id": "default",
|
||||
"translation": "Default"
|
||||
},
|
||||
{
|
||||
"id": "role",
|
||||
"translation": "Role"
|
||||
|
@ -615,10 +619,6 @@
|
|||
"id": "userstatus_banned",
|
||||
"translation": "Banned"
|
||||
},
|
||||
{
|
||||
"id": "default",
|
||||
"translation": "Default"
|
||||
},
|
||||
{
|
||||
"id": "userstatus_trusted",
|
||||
"translation": "Trusted member"
|
||||
|
@ -631,6 +631,10 @@
|
|||
"id": "userstatus_moderator",
|
||||
"translation": "Moderator"
|
||||
},
|
||||
{
|
||||
"id": "userstatus_janitor",
|
||||
"translation": "Janitor"
|
||||
},
|
||||
{
|
||||
"id": "userstatus_uploader",
|
||||
"translation": "Uploader"
|
||||
|
@ -883,6 +887,10 @@
|
|||
"id": "torrent_uploaded",
|
||||
"translation": "torrent uploaded successfully!"
|
||||
},
|
||||
{
|
||||
"id": "torrent_uploaded_locked",
|
||||
"translation": "Your torrent has been uploaded but is locked because you are banned."
|
||||
},
|
||||
{
|
||||
"id": "preferences",
|
||||
"translation": "Preferences"
|
||||
|
@ -976,9 +984,21 @@
|
|||
"translation": "Torrent #%d from %s has been locked by %s."
|
||||
},
|
||||
{
|
||||
"id": "torrent_blocked_by",
|
||||
"id": "torrent_unblocked_by",
|
||||
"translation": "Torrent #%d from %s has been unlocked by %s."
|
||||
},
|
||||
{
|
||||
"id": "user_banned",
|
||||
"translation": "User has been banned!"
|
||||
},
|
||||
{
|
||||
"id": "user_banned",
|
||||
"translation": "User has been unbanned!"
|
||||
},
|
||||
{
|
||||
"id": "user_unbanned_by",
|
||||
"translation": "User %s(%d) #%d has been unbanned by %s"
|
||||
},
|
||||
{
|
||||
"id": "torrents_deleted",
|
||||
"translation": "Torrents Deleted"
|
||||
|
@ -1099,6 +1119,14 @@
|
|||
"id": "torrent_block",
|
||||
"translation": "Lock"
|
||||
},
|
||||
{
|
||||
"id": "unban",
|
||||
"translation": "Unban"
|
||||
},
|
||||
{
|
||||
"id": "ban",
|
||||
"translation": "Ban"
|
||||
},
|
||||
{
|
||||
"id": "torrent_deleted_definitely",
|
||||
"translation": "Torrent has been erased from the database!"
|
||||
|
@ -2250,5 +2278,13 @@
|
|||
{
|
||||
"id": "unread",
|
||||
"translation": "Unread"
|
||||
},
|
||||
{
|
||||
"id": "moderation_guidelines",
|
||||
"translation": "Moderation Guidelines"
|
||||
},
|
||||
{
|
||||
"id": "guidelines",
|
||||
"translation": "Guidelines"
|
||||
}
|
||||
]
|
||||
|
|
|
@ -39,25 +39,25 @@ func stringIsASCII(input string) bool {
|
|||
|
||||
// ByQueryNoUser : search torrents according to request without user
|
||||
func ByQueryNoUser(c *gin.Context, pagenum int) (search TorrentParam, tor []models.Torrent, count int, err error) {
|
||||
search, tor, count, err = ByQuery(c, pagenum, false, false, false)
|
||||
search, tor, count, err = ByQuery(c, pagenum, false, false, false, false)
|
||||
return
|
||||
}
|
||||
|
||||
// ByQueryWithUser : search torrents according to request with user
|
||||
func ByQueryWithUser(c *gin.Context, pagenum int) (search TorrentParam, tor []models.Torrent, count int, err error) {
|
||||
search, tor, count, err = ByQuery(c, pagenum, true, false, false)
|
||||
search, tor, count, err = ByQuery(c, pagenum, true, false, false, true)
|
||||
return
|
||||
}
|
||||
|
||||
// ByQueryDeleted : search deleted torrents according to request with user and count
|
||||
func ByQueryDeleted(c *gin.Context, pagenum int) (search TorrentParam, tor []models.Torrent, count int, err error) {
|
||||
search, tor, count, err = ByQuery(c, pagenum, true, true, false)
|
||||
search, tor, count, err = ByQuery(c, pagenum, true, true, false, true)
|
||||
return
|
||||
}
|
||||
|
||||
// ByQueryNoHidden : search torrents and filter those hidden
|
||||
func ByQueryNoHidden(c *gin.Context, pagenum int) (search TorrentParam, tor []models.Torrent, count int, err error) {
|
||||
search, tor, count, err = ByQuery(c, pagenum, false, false, true)
|
||||
search, tor, count, err = ByQuery(c, pagenum, false, false, true, false)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -66,11 +66,12 @@ func ByQueryNoHidden(c *gin.Context, pagenum int) (search TorrentParam, tor []mo
|
|||
// elasticsearch always provide a count to how many hits
|
||||
// ES doesn't store users
|
||||
// deleted is unused because es doesn't index deleted torrents
|
||||
func ByQuery(c *gin.Context, pagenum int, withUser bool, deleted bool, hidden bool) (TorrentParam, []models.Torrent, int, error) {
|
||||
func ByQuery(c *gin.Context, pagenum int, withUser bool, deleted bool, hidden bool, locked bool) (TorrentParam, []models.Torrent, int, error) {
|
||||
var torrentParam TorrentParam
|
||||
torrentParam.FromRequest(c)
|
||||
torrentParam.Offset = uint32(pagenum)
|
||||
torrentParam.Hidden = hidden
|
||||
torrentParam.Locked = locked
|
||||
torrentParam.Full = withUser
|
||||
torrentParam.Deleted = deleted
|
||||
|
||||
|
@ -106,6 +107,6 @@ func ByQuery(c *gin.Context, pagenum int, withUser bool, deleted bool, hidden bo
|
|||
}
|
||||
|
||||
// AuthorizedQuery return a seach byquery according to the bool. If false, it doesn't look for hidden torrents, else it looks for every torrents
|
||||
func AuthorizedQuery(c *gin.Context, pagenum int, authorized bool) (TorrentParam, []models.Torrent, int, error) {
|
||||
return ByQuery(c, pagenum, true, false, !authorized)
|
||||
func AuthorizedQuery(c *gin.Context, pagenum int, authorized bool, locked bool) (TorrentParam, []models.Torrent, int, error) {
|
||||
return ByQuery(c, pagenum, true, false, !authorized, locked)
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ type TorrentParam struct {
|
|||
Full bool // True means load all members
|
||||
Order bool // True means ascending
|
||||
Hidden bool // True means filter hidden torrents
|
||||
Locked bool // False means filter locked torrents
|
||||
Deleted bool // False means filter deleted torrents
|
||||
Status Status
|
||||
Sort SortMode
|
||||
|
@ -71,7 +72,7 @@ func (p *TorrentParam) Identifier() string {
|
|||
tags += p.VideoQuality
|
||||
dbids := fmt.Sprintf("%d%d%d%s", p.AnidbID, p.VndbID, p.VgmdbID, p.Dlsite)
|
||||
|
||||
identifier := fmt.Sprintf("%s%s%s%d%d%d%d%d%d%d%s%s%s%d%s%s%s%t%t%t%t", p.NameLike, p.NotNull, languages, p.Max, p.Offset, p.FromID, p.MinSize, p.MaxSize, p.Status, p.Sort, dbids, p.FromDate, p.ToDate, p.UserID, ids, cats, tags, p.Full, p.Order, p.Hidden, p.Deleted)
|
||||
identifier := fmt.Sprintf("%s%s%s%d%d%d%d%d%d%d%s%s%s%d%s%s%s%t%t%t%t%t", p.NameLike, p.NotNull, languages, p.Max, p.Offset, p.FromID, p.MinSize, p.MaxSize, p.Status, p.Sort, dbids, p.FromDate, p.ToDate, p.UserID, ids, cats, tags, p.Full, p.Order, p.Hidden, p.Locked, p.Deleted)
|
||||
return base64.URLEncoding.EncodeToString([]byte(identifier))
|
||||
}
|
||||
|
||||
|
@ -251,8 +252,11 @@ func (p *TorrentParam) toESQuery(c *gin.Context) *Query {
|
|||
|
||||
if p.Status != ShowAll {
|
||||
query.Append(p.Status.ToESQuery())
|
||||
} else if !p.Locked {
|
||||
query.Append(fmt.Sprintf("!(status:%d)", 5))
|
||||
}
|
||||
|
||||
|
||||
if p.FromID != 0 {
|
||||
query.Append("id:>" + strconv.FormatInt(int64(p.FromID), 10))
|
||||
}
|
||||
|
@ -406,7 +410,10 @@ func (p *TorrentParam) toDBQuery(c *gin.Context) *Query {
|
|||
}
|
||||
if p.Status != 0 {
|
||||
query.Append(p.Status.ToDBQuery())
|
||||
} else if !p.Locked {
|
||||
query.Append("status IS NOT ?", 5)
|
||||
}
|
||||
|
||||
if len(p.NotNull) > 0 {
|
||||
query.Append(p.NotNull)
|
||||
}
|
||||
|
|
|
@ -12,13 +12,13 @@ import (
|
|||
func TestTorrentParam_Identifier(t *testing.T) {
|
||||
torrentParam := &TorrentParam{}
|
||||
assert := assert.New(t)
|
||||
assert.Equal("MDAwMDAwMDAwMDBmYWxzZWZhbHNlZmFsc2VmYWxzZQ==", torrentParam.Identifier(), "It should be empty")
|
||||
assert.Equal("MDAwMDAwMDAwMDBmYWxzZWZhbHNlZmFsc2VmYWxzZWZhbHNl", torrentParam.Identifier(), "It should be empty")
|
||||
torrentParam = &TorrentParam{
|
||||
NameLike: "test",
|
||||
NotNull: "IS NULL",
|
||||
Hidden: false,
|
||||
}
|
||||
assert.Equal("dGVzdElTIE5VTEwwMDAwMDAwMDAwMGZhbHNlZmFsc2VmYWxzZWZhbHNl", torrentParam.Identifier(), "It should be empty")
|
||||
assert.Equal("dGVzdElTIE5VTEwwMDAwMDAwMDAwMGZhbHNlZmFsc2VmYWxzZWZhbHNlZmFsc2U=", torrentParam.Identifier(), "It should be empty")
|
||||
}
|
||||
|
||||
func TestTorrentParam_FromRequest(t *testing.T) {
|
||||
|
@ -57,14 +57,14 @@ func TestTorrentParam_ToESQuery(t *testing.T) {
|
|||
Test TorrentParam
|
||||
Expected string
|
||||
}{
|
||||
{TorrentParam{}, ""},
|
||||
{TorrentParam{NameLike: "lol"}, ""},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12}, "id:>12"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, FromDate: DateFilter("2017-08-01"), ToDate: DateFilter("2017-08-05")}, "id:>12 date: [2017-08-01 2017-08-05]"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, ToDate: DateFilter("2017-08-05")}, "id:>12 date: [* 2017-08-05]"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, FromDate: DateFilter("2017-08-01")}, "id:>12 date: [2017-08-01 *]"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, Category: Categories{&Category{3, 12}}}, "(category: 3 AND sub_category: 12) id:>12"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, Category: Categories{&Category{3, 12}, &Category{3, 12}}}, "((category: 3 AND sub_category: 12) OR (category: 3 AND sub_category: 12)) id:>12"},
|
||||
{TorrentParam{}, "!(status:5)"},
|
||||
{TorrentParam{NameLike: "lol"}, "!(status:5)"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12}, "!(status:5) id:>12"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, FromDate: DateFilter("2017-08-01"), ToDate: DateFilter("2017-08-05")}, "!(status:5) id:>12 date: [2017-08-01 2017-08-05]"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, ToDate: DateFilter("2017-08-05")}, "!(status:5) id:>12 date: [* 2017-08-05]"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, FromDate: DateFilter("2017-08-01")}, "!(status:5) id:>12 date: [2017-08-01 *]"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, Category: Categories{&Category{3, 12}}}, "(category: 3 AND sub_category: 12) !(status:5) id:>12"},
|
||||
{TorrentParam{NameLike: "lol", FromID: 12, Category: Categories{&Category{3, 12}, &Category{3, 12}}}, "((category: 3 AND sub_category: 12) OR (category: 3 AND sub_category: 12)) !(status:5) id:>12"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
@ -174,6 +174,9 @@ func UpdateTorrent(r *torrentValidator.UpdateRequest, t *models.Torrent, current
|
|||
} else if currentUser.IsTrusted() {
|
||||
status = models.TorrentStatusTrusted
|
||||
}
|
||||
if status != t.Status && status != models.TorrentStatusBlocked {
|
||||
t.DeletedAt = nil
|
||||
}
|
||||
t.Status = status
|
||||
|
||||
t.Hidden = r.Update.Hidden
|
||||
|
|
Référencer dans un nouveau ticket