diff --git a/controllers/activities/activities.go b/controllers/activities/activities.go index 972dc2df..56d75cff 100644 --- a/controllers/activities/activities.go +++ b/controllers/activities/activities.go @@ -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) } diff --git a/controllers/api/api.go b/controllers/api/api.go index fbd9ea8a..b4466b5b 100644 --- a/controllers/api/api.go +++ b/controllers/api/api.go @@ -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) diff --git a/controllers/feed/helpers.go b/controllers/feed/helpers.go index 76a7dffa..7a49e013 100644 --- a/controllers/feed/helpers.go +++ b/controllers/feed/helpers.go @@ -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 } diff --git a/controllers/middlewares/middlewares.go b/controllers/middlewares/middlewares.go index a0264408..7fd59722 100644 --- a/controllers/middlewares/middlewares.go +++ b/controllers/middlewares/middlewares.go @@ -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() diff --git a/controllers/moderator/comments.go b/controllers/moderator/comments.go index 26952c8e..38d02e73 100644 --- a/controllers/moderator/comments.go +++ b/controllers/moderator/comments.go @@ -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") diff --git a/controllers/moderator/helpers.go b/controllers/moderator/helpers.go index ded87655..97de3f3a 100644 --- a/controllers/moderator/helpers.go +++ b/controllers/moderator/helpers.go @@ -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) diff --git a/controllers/moderator/index.go b/controllers/moderator/index.go index 8783910c..8542f313 100644 --- a/controllers/moderator/index.go +++ b/controllers/moderator/index.go @@ -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") +} diff --git a/controllers/moderator/router.go b/controllers/moderator/router.go index 6fd0e94e..612d30b4 100644 --- a/controllers/moderator/router.go +++ b/controllers/moderator/router.go @@ -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) diff --git a/controllers/moderator/torrents.go b/controllers/moderator/torrents.go index b594f5e9..e3d5cb10 100644 --- a/controllers/moderator/torrents.go +++ b/controllers/moderator/torrents.go @@ -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 diff --git a/controllers/search/search.go b/controllers/search/search.go index e2ef86a5..8fa9c506 100644 --- a/controllers/search/search.go +++ b/controllers/search/search.go @@ -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 diff --git a/controllers/torrent/comment.go b/controllers/torrent/comment.go index 350f2c6d..4924edd1 100644 --- a/controllers/torrent/comment.go +++ b/controllers/torrent/comment.go @@ -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) } diff --git a/controllers/torrent/delete.go b/controllers/torrent/delete.go index 5f853fa1..a45b5269 100644 --- a/controllers/torrent/delete.go +++ b/controllers/torrent/delete.go @@ -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) diff --git a/controllers/torrent/edit.go b/controllers/torrent/edit.go index 5c387995..2f282ec4 100644 --- a/controllers/torrent/edit.go +++ b/controllers/torrent/edit.go @@ -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 } diff --git a/controllers/torrent/stats.go b/controllers/torrent/stats.go index cf893173..f11dffa6 100644 --- a/controllers/torrent/stats.go +++ b/controllers/torrent/stats.go @@ -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) } } diff --git a/controllers/torrent/view.go b/controllers/torrent/view.go index e32cbed2..123a0b73 100644 --- a/controllers/torrent/view.go +++ b/controllers/torrent/view.go @@ -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) } diff --git a/controllers/upload/upload.go b/controllers/upload/upload.go index 67171037..ece7310b 100644 --- a/controllers/upload/upload.go +++ b/controllers/upload/upload.go @@ -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) diff --git a/controllers/user/profile.go b/controllers/user/profile.go index 634ac395..9e9f157f 100644 --- a/controllers/user/profile.go +++ b/controllers/user/profile.go @@ -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 diff --git a/controllers/user/router.go b/controllers/user/router.go index 33e62ef7..7bc9f4c4 100644 --- a/controllers/user/router.go +++ b/controllers/user/router.go @@ -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) diff --git a/models/torrent.go b/models/torrent.go index e68ed7d0..a533157f 100644 --- a/models/torrent.go +++ b/models/torrent.go @@ -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{}) } diff --git a/models/torrents/find.go b/models/torrents/find.go index a7e915ee..7f091ed5 100644 --- a/models/torrents/find.go +++ b/models/torrents/find.go @@ -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) diff --git a/models/user.go b/models/user.go index cb9f49cc..5016d931 100644 --- a/models/user.go +++ b/models/user.go @@ -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" } diff --git a/models/users/helpers.go b/models/users/helpers.go index fdb4a0e0..321467ea 100644 --- a/models/users/helpers.go +++ b/models/users/helpers.go @@ -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 diff --git a/public/css/main.css b/public/css/main.css index 836ff1e5..da2eebd8 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -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; } diff --git a/templates/admin/guidelines.jet.html b/templates/admin/guidelines.jet.html new file mode 100644 index 00000000..68804848 --- /dev/null +++ b/templates/admin/guidelines.jet.html @@ -0,0 +1,8 @@ +{{ extends "layouts/index_admin" }} +{{block title()}}{{ T("moderation_guidelines") }}{{end}} +{{ block content_body()}} +
+

{{ T("moderation_guidelines") }}

+ +
+{{end}} diff --git a/templates/admin/index.jet.html b/templates/admin/index.jet.html index 00cde9b2..61390077 100644 --- a/templates/admin/index.jet.html +++ b/templates/admin/index.jet.html @@ -14,19 +14,26 @@ {{range Torrents}} - + {{ .Name }} {{ T("edit") }} - {{ .UploaderID }} + {{ if .Uploader }}{{.Uploader.Username }}{{else}}れんちょん{{end}} -
- - -
+ {{ if User.IsModerator() }} +
+ + {{ if .IsDeleted() }}{{ end }} + +
+ {{end}} +
+ + +
{{end}} @@ -88,10 +95,16 @@ {{ .Username }} {{if .ID > 0}} -
- {{ yield csrf_field()}} - -
+ {{ if User.IsModerator() }} +
+ {{ yield csrf_field()}} + +
+ {{end}} +
+ {{ yield csrf_field()}} + +
{{end}} diff --git a/templates/admin/torrentlist.jet.html b/templates/admin/torrentlist.jet.html index 5d12f5d8..82b23e83 100644 --- a/templates/admin/torrentlist.jet.html +++ b/templates/admin/torrentlist.jet.html @@ -38,12 +38,12 @@ {{ range Models}} - + - {{ .Name }} {{ if !.IsDeleted }} + {{ .Name }} {{ if User.IsModerator() }} {{ T("edit")}} {{end}} @@ -57,14 +57,15 @@
- +
+ {{ if User.IsModerator() }}
- {{ if .IsDeleted }}{{ end }} - + {{ if .IsDeleted() }}{{ end }} +
- + {{end}} {{end}} diff --git a/templates/admin/userlist.jet.html b/templates/admin/userlist.jet.html index a7600796..511a7152 100644 --- a/templates/admin/userlist.jet.html +++ b/templates/admin/userlist.jet.html @@ -13,7 +13,7 @@ {{ range Models}} - + {{ .Username }} @@ -21,7 +21,10 @@ {{if .ID > 0}}
{{ yield csrf_field()}} + {{ if User.IsModerator() }} + {{end}} +
{{end}} diff --git a/templates/errors/torrent_file_missing.jet.html b/templates/errors/torrent_file_missing.jet.html index 1eb8727a..c0d5f0e4 100644 --- a/templates/errors/torrent_file_missing.jet.html +++ b/templates/errors/torrent_file_missing.jet.html @@ -7,7 +7,7 @@
{{ T("magnet_link")}}
- {{ if !isset(Errors[name])}}

{{ T("pending_torrent") }}

{{end}}

+ {{ if !isset(Errors["errors"])}}

{{ T("pending_torrent") }}

{{end}}

{{ end }} No torrent file diff --git a/templates/layouts/partials/helpers/badgemenu.jet.html b/templates/layouts/partials/helpers/badgemenu.jet.html index 17a77187..ec5ec00e 100644 --- a/templates/layouts/partials/helpers/badgemenu.jet.html +++ b/templates/layouts/partials/helpers/badgemenu.jet.html @@ -1,18 +1,18 @@ {{ import "csrf" }} {{block badge_user()}} -
+
{{if User.ID > 0 }}
- {{ T("profile")}} + {{ T("profile")}}{{ if User.IsBanned() }} ({{T("banned")}}){{end}} {{ T("my_notifications")}} {{if User.GetUnreadNotifications() > 0}}({{ User.GetUnreadNotifications() }}){{end}} @@ -20,7 +20,7 @@ {{ T("settings")}} - {{if User.HasAdmin()}} + {{if User.IsJanitor()}} {{ T("moderation")}} {{end}}
diff --git a/templates/layouts/partials/helpers/oldNav.jet.html b/templates/layouts/partials/helpers/oldNav.jet.html index 270e5748..3790c884 100644 --- a/templates/layouts/partials/helpers/oldNav.jet.html +++ b/templates/layouts/partials/helpers/oldNav.jet.html @@ -13,7 +13,6 @@ {{ if _% 3 != 2}}{{ if _% 3 == 0}}{{end}}{{end}} {{end}} {{ end }} - {{ if Search.Category != ""}} diff --git a/templates/layouts/partials/menu/admin.jet.html b/templates/layouts/partials/menu/admin.jet.html index 2b1f7a78..1e993ce2 100644 --- a/templates/layouts/partials/menu/admin.jet.html +++ b/templates/layouts/partials/menu/admin.jet.html @@ -7,4 +7,5 @@ {{ T("announcements")}} {{ T("torrent_reports")}} {{ T("torrent_reassign")}} + {{ T("guidelines")}}
diff --git a/templates/layouts/partials/menu/profile.jet.html b/templates/layouts/partials/menu/profile.jet.html index ee9fa8c9..cfd6d7a5 100644 --- a/templates/layouts/partials/menu/profile.jet.html +++ b/templates/layouts/partials/menu/profile.jet.html @@ -1,5 +1,6 @@ +{{ import "layouts/partials/helpers/csrf" }} {{ block profile_menu(route="profile") }} -
+
{{ UserProfile.Username }} @@ -10,9 +11,11 @@

{{ UserProfile.Username}}

+ {{ if UserProfile.GetRole() != "" }}

{{T(UserProfile.GetRole())}}

+ {{end}}

{{T("followers")}}: {{len(UserProfile.Followers)}}
{{ T("torrents_uploaded") }}:{{ NbTorrents[0] }}
{{T("size")}}: {{fileSize(NbTorrents[1], T, false)}}

@@ -43,12 +46,19 @@ {{ if User.CurrentUserIdentical(UserProfile.ID) }} {{ T("my_notifications")}} {{end}} - {{if UserProfile.ID > 0 && User.CurrentOrAdmin(UserProfile.ID) }} - - {{ T("settings")}} - - {{end}} + {{if UserProfile.ID > 0}} + {{ if User.CurrentOrAdmin(UserProfile.ID) }} + + {{ T("settings")}} + + {{else if User.IsJanitor() && !UserProfile.IsJanitor() }} + + {{ yield csrf_field()}} + + + {{end}} {{end}} + {{end}}
{{ if User.ID != UserProfile.ID }} -{{ if User.HasAdmin() }} +{{ if User.IsModerator() }}
@@ -175,7 +175,7 @@ -{{ if User.HasAdmin() }} +{{ if User.IsModerator() }}