From 32c51a57cb7acea481846c13a747b5923a5d6fa4 Mon Sep 17 00:00:00 2001 From: akuma06 Date: Sun, 21 May 2017 18:13:28 +0200 Subject: [PATCH 1/4] User Settings Notification (WIP) --- config/notifications.go | 13 ++++++++++++ model/user.go | 31 ++++++++++++++++++++++++++- router/upload_handler.go | 10 +++++---- router/user_handler.go | 30 ++++++++++++++------------ service/user/form/form_validator.go | 33 +++++++++++++++++++++-------- util/modelHelper/model_helper.go | 28 +++++++++++++----------- 6 files changed, 105 insertions(+), 40 deletions(-) create mode 100644 config/notifications.go diff --git a/config/notifications.go b/config/notifications.go new file mode 100644 index 00000000..05cc4b94 --- /dev/null +++ b/config/notifications.go @@ -0,0 +1,13 @@ +package config + + +/* + * Here we config the notifications options + */ +var EnableNotifications = map[string]bool { + "new_torrent": true, + "new_comment_owner": true, + "new_comment_all": true, + "new_follower": false, + "followed": false, +} \ No newline at end of file diff --git a/model/user.go b/model/user.go index d6dc565c..c15b4f30 100644 --- a/model/user.go +++ b/model/user.go @@ -24,6 +24,7 @@ type User struct { ApiToken string `gorm:"column:api_token"` ApiTokenExpiry time.Time `gorm:"column:api_token_expiry"` Language string `gorm:"column:language"` + UserSettings string `gorm:"column:settings"` // TODO: move this to PublicUser Likings []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"` @@ -31,9 +32,10 @@ type User struct { MD5 string `json:"md5" gorm:"column:md5"` // Hash of email address, used for Gravatar Torrents []Torrent `gorm:"ForeignKey:UploaderID"` + Notifications []Notification `gorm:"ForeignKey:UserID"` UnreadNotifications int `gorm:"-"` // We don't want to loop every notifications when accessing user unread notif - Notifications []Notification `gorm:"ForeignKey:UserID"` + Settings *UserSettings `gorm:"-"` // We don't want to loop every notifications when accessing user unread notif } type UserJSON struct { @@ -99,6 +101,10 @@ type UserUploadsOld struct { TorrentId uint `gorm:"column:torrent_id"` } +type UserSettings struct { + settings map[string]interface{} `json:"settings"` +} + func (c UserUploadsOld) TableName() string { // is this needed here? return config.UploadsOldTableName @@ -115,3 +121,26 @@ func (u *User) ToJSON() UserJSON { } return json } + +/* User Settings */ + +func(s *UserSettings) Get(key string) interface{} { + return s.settings[key] +} + +func (s *UserSettings) Set(key string, val interface{}) { + s.settings[key] = val +} + +func (s *UserSettings) GetSettings() { + return s.settings +} + +func (u *User) SaveSettings() { + u.UserSettings , _ = json.Marshal(u.Settings.GetSettings()) +} + +func (u *User) ParseSettings() { + if len(u.Settings.GetSettings()) == 0 + json.Unmarshal([]byte(u.UserSettings), u.Settings) +} \ No newline at end of file diff --git a/router/upload_handler.go b/router/upload_handler.go index fadd73f4..717be98b 100644 --- a/router/upload_handler.go +++ b/router/upload_handler.go @@ -79,14 +79,16 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) { url, err := Router.Get("view_torrent").URL("id", strconv.FormatUint(uint64(torrent.ID), 10)) - if (user.ID > 0) { // If we are a member + if (user.ID > 0 && config.EnableNotifications["new_torrent"]) { // If we are a member and notifications for new torrents are enabled userService.GetLikings(user) // We populate the liked field for users if len(user.Likings) > 0 { // If we are followed by at least someone for _, follower := range user.Likings { - T, _, _ := languages.TfuncAndLanguageWithFallback(user.Language, user.Language) // We need to send the notification to every user in their language + follower.ParseSettings() // We need to call it before checking settings + if follower.Settings.Get("notifications.new_torrent"] { + T, _, _ := languages.TfuncAndLanguageWithFallback(user.Language, user.Language) // We need to send the notification to every user in their language - notifierService.NotifyUser(&follower, torrent.Identifier(), fmt.Sprintf(T("new_torrent_uploaded"), torrent.Name, user.Username), url.String()) - + notifierService.NotifyUser(&follower, torrent.Identifier(), fmt.Sprintf(T("new_torrent_uploaded"), torrent.Name, user.Username), url.String()) + } } } } diff --git a/router/user_handler.go b/router/user_handler.go index 3ef4a324..65e083e6 100644 --- a/router/user_handler.go +++ b/router/user_handler.go @@ -137,40 +137,42 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) { NotFoundHandler(w, r) return } - + messages := msg.GetMessages(r) userForm := form.UserForm{} - err := form.NewErrors() - infos := form.NewInfos() + userSettingsForm := form.UserSettingsForm{} + + T := languages.GetTfuncFromRequest(r) if len(r.PostFormValue("email")) > 0 { - _, err = form.EmailValidation(r.PostFormValue("email"), err) + form.EmailValidation(r.PostFormValue("email"), &messages) } if len(r.PostFormValue("username")) > 0 { - _, err = form.ValidateUsername(r.PostFormValue("username"), err) + form.ValidateUsername(r.PostFormValue("username"), &messages) } - if len(err) == 0 { + if !messages.HasErrors() { modelHelper.BindValueForm(&userForm, r) + modelHelper.BindValueForm(&userSettingsForm, r) if !userPermission.HasAdmin(currentUser) { userForm.Username = userProfile.Username userForm.Status = userProfile.Status } else { if userProfile.Status != userForm.Status && userForm.Status == 2 { - err["errors"] = append(err["errors"], "Elevating status to moderator is prohibited") + messages.AddError("errors", "Elevating status to moderator is prohibited") } } - err = modelHelper.ValidateForm(&userForm, err) - if len(err) == 0 { + modelHelper.ValidateForm(&userForm, &messages) + if !messages.HasErrors() { if userForm.Email != userProfile.Email { userService.SendVerificationToUser(*currentUser, userForm.Email) - infos["infos"] = append(infos["infos"], fmt.Sprintf(string(T("email_changed")), userForm.Email)) + messages.AddInfof("infos", string(T("email_changed")), userForm.Email) userForm.Email = userProfile.Email // reset, it will be set when user clicks verification } userProfile, _, errorUser = userService.UpdateUser(w, &userForm, currentUser, id) if errorUser != nil { - err["errors"] = append(err["errors"], errorUser.Error()) + messages.ImportFromError("errors", errorUser) } else { - infos["infos"] = append(infos["infos"], string(T("profile_updated"))) + messages.AddInfo("infos", string(T("profile_updated"))) } } } @@ -179,8 +181,8 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) { CommonTemplateVariables: NewCommonVariables(r), UserProfile: &userProfile, UserForm: userForm, - FormErrors: err, - FormInfos: infos, + FormErrors: messages.GetAllErrors(), + FormInfos: messages.GetAllInfos(), Languages: availableLanguages, } errorTmpl := viewProfileEditTemplate.ExecuteTemplate(w, "index.html", upev) diff --git a/service/user/form/form_validator.go b/service/user/form/form_validator.go index 16dcc0a1..9d07a043 100644 --- a/service/user/form/form_validator.go +++ b/service/user/form/form_validator.go @@ -4,33 +4,34 @@ import ( "regexp" "github.com/NyaaPantsu/nyaa/util/log" + msg "github.com/NyaaPantsu/nyaa/util/messages" ) const EMAIL_REGEX = `(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})` const USERNAME_REGEX = `(\W)` -func EmailValidation(email string, err map[string][]string) (bool, map[string][]string) { +func EmailValidation(email string, mes *msg.Messages) bool { exp, errorRegex := regexp.Compile(EMAIL_REGEX) if regexpCompiled := log.CheckError(errorRegex); regexpCompiled { if exp.MatchString(email) { - return true, err + return true } } - err["email"] = append(err["email"], "Email Address is not valid") - return false, err + mes.AddError("email", "Email Address is not valid") + return false } -func ValidateUsername(username string, err map[string][]string) (bool, map[string][]string) { +func ValidateUsername(username string, mes *msg.Messages) bool { exp, errorRegex := regexp.Compile(USERNAME_REGEX) if regexpCompiled := log.CheckError(errorRegex); regexpCompiled { if exp.MatchString(username) { - err["username"] = append(err["username"], "Username contains illegal characters") - return false, err + mes.AddError("username", "Username contains illegal characters") + return false } } else { - return false, err + return false } - return true, err + return true } func NewErrors() map[string][]string { @@ -73,6 +74,20 @@ type UserForm struct { Status int `form:"status" default:"0"` } +// UserSettingsForm is used when updating a user. +type UserSettingsForm struct { + NewTorrent bool `form:"new_torrent" default:"true"` + NewTorrentEmail bool `form:"new_torrent_email" default:"true"` + NewComment bool `form:"new_comment" default:"true"` + NewCommentEmail bool `form:"new_comment_email" default:"false"` + NewResponses bool `form:"new_responses" default:"true"` + NewResponsesEmail bool `form:"new_responses_email" default:"false"` + NewFollower bool `form:"new_follower" default:"true"` + NewFollowerEmail bool `form:"new_follower_email" default:"true"` + Followed bool `form:"followed" default:"false"` + FollowedEmail bool `form:"followed_email" default:"false"` +} + // PasswordForm is used when updating a user password. type PasswordForm struct { CurrentPassword string `form:"currentPassword"` diff --git a/util/modelHelper/model_helper.go b/util/modelHelper/model_helper.go index 9d42f5cd..a22fb649 100644 --- a/util/modelHelper/model_helper.go +++ b/util/modelHelper/model_helper.go @@ -3,6 +3,7 @@ package modelHelper import ( "fmt" "github.com/NyaaPantsu/nyaa/util/log" + msg "github.com/NyaaPantsu/nyaa/util/messages" "net/http" "reflect" "strconv" @@ -57,7 +58,7 @@ func BindValueForm(form interface{}, r *http.Request) { } } -func ValidateForm(form interface{}, errorForm map[string][]string) map[string][]string { +func ValidateForm(form interface{}, mes *msg.Messages) { formElem := reflect.ValueOf(form).Elem() for i := 0; i < formElem.NumField(); i++ { typeField := formElem.Type().Field(i) @@ -69,28 +70,28 @@ func ValidateForm(form interface{}, errorForm map[string][]string) map[string][] if tag.Get("len_min") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) { // Check minimum length lenMin, _ := strconv.Atoi(tag.Get("len_min")) if formElem.Field(i).Len() < lenMin { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Minimal length of %s required for the input: %s", strconv.Itoa(lenMin), inputName)) + mes.AddErrorf(tag.Get("form"), "Minimal length of %s required for the input: %s", strconv.Itoa(lenMin), inputName) } } if tag.Get("len_max") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) { // Check maximum length lenMax, _ := strconv.Atoi(tag.Get("len_max")) if formElem.Field(i).Len() > lenMax { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Maximal length of %s required for the input: %s", strconv.Itoa(lenMax), inputName)) + mes.AddErrorf(tag.Get("form"), "Maximal length of %s required for the input: %s", strconv.Itoa(lenMax), inputName) } } if tag.Get("equalInput") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) { otherInput := formElem.FieldByName(tag.Get("equalInput")) if formElem.Field(i).Interface() != otherInput.Interface() { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Must be same %s", inputName)) + mes.AddErrorf(tag.Get("form"), "Must be same %s", inputName) } } switch typeField.Type.Name() { case "string": if tag.Get("equal") != "" && formElem.Field(i).String() != tag.Get("equal") { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName)) + mes.AddErrorf(tag.Get("form"), "Wrong value for the input: %s", inputName) } if tag.Get("needed") != "" && formElem.Field(i).String() == "" { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName)) + mes.AddErrorf(tag.Get("form"), "Field needed: %s", inputName) } if formElem.Field(i).String() == "" && tag.Get("default") != "" { formElem.Field(i).SetString(tag.Get("default")) @@ -99,11 +100,11 @@ func ValidateForm(form interface{}, errorForm map[string][]string) map[string][] if tag.Get("equal") != "" { // Check minimum length equal, _ := strconv.Atoi(tag.Get("equal")) if formElem.Field(i).Int() > int64(equal) { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName)) + mes.AddErrorf(tag.Get("form"), "Wrong value for the input: %s", inputName) } } if tag.Get("needed") != "" && formElem.Field(i).Int() == 0 { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName)) + mes.AddErrorf(tag.Get("form"), "Field needed: %s", inputName) } if formElem.Field(i).Interface == nil && tag.Get("default") != "" { defaultValue, _ := strconv.Atoi(tag.Get("default")) @@ -113,11 +114,11 @@ func ValidateForm(form interface{}, errorForm map[string][]string) map[string][] if tag.Get("equal") != "" { // Check minimum length equal, _ := strconv.Atoi(tag.Get("equal")) if formElem.Field(i).Float() != float64(equal) { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName)) + mes.AddErrorf(tag.Get("form"), "Wrong value for the input: %s", inputName) } } if tag.Get("needed") != "" && formElem.Field(i).Float() == 0 { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Field needed: %s", inputName)) + mes.AddErrorf(tag.Get("form"), "Field needed: %s", inputName) } if formElem.Field(i).Interface == nil && tag.Get("default") != "" { defaultValue, _ := strconv.Atoi(tag.Get("default")) @@ -127,10 +128,13 @@ func ValidateForm(form interface{}, errorForm map[string][]string) map[string][] if tag.Get("equal") != "" { // Check minimum length equal, _ := strconv.ParseBool(tag.Get("equal")) if formElem.Field(i).Bool() != equal { - errorForm[tag.Get("form")] = append(errorForm[tag.Get("form")], fmt.Sprintf("Wrong value for the input: %s", inputName)) + mes.AddErrorf(tag.Get("form"), "Wrong value for the input: %s", inputName) } } + if formElem.Field(i).Interface == nil && tag.Get("default") != "" { + defaultValue, _ := strconv.ParseBool(tag.Get("default")) + formElem.Field(i).SetBool(defaultValue) + } } } - return errorForm } From 56390333703d91a5bd32ec2001cb5e66619e52f3 Mon Sep 17 00:00:00 2001 From: akuma06 Date: Sun, 21 May 2017 19:38:39 +0200 Subject: [PATCH 2/4] Wiiiiiip --- config/notifications.go | 13 ----- config/user_settings.go | 22 ++++++++ model/user.go | 31 ++++++---- router/modpanel.go | 23 ++++---- router/upload_handler.go | 2 +- router/user_handler.go | 100 ++++++++++++++++----------------- router/view_torrent_handler.go | 71 ++++++++++------------- service/user/user.go | 2 + 8 files changed, 133 insertions(+), 131 deletions(-) delete mode 100644 config/notifications.go create mode 100644 config/user_settings.go diff --git a/config/notifications.go b/config/notifications.go deleted file mode 100644 index 05cc4b94..00000000 --- a/config/notifications.go +++ /dev/null @@ -1,13 +0,0 @@ -package config - - -/* - * Here we config the notifications options - */ -var EnableNotifications = map[string]bool { - "new_torrent": true, - "new_comment_owner": true, - "new_comment_all": true, - "new_follower": false, - "followed": false, -} \ No newline at end of file diff --git a/config/user_settings.go b/config/user_settings.go new file mode 100644 index 00000000..b6c38f96 --- /dev/null +++ b/config/user_settings.go @@ -0,0 +1,22 @@ +package config + + +/* + * Here we config the notifications options + * Uses in user model for default setting + * Be aware, default values in user update form are + * in service/user/form/form_validator.go + */ + +var DefaultUserSettings = map[string]bool { + "new_torrent": true, + "new_torrent_email": false, + "new_comment": true, + "new_comment_email": false, + "new_responses": true, + "new_responses_email": false, + "new_follower": false, + "new_follower_email": false, + "followed": false, + "followed_email": false, +} \ No newline at end of file diff --git a/model/user.go b/model/user.go index c15b4f30..61b44bc5 100644 --- a/model/user.go +++ b/model/user.go @@ -35,7 +35,7 @@ type User struct { Notifications []Notification `gorm:"ForeignKey:UserID"` UnreadNotifications int `gorm:"-"` // We don't want to loop every notifications when accessing user unread notif - Settings *UserSettings `gorm:"-"` // We don't want to loop every notifications when accessing user unread notif + Settings UserSettings `gorm:"-"` // We don't want to load settings everytime, stock it as a string, parse it when needed } type UserJSON struct { @@ -124,23 +124,32 @@ func (u *User) ToJSON() UserJSON { /* User Settings */ -func(s *UserSettings) Get(key string) interface{} { +func(s UserSettings) Get(key string) interface{} { + if (s.settings[key] != nil) { return s.settings[key] + } else { + return config.DefaultUserSettings[key] + } } -func (s *UserSettings) Set(key string, val interface{}) { - s.settings[key] = val -} - -func (s *UserSettings) GetSettings() { +func (s UserSettings) GetSettings() { return s.settings } -func (u *User) SaveSettings() { +func (s UserSettings) Set(key string, val interface{}) { + s.settings[key] = val +} + +func (s UserSettings) ToDefault() { + s.settings = config.DefaultUserSettings +} + +func (u User) SaveSettings() { u.UserSettings , _ = json.Marshal(u.Settings.GetSettings()) } -func (u *User) ParseSettings() { - if len(u.Settings.GetSettings()) == 0 - json.Unmarshal([]byte(u.UserSettings), u.Settings) +func (u User) ParseSettings() { + if len(u.Settings.GetSettings()) == 0 && u.UserSettings != "" { + json.Unmarshal([]byte(u.UserSettings), u.Settings) + } } \ No newline at end of file diff --git a/router/modpanel.go b/router/modpanel.go index 305a2574..d2bcd08a 100644 --- a/router/modpanel.go +++ b/router/modpanel.go @@ -251,15 +251,15 @@ func TorrentEditModPanel(w http.ResponseWriter, r *http.Request) { func TorrentPostEditModPanel(w http.ResponseWriter, r *http.Request) { var uploadForm UploadForm id := r.URL.Query().Get("id") - err := form.NewErrors() + messages := msg.GetMessages(r) infos := form.NewInfos() torrent, _ := torrentService.GetTorrentById(id) if torrent.ID > 0 { errUp := uploadForm.ExtractEditInfo(r) if errUp != nil { - err["errors"] = append(err["errors"], "Failed to update torrent!") + messages.AddError("errors", "Failed to update torrent!") } - if len(err) == 0 { + if !messages.HasErrors() { // update some (but not all!) values torrent.Name = uploadForm.Name torrent.Category = uploadForm.CategoryID @@ -269,10 +269,10 @@ func TorrentPostEditModPanel(w http.ResponseWriter, r *http.Request) { torrent.Description = uploadForm.Description torrent.Uploader = nil // GORM will create a new user otherwise (wtf?!) db.ORM.Save(&torrent) - infos["infos"] = append(infos["infos"], "Torrent details updated.") + messages.AddInfo("infos", "Torrent details updated.") } } - htv := PanelTorrentEdVbs{NewPanelCommonVariables(r), uploadForm, err, infos} + htv := PanelTorrentEdVbs{NewPanelCommonVariables(r), uploadForm, messages.GetAllErrors(), messages.GetAllInfos()} err_ := panelTorrentEd.ExecuteTemplate(w, "admin_index.html", htv) log.CheckError(err_) } @@ -280,7 +280,6 @@ func TorrentPostEditModPanel(w http.ResponseWriter, r *http.Request) { func CommentDeleteModPanel(w http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") - _ = form.NewErrors() _, _ = userService.DeleteComment(id) url, _ := Router.Get("mod_clist").URL() http.Redirect(w, r, url.String()+"?deleted", http.StatusSeeOther) @@ -288,7 +287,6 @@ func CommentDeleteModPanel(w http.ResponseWriter, r *http.Request) { func TorrentDeleteModPanel(w http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") - _ = form.NewErrors() _, _ = torrentService.DeleteTorrent(id) //delete reports of torrent @@ -305,7 +303,6 @@ func TorrentReportDeleteModPanel(w http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") fmt.Println(id) idNum, _ := strconv.ParseUint(id, 10, 64) - _ = form.NewErrors() _, _ = reportService.DeleteTorrentReport(uint(idNum)) url, _ := Router.Get("mod_trlist").URL() @@ -320,22 +317,22 @@ func TorrentReassignModPanel(w http.ResponseWriter, r *http.Request) { func TorrentPostReassignModPanel(w http.ResponseWriter, r *http.Request) { var rForm ReassignForm - err := form.NewErrors() + messages := msg.GetMessages(r) infos := form.NewInfos() err2 := rForm.ExtractInfo(r) if err2 != nil { - err["errors"] = append(err["errors"], err2.Error()) + messages.ImportFromError("errors", err2) } else { count, err2 := rForm.ExecuteAction() if err2 != nil { - err["errors"] = append(err["errors"], "Something went wrong") + messages.AddError("errors", "Something went wrong") } else { - infos["infos"] = append(infos["infos"], fmt.Sprintf("%d torrents updated.", count)) + messages.AddInfof("infos", "%d torrents updated.", count) } } - htv := PanelTorrentReassignVbs{NewPanelCommonVariables(r), rForm, err, infos} + htv := PanelTorrentReassignVbs{NewPanelCommonVariables(r), rForm, messages.GetAllErrors(), messages.GetAllInfos()} err_ := panelTorrentReassign.ExecuteTemplate(w, "admin_index.html", htv) log.CheckError(err_) } diff --git a/router/upload_handler.go b/router/upload_handler.go index 717be98b..88e01919 100644 --- a/router/upload_handler.go +++ b/router/upload_handler.go @@ -79,7 +79,7 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) { url, err := Router.Get("view_torrent").URL("id", strconv.FormatUint(uint64(torrent.ID), 10)) - if (user.ID > 0 && config.EnableNotifications["new_torrent"]) { // If we are a member and notifications for new torrents are enabled + if (user.ID > 0 && config.DefaultUserSettings["new_torrent"]) { // If we are a member and notifications for new torrents are enabled userService.GetLikings(user) // We populate the liked field for users if len(user.Likings) > 0 { // If we are followed by at least someone for _, follower := range user.Likings { diff --git a/router/user_handler.go b/router/user_handler.go index 65e083e6..0131c078 100644 --- a/router/user_handler.go +++ b/router/user_handler.go @@ -25,13 +25,14 @@ func UserRegisterFormHandler(w http.ResponseWriter, r *http.Request) { HomeHandler(w, r) return } + messages := msg.GetMessages(r) registrationForm := form.RegistrationForm{} modelHelper.BindValueForm(®istrationForm, r) registrationForm.CaptchaID = captcha.GetID() urtv := UserRegisterTemplateVariables{ CommonTemplateVariables: NewCommonVariables(r), RegistrationForm: registrationForm, - FormErrors: form.NewErrors(), + FormErrors: messages.GetAllErrors(), } err := viewRegisterTemplate.ExecuteTemplate(w, "index.html", urtv) if err != nil { @@ -41,13 +42,20 @@ func UserRegisterFormHandler(w http.ResponseWriter, r *http.Request) { // Getting View User Login func UserLoginFormHandler(w http.ResponseWriter, r *http.Request) { + _, errorUser := userService.CurrentUser(r) + // User is already connected, redirect to home + if errorUser == nil { + HomeHandler(w, r) + return + } + loginForm := form.LoginForm{} modelHelper.BindValueForm(&loginForm, r) - + messages := msg.GetMessages(r) ulfv := UserLoginFormVariables{ CommonTemplateVariables: NewCommonVariables(r), LoginForm: loginForm, - FormErrors: form.NewErrors(), + FormErrors: messages.GetAllErrors(), } err := viewLoginTemplate.ExecuteTemplate(w, "index.html", ulfv) @@ -61,33 +69,33 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] T := languages.GetTfuncFromRequest(r) + messages := msg.GetMessages(r) + userProfile, _, errorUser := userService.RetrieveUserForAdmin(id) if errorUser == nil { currentUser := GetUser(r) follow := r.URL.Query()["followed"] unfollow := r.URL.Query()["unfollowed"] - infosForm := form.NewInfos() deleteVar := r.URL.Query()["delete"] if (deleteVar != nil) && (userPermission.CurrentOrAdmin(currentUser, userProfile.ID)) { - err := form.NewErrors() _, errUser := userService.DeleteUser(w, currentUser, id) if errUser != nil { - err["errors"] = append(err["errors"], errUser.Error()) + messages.ImportFromError("errors", errUser) } - htv := UserVerifyTemplateVariables{NewCommonVariables(r), err} + htv := UserVerifyTemplateVariables{NewCommonVariables(r), messages.GetAllErrors()} errorTmpl := viewUserDeleteTemplate.ExecuteTemplate(w, "index.html", htv) if errorTmpl != nil { http.Error(w, errorTmpl.Error(), http.StatusInternalServerError) } } else { if follow != nil { - infosForm["infos"] = append(infosForm["infos"], fmt.Sprintf(string(T("user_followed_msg")), userProfile.Username)) + messages.AddInfof("infos", string(T("user_followed_msg")), userProfile.Username) } if unfollow != nil { - infosForm["infos"] = append(infosForm["infos"], fmt.Sprintf(string(T("user_unfollowed_msg")), userProfile.Username)) + messages.AddInfof("infos", string(T("user_unfollowed_msg")), userProfile.Username) } - htv := UserProfileVariables{NewCommonVariables(r), &userProfile, infosForm} + htv := UserProfileVariables{NewCommonVariables(r), &userProfile, messages.GetAllInfos()} err := viewProfileTemplate.ExecuteTemplate(w, "index.html", htv) if err != nil { @@ -95,10 +103,7 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) { } } } else { - err := notFoundTemplate.ExecuteTemplate(w, "index.html", NotFoundTemplateVariables{NewCommonVariables(r)}) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } + NotFoundHandler(w, r) } } @@ -107,23 +112,22 @@ func UserDetailsHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] currentUser := GetUser(r) + messages := msg.GetMessages(r) + userProfile, _, errorUser := userService.RetrieveUserForAdmin(id) if errorUser == nil && userPermission.CurrentOrAdmin(currentUser, userProfile.ID) { if userPermission.CurrentOrAdmin(currentUser, userProfile.ID) { b := form.UserForm{} modelHelper.BindValueForm(&b, r) availableLanguages := languages.GetAvailableLanguages() - htv := UserProfileEditVariables{NewCommonVariables(r), &userProfile, b, form.NewErrors(), form.NewInfos(), availableLanguages} + htv := UserProfileEditVariables{NewCommonVariables(r), &userProfile, b, messages.GetAllErrors(), messages.GetAllInfos(), availableLanguages} err := viewProfileEditTemplate.ExecuteTemplate(w, "index.html", htv) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } } else { - err := notFoundTemplate.ExecuteTemplate(w, "index.html", NotFoundTemplateVariables{NewCommonVariables(r)}) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } + NotFoundHandler(w, r) } } @@ -194,29 +198,30 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) { // Post Registration controller, we do some check on the form here, the rest on user service func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) { b := form.RegistrationForm{} - err := form.NewErrors() + messages = msg.GetMessages(r) + if !captcha.Authenticate(captcha.Extract(r)) { - err["errors"] = append(err["errors"], "Wrong captcha!") + messages.AddError("errors", "Wrong captcha!") } - if len(err) == 0 { + if !messages.HasErrors() { if len(r.PostFormValue("email")) > 0 { - _, err = form.EmailValidation(r.PostFormValue("email"), err) + form.EmailValidation(r.PostFormValue("email"), &messages) } - _, err = form.ValidateUsername(r.PostFormValue("username"), err) - if len(err) == 0 { + form.ValidateUsername(r.PostFormValue("username"), &messages) + if !messages.HasErrors() { modelHelper.BindValueForm(&b, r) - err = modelHelper.ValidateForm(&b, err) - if len(err) == 0 { + modelHelper.ValidateForm(&b, &messages) + if !messages.HasErrors() { _, errorUser := userService.CreateUser(w, r) if errorUser != nil { - err["errors"] = append(err["errors"], errorUser.Error()) + messages.ImportFromError("errors", errorUser) } - if len(err) == 0 { + if !messages.HasErrors() { common := NewCommonVariables(r) common.User = &model.User{ Email: r.PostFormValue("email"), // indicate whether user had email set } - htv := UserRegisterTemplateVariables{common, b, err} + htv := UserRegisterTemplateVariables{common, b, messages.GetAllErrors()} errorTmpl := viewRegisterSuccessTemplate.ExecuteTemplate(w, "index.html", htv) if errorTmpl != nil { http.Error(w, errorTmpl.Error(), http.StatusInternalServerError) @@ -225,25 +230,21 @@ func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) { } } } - if len(err) > 0 { - b.CaptchaID = captcha.GetID() - htv := UserRegisterTemplateVariables{NewCommonVariables(r), b, err} - errorTmpl := viewRegisterTemplate.ExecuteTemplate(w, "index.html", htv) - if errorTmpl != nil { - http.Error(w, errorTmpl.Error(), http.StatusInternalServerError) - } + if messages.HasErrors() { + UserRegisterFormHandler(w, r) } } func UserVerifyEmailHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) token := vars["token"] - err := form.NewErrors() + messages := msg.GetMessages(r) + _, errEmail := userService.EmailVerification(token, w) if errEmail != nil { - err["errors"] = append(err["errors"], errEmail.Error()) + messages.ImportFromError("errors", errEmail) } - htv := UserVerifyTemplateVariables{NewCommonVariables(r), err} + htv := UserVerifyTemplateVariables{NewCommonVariables(r), messages.GetAllErrors()} errorTmpl := viewVerifySuccessTemplate.ExecuteTemplate(w, "index.html", htv) if errorTmpl != nil { http.Error(w, errorTmpl.Error(), http.StatusInternalServerError) @@ -254,13 +255,14 @@ func UserVerifyEmailHandler(w http.ResponseWriter, r *http.Request) { func UserLoginPostHandler(w http.ResponseWriter, r *http.Request) { b := form.LoginForm{} modelHelper.BindValueForm(&b, r) - err := form.NewErrors() - err = modelHelper.ValidateForm(&b, err) - if len(err) == 0 { + messages := msg.GetAllErrors() + + modelHelper.ValidateForm(&b, &messages) + if !messages.HasErrors() { _, errorUser := userService.CreateUserAuthentication(w, r) if errorUser != nil { - err["errors"] = append(err["errors"], errorUser.Error()) - htv := UserLoginFormVariables{NewCommonVariables(r), b, err} + messages.ImportFromError("errors", errorUser) + htv := UserLoginFormVariables{NewCommonVariables(r), b, messages.GetAllErrors()} errorTmpl := viewLoginTemplate.ExecuteTemplate(w, "index.html", htv) if errorTmpl != nil { http.Error(w, errorTmpl.Error(), http.StatusInternalServerError) @@ -271,12 +273,8 @@ func UserLoginPostHandler(w http.ResponseWriter, r *http.Request) { http.Redirect(w, r, url.String(), http.StatusSeeOther) } } - if len(err) > 0 { - htv := UserLoginFormVariables{NewCommonVariables(r), b, err} - errorTmpl := viewLoginTemplate.ExecuteTemplate(w, "index.html", htv) - if errorTmpl != nil { - http.Error(w, errorTmpl.Error(), http.StatusInternalServerError) - } + if messages.HasErrors() { + UserLoginFormHandler(w,r) } } diff --git a/router/view_torrent_handler.go b/router/view_torrent_handler.go index d293dbaf..e7b80d91 100644 --- a/router/view_torrent_handler.go +++ b/router/view_torrent_handler.go @@ -56,72 +56,59 @@ func PostCommentHandler(w http.ResponseWriter, r *http.Request) { id := vars["id"] currentUser := GetUser(r) + messages := msg.GetMessages(r) + if userPermission.NeedsCaptcha(currentUser) { userCaptcha := captcha.Extract(r) if !captcha.Authenticate(userCaptcha) { - http.Error(w, "bad captcha", 403) - return + messages.AddError("errors", "Bad captcha!") } } content := p.Sanitize(r.FormValue("comment")) if strings.TrimSpace(content) == "" { - http.Error(w, "comment empty", 406) - return + messages.AddError("errors", "Comment empty!") } + if !messages.HasErrors() { + idNum, err := strconv.Atoi(id) - idNum, err := strconv.Atoi(id) + userID := currentUser.ID + comment := model.Comment{TorrentID: uint(idNum), UserID: userID, Content: content, CreatedAt: time.Now()} - userID := currentUser.ID - comment := model.Comment{TorrentID: uint(idNum), UserID: userID, Content: content, CreatedAt: time.Now()} - - err = db.ORM.Create(&comment).Error - if err != nil { - util.SendError(w, err, 500) - return - } - - url, err := Router.Get("view_torrent").URL("id", id) - if err == nil { - http.Redirect(w, r, url.String(), 302) - } else { - http.Error(w, err.Error(), http.StatusInternalServerError) + err = db.ORM.Create(&comment).Error + if err != nil { + messages.ImportFromError("errors", err) + } } + ViewHandler(w,r) } func ReportTorrentHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] - + messages := msg.GetMessages(r) currentUser := GetUser(r) if userPermission.NeedsCaptcha(currentUser) { userCaptcha := captcha.Extract(r) if !captcha.Authenticate(userCaptcha) { - http.Error(w, "bad captcha", 403) - return + messages.AddError("errors", "Bad captcha!") } } + if !messages.HasErrors() { + idNum, err := strconv.Atoi(id) + userID := currentUser.ID - idNum, err := strconv.Atoi(id) - userID := currentUser.ID + report := model.TorrentReport{ + Description: r.FormValue("report_type"), + TorrentID: uint(idNum), + UserID: userID, + CreatedAt: time.Now(), + } - report := model.TorrentReport{ - Description: r.FormValue("report_type"), - TorrentID: uint(idNum), - UserID: userID, - CreatedAt: time.Now(), - } - - err = db.ORM.Create(&report).Error - if err != nil { - util.SendError(w, err, 500) - return - } - - url, err := Router.Get("view_torrent").URL("id", id) - if err == nil { - http.Redirect(w, r, url.String(), 302) - } else { - http.Error(w, err.Error(), http.StatusInternalServerError) + err = db.ORM.Create(&report).Error + if err != nil { + messages.ImportFromError("errors", err) + } } + ViewHandler(w,r) } diff --git a/service/user/user.go b/service/user/user.go index 54b7b058..adf07ad6 100644 --- a/service/user/user.go +++ b/service/user/user.go @@ -80,6 +80,8 @@ func CreateUserFromForm(registrationForm formStruct.RegistrationForm) (model.Use } user.Email = "" // unset email because it will be verified later user.CreatedAt = time.Now() + // User settings to default + user.ToDefault() // currently unused but needs to be set: user.ApiToken = "" user.ApiTokenExpiry = time.Unix(0, 0) From a4c23dda1f02c582efb8553cc606c56afc81fe33 Mon Sep 17 00:00:00 2001 From: akuma06 Date: Sun, 21 May 2017 20:20:40 +0200 Subject: [PATCH 3/4] wiiiip --- model/user.go | 16 +++++++++------- router/modpanel.go | 9 ++++----- router/upload_handler.go | 3 ++- router/user_handler.go | 5 ++--- router/view_torrent_handler.go | 1 - service/user/cookie_helper.go | 12 +++++++----- service/user/user.go | 5 +++-- util/modelHelper/model_helper.go | 1 - 8 files changed, 27 insertions(+), 25 deletions(-) diff --git a/model/user.go b/model/user.go index 61b44bc5..1147c7f6 100644 --- a/model/user.go +++ b/model/user.go @@ -1,6 +1,7 @@ package model import ( + "encoding/json" "time" "github.com/NyaaPantsu/nyaa/config" @@ -102,7 +103,7 @@ type UserUploadsOld struct { } type UserSettings struct { - settings map[string]interface{} `json:"settings"` + settings map[string]bool`json:"settings"` } func (c UserUploadsOld) TableName() string { @@ -124,19 +125,19 @@ func (u *User) ToJSON() UserJSON { /* User Settings */ -func(s UserSettings) Get(key string) interface{} { - if (s.settings[key] != nil) { - return s.settings[key] +func(s UserSettings) Get(key string) bool { + if val, ok:= s.settings[key]; ok { + return val } else { return config.DefaultUserSettings[key] } } -func (s UserSettings) GetSettings() { +func (s UserSettings) GetSettings() map[string]bool { return s.settings } -func (s UserSettings) Set(key string, val interface{}) { +func (s UserSettings) Set(key string, val bool) { s.settings[key] = val } @@ -145,7 +146,8 @@ func (s UserSettings) ToDefault() { } func (u User) SaveSettings() { - u.UserSettings , _ = json.Marshal(u.Settings.GetSettings()) + byteArray, _ := json.Marshal(u.Settings.GetSettings()) + u.UserSettings = string(byteArray[:]) } func (u User) ParseSettings() { diff --git a/router/modpanel.go b/router/modpanel.go index d2bcd08a..8a4b1668 100644 --- a/router/modpanel.go +++ b/router/modpanel.go @@ -16,7 +16,6 @@ import ( "github.com/NyaaPantsu/nyaa/service/torrent" "github.com/NyaaPantsu/nyaa/service/user" "github.com/NyaaPantsu/nyaa/service/user/permission" - form "github.com/NyaaPantsu/nyaa/service/user/form" "github.com/NyaaPantsu/nyaa/util/log" msg "github.com/NyaaPantsu/nyaa/util/messages" "github.com/NyaaPantsu/nyaa/util/search" @@ -235,6 +234,7 @@ func CommentsListPanel(w http.ResponseWriter, r *http.Request) { func TorrentEditModPanel(w http.ResponseWriter, r *http.Request) { id := r.URL.Query().Get("id") torrent, _ := torrentService.GetTorrentById(id) + messages:= msg.GetMessages(r) torrentJson := torrent.ToJSON() uploadForm := NewUploadForm() @@ -243,7 +243,7 @@ func TorrentEditModPanel(w http.ResponseWriter, r *http.Request) { uploadForm.Status = torrentJson.Status uploadForm.WebsiteLink = string(torrentJson.WebsiteLink) uploadForm.Description = string(torrentJson.Description) - htv := PanelTorrentEdVbs{NewPanelCommonVariables(r), uploadForm, form.NewErrors(), form.NewInfos()} + htv := PanelTorrentEdVbs{NewPanelCommonVariables(r), uploadForm, messages.GetAllErrors(), messages.GetAllInfos()} err := panelTorrentEd.ExecuteTemplate(w, "admin_index.html", htv) log.CheckError(err) } @@ -252,7 +252,6 @@ func TorrentPostEditModPanel(w http.ResponseWriter, r *http.Request) { var uploadForm UploadForm id := r.URL.Query().Get("id") messages := msg.GetMessages(r) - infos := form.NewInfos() torrent, _ := torrentService.GetTorrentById(id) if torrent.ID > 0 { errUp := uploadForm.ExtractEditInfo(r) @@ -310,7 +309,8 @@ func TorrentReportDeleteModPanel(w http.ResponseWriter, r *http.Request) { } func TorrentReassignModPanel(w http.ResponseWriter, r *http.Request) { - htv := PanelTorrentReassignVbs{NewPanelCommonVariables(r), ReassignForm{}, form.NewErrors(), form.NewInfos()} + messages := msg.GetMessages(r) + htv := PanelTorrentReassignVbs{NewPanelCommonVariables(r), ReassignForm{}, messages.GetAllErrors(), messages.GetAllInfos()} err := panelTorrentReassign.ExecuteTemplate(w, "admin_index.html", htv) log.CheckError(err) } @@ -318,7 +318,6 @@ func TorrentReassignModPanel(w http.ResponseWriter, r *http.Request) { func TorrentPostReassignModPanel(w http.ResponseWriter, r *http.Request) { var rForm ReassignForm messages := msg.GetMessages(r) - infos := form.NewInfos() err2 := rForm.ExtractInfo(r) if err2 != nil { diff --git a/router/upload_handler.go b/router/upload_handler.go index 88e01919..5e500811 100644 --- a/router/upload_handler.go +++ b/router/upload_handler.go @@ -6,6 +6,7 @@ import ( "strconv" "time" + "github.com/NyaaPantsu/nyaa/config" "github.com/NyaaPantsu/nyaa/db" "github.com/NyaaPantsu/nyaa/model" "github.com/NyaaPantsu/nyaa/service/captcha" @@ -84,7 +85,7 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) { if len(user.Likings) > 0 { // If we are followed by at least someone for _, follower := range user.Likings { follower.ParseSettings() // We need to call it before checking settings - if follower.Settings.Get("notifications.new_torrent"] { + if follower.Settings.Get("notifications.new_torrent") { T, _, _ := languages.TfuncAndLanguageWithFallback(user.Language, user.Language) // We need to send the notification to every user in their language notifierService.NotifyUser(&follower, torrent.Identifier(), fmt.Sprintf(T("new_torrent_uploaded"), torrent.Name, user.Username), url.String()) diff --git a/router/user_handler.go b/router/user_handler.go index 0131c078..31a18951 100644 --- a/router/user_handler.go +++ b/router/user_handler.go @@ -1,7 +1,6 @@ package router import ( - "fmt" "net/http" "strconv" @@ -198,7 +197,7 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) { // Post Registration controller, we do some check on the form here, the rest on user service func UserRegisterPostHandler(w http.ResponseWriter, r *http.Request) { b := form.RegistrationForm{} - messages = msg.GetMessages(r) + messages := msg.GetMessages(r) if !captcha.Authenticate(captcha.Extract(r)) { messages.AddError("errors", "Wrong captcha!") @@ -255,7 +254,7 @@ func UserVerifyEmailHandler(w http.ResponseWriter, r *http.Request) { func UserLoginPostHandler(w http.ResponseWriter, r *http.Request) { b := form.LoginForm{} modelHelper.BindValueForm(&b, r) - messages := msg.GetAllErrors() + messages := msg.GetMessages(r) modelHelper.ValidateForm(&b, &messages) if !messages.HasErrors() { diff --git a/router/view_torrent_handler.go b/router/view_torrent_handler.go index e7b80d91..3221ee02 100644 --- a/router/view_torrent_handler.go +++ b/router/view_torrent_handler.go @@ -12,7 +12,6 @@ import ( "github.com/NyaaPantsu/nyaa/service/notifier" "github.com/NyaaPantsu/nyaa/service/torrent" "github.com/NyaaPantsu/nyaa/service/user/permission" - "github.com/NyaaPantsu/nyaa/util" "github.com/NyaaPantsu/nyaa/util/log" msg "github.com/NyaaPantsu/nyaa/util/messages" "github.com/gorilla/mux" diff --git a/service/user/cookie_helper.go b/service/user/cookie_helper.go index b4d7f640..59bc9aa3 100644 --- a/service/user/cookie_helper.go +++ b/service/user/cookie_helper.go @@ -5,6 +5,7 @@ import ( "github.com/NyaaPantsu/nyaa/db" "github.com/NyaaPantsu/nyaa/model" formStruct "github.com/NyaaPantsu/nyaa/service/user/form" + msg "github.com/NyaaPantsu/nyaa/util/messages" "github.com/NyaaPantsu/nyaa/util/modelHelper" "github.com/NyaaPantsu/nyaa/util/timeHelper" "github.com/gorilla/context" @@ -62,14 +63,15 @@ func ClearCookie(w http.ResponseWriter) (int, error) { } // SetCookieHandler sets the authentication cookie -func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, error) { +func SetCookieHandler(w http.ResponseWriter, r *http.Request, email string, pass string) (int, error) { if email == "" || pass == "" { return http.StatusNotFound, errors.New("No username/password entered") } var user model.User + messages := msg.GetMessages(r) // search by email or username - isValidEmail, _ := formStruct.EmailValidation(email, formStruct.NewErrors()) + isValidEmail := formStruct.EmailValidation(email, &messages) if isValidEmail { if db.ORM.Where("email = ?", email).First(&user).RecordNotFound() { return http.StatusNotFound, errors.New("User not found") @@ -104,17 +106,17 @@ func SetCookieHandler(w http.ResponseWriter, email string, pass string) (int, er } // RegisterHanderFromForm sets cookie from a RegistrationForm. -func RegisterHanderFromForm(w http.ResponseWriter, registrationForm formStruct.RegistrationForm) (int, error) { +func RegisterHanderFromForm(w http.ResponseWriter, r *http.Request, registrationForm formStruct.RegistrationForm) (int, error) { username := registrationForm.Username // email isn't set at this point pass := registrationForm.Password - return SetCookieHandler(w, username, pass) + return SetCookieHandler(w, r, username, pass) } // RegisterHandler sets a cookie when user registered. func RegisterHandler(w http.ResponseWriter, r *http.Request) (int, error) { var registrationForm formStruct.RegistrationForm modelHelper.BindValueForm(®istrationForm, r) - return RegisterHanderFromForm(w, registrationForm) + return RegisterHanderFromForm(w, r, registrationForm) } // CurrentUser determines the current user from the request or context diff --git a/service/user/user.go b/service/user/user.go index adf07ad6..abc638d3 100644 --- a/service/user/user.go +++ b/service/user/user.go @@ -81,7 +81,8 @@ func CreateUserFromForm(registrationForm formStruct.RegistrationForm) (model.Use user.Email = "" // unset email because it will be verified later user.CreatedAt = time.Now() // User settings to default - user.ToDefault() + user.Settings.ToDefault() + user.SaveSettings() // currently unused but needs to be set: user.ApiToken = "" user.ApiTokenExpiry = time.Unix(0, 0) @@ -321,7 +322,7 @@ func CreateUserAuthentication(w http.ResponseWriter, r *http.Request) (int, erro modelHelper.BindValueForm(&form, r) username := form.Username pass := form.Password - status, err := SetCookieHandler(w, username, pass) + status, err := SetCookieHandler(w, r, username, pass) return status, err } diff --git a/util/modelHelper/model_helper.go b/util/modelHelper/model_helper.go index a22fb649..fadbd57e 100644 --- a/util/modelHelper/model_helper.go +++ b/util/modelHelper/model_helper.go @@ -1,7 +1,6 @@ package modelHelper import ( - "fmt" "github.com/NyaaPantsu/nyaa/util/log" msg "github.com/NyaaPantsu/nyaa/util/messages" "net/http" From 07c120407ef8dc0c3f7dd0a16996956e4d7f98ba Mon Sep 17 00:00:00 2001 From: akuma06 Date: Mon, 22 May 2017 00:22:42 +0200 Subject: [PATCH 4/4] Finished --- config/user_settings.go | 2 +- model/comment.go | 7 +- model/torrent.go | 2 +- model/user.go | 44 ++++++--- router/template_functions.go | 3 + router/upload_handler.go | 6 +- router/user_handler.go | 5 +- router/view_torrent_handler.go | 26 ++++-- service/notifier/notifier.go | 5 +- service/user/user.go | 17 +++- templates/_profile_edit.html | 163 +++++++++++++++++++++++++++++++++ translations/en-us.all.json | 56 +++++++++++ util/messages/messages.go | 6 ++ 13 files changed, 313 insertions(+), 29 deletions(-) diff --git a/config/user_settings.go b/config/user_settings.go index b6c38f96..cbc5b513 100644 --- a/config/user_settings.go +++ b/config/user_settings.go @@ -13,7 +13,7 @@ var DefaultUserSettings = map[string]bool { "new_torrent_email": false, "new_comment": true, "new_comment_email": false, - "new_responses": true, + "new_responses": false, "new_responses_email": false, "new_follower": false, "new_follower_email": false, diff --git a/model/comment.go b/model/comment.go index 22d97667..5169142c 100644 --- a/model/comment.go +++ b/model/comment.go @@ -1,8 +1,9 @@ package model import ( - "github.com/NyaaPantsu/nyaa/config" "time" + + "github.com/NyaaPantsu/nyaa/config" ) type Comment struct { @@ -27,6 +28,10 @@ func (c Comment) TableName() string { return config.CommentsTableName } +func (c *Comment) Identifier() string { // We Can personalize the identifier but we would have to handle toggle read in that case + return c.Torrent.Identifier() +} + type OldComment struct { TorrentID uint `gorm:"column:torrent_id"` Username string `gorm:"column:username"` diff --git a/model/torrent.go b/model/torrent.go index 0cd5ddd9..6f8f4be1 100644 --- a/model/torrent.go +++ b/model/torrent.go @@ -86,7 +86,7 @@ func (t Torrent) TableName() string { return config.TorrentsTableName } -func (t Torrent) Identifier() string { +func (t *Torrent) Identifier() string { return "torrent_"+strconv.Itoa(int(t.ID)) } diff --git a/model/user.go b/model/user.go index 1147c7f6..e053c013 100644 --- a/model/user.go +++ b/model/user.go @@ -3,6 +3,7 @@ package model import ( "encoding/json" "time" + "fmt" "github.com/NyaaPantsu/nyaa/config" ) @@ -103,7 +104,7 @@ type UserUploadsOld struct { } type UserSettings struct { - settings map[string]bool`json:"settings"` + Settings map[string]bool`json:"settings"` } func (c UserUploadsOld) TableName() string { @@ -125,33 +126,48 @@ func (u *User) ToJSON() UserJSON { /* User Settings */ -func(s UserSettings) Get(key string) bool { - if val, ok:= s.settings[key]; ok { +func(s *UserSettings) Get(key string) bool { + if val, ok:= s.Settings[key]; ok { return val } else { return config.DefaultUserSettings[key] } } -func (s UserSettings) GetSettings() map[string]bool { - return s.settings +func (s *UserSettings) GetSettings() map[string]bool { + return s.Settings } -func (s UserSettings) Set(key string, val bool) { - s.settings[key] = val +func (s *UserSettings) Set(key string, val bool) { + if s.Settings == nil { + s.Settings = make(map[string]bool) + } + s.Settings[key] = val } -func (s UserSettings) ToDefault() { - s.settings = config.DefaultUserSettings +func (s *UserSettings) ToDefault() { + s.Settings = config.DefaultUserSettings } -func (u User) SaveSettings() { - byteArray, _ := json.Marshal(u.Settings.GetSettings()) - u.UserSettings = string(byteArray[:]) +func (s *UserSettings) Initialize() { + s.Settings = make(map[string]bool) } -func (u User) ParseSettings() { +func (u *User) SaveSettings() { + byteArray, err := json.Marshal(u.Settings) + + if (err != nil) { + fmt.Print(err) + } + u.UserSettings = string(byteArray) +} + +func (u *User) ParseSettings() { if len(u.Settings.GetSettings()) == 0 && u.UserSettings != "" { - json.Unmarshal([]byte(u.UserSettings), u.Settings) + u.Settings.Initialize() + json.Unmarshal([]byte(u.UserSettings), &u.Settings) + } else if len(u.Settings.GetSettings()) == 0 && u.UserSettings != "" { + u.Settings.Initialize() + u.Settings.ToDefault() } } \ No newline at end of file diff --git a/router/template_functions.go b/router/template_functions.go index e0e2478e..9c8e15c5 100644 --- a/router/template_functions.go +++ b/router/template_functions.go @@ -216,4 +216,7 @@ var FuncMap = template.FuncMap{ "makeCaptchaData": func(captchaID string, T languages.TemplateTfunc) captchaData { return captchaData{captchaID, T} }, + "DefaultUserSettings": func(s string) bool{ + return config.DefaultUserSettings[s] + }, } diff --git a/router/upload_handler.go b/router/upload_handler.go index 5e500811..3c65eab9 100644 --- a/router/upload_handler.go +++ b/router/upload_handler.go @@ -85,10 +85,10 @@ func UploadPostHandler(w http.ResponseWriter, r *http.Request) { if len(user.Likings) > 0 { // If we are followed by at least someone for _, follower := range user.Likings { follower.ParseSettings() // We need to call it before checking settings - if follower.Settings.Get("notifications.new_torrent") { - T, _, _ := languages.TfuncAndLanguageWithFallback(user.Language, user.Language) // We need to send the notification to every user in their language + if follower.Settings.Get("new_torrent") { + T, _, _ := languages.TfuncAndLanguageWithFallback(follower.Language, follower.Language) // We need to send the notification to every user in their language - notifierService.NotifyUser(&follower, torrent.Identifier(), fmt.Sprintf(T("new_torrent_uploaded"), torrent.Name, user.Username), url.String()) + notifierService.NotifyUser(&follower, torrent.Identifier(), fmt.Sprintf(T("new_torrent_uploaded"), torrent.Name, user.Username), url.String(), follower.Settings.Get("new_torrent_email")) } } } diff --git a/router/user_handler.go b/router/user_handler.go index 31a18951..b660786e 100644 --- a/router/user_handler.go +++ b/router/user_handler.go @@ -94,6 +94,7 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) { if unfollow != nil { messages.AddInfof("infos", string(T("user_unfollowed_msg")), userProfile.Username) } + userProfile.ParseSettings() htv := UserProfileVariables{NewCommonVariables(r), &userProfile, messages.GetAllInfos()} err := viewProfileTemplate.ExecuteTemplate(w, "index.html", htv) @@ -119,6 +120,7 @@ func UserDetailsHandler(w http.ResponseWriter, r *http.Request) { b := form.UserForm{} modelHelper.BindValueForm(&b, r) availableLanguages := languages.GetAvailableLanguages() + userProfile.ParseSettings() htv := UserProfileEditVariables{NewCommonVariables(r), &userProfile, b, messages.GetAllErrors(), messages.GetAllInfos(), availableLanguages} err := viewProfileEditTemplate.ExecuteTemplate(w, "index.html", htv) if err != nil { @@ -140,6 +142,7 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) { NotFoundHandler(w, r) return } + userProfile.ParseSettings() messages := msg.GetMessages(r) userForm := form.UserForm{} userSettingsForm := form.UserSettingsForm{} @@ -171,7 +174,7 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) { messages.AddInfof("infos", string(T("email_changed")), userForm.Email) userForm.Email = userProfile.Email // reset, it will be set when user clicks verification } - userProfile, _, errorUser = userService.UpdateUser(w, &userForm, currentUser, id) + userProfile, _, errorUser = userService.UpdateUser(w, &userForm, &userSettingsForm, currentUser, id) if errorUser != nil { messages.ImportFromError("errors", errorUser) } else { diff --git a/router/view_torrent_handler.go b/router/view_torrent_handler.go index 3221ee02..7cb2c2aa 100644 --- a/router/view_torrent_handler.go +++ b/router/view_torrent_handler.go @@ -1,6 +1,7 @@ package router import ( + "fmt" "net/http" "strconv" "strings" @@ -12,6 +13,7 @@ import ( "github.com/NyaaPantsu/nyaa/service/notifier" "github.com/NyaaPantsu/nyaa/service/torrent" "github.com/NyaaPantsu/nyaa/service/user/permission" + "github.com/NyaaPantsu/nyaa/util/languages" "github.com/NyaaPantsu/nyaa/util/log" msg "github.com/NyaaPantsu/nyaa/util/messages" "github.com/gorilla/mux" @@ -54,13 +56,19 @@ func PostCommentHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) id := vars["id"] + torrent, err := torrentService.GetTorrentById(id) + if (err != nil) { + NotFoundHandler(w, r) + return + } + currentUser := GetUser(r) messages := msg.GetMessages(r) if userPermission.NeedsCaptcha(currentUser) { userCaptcha := captcha.Extract(r) if !captcha.Authenticate(userCaptcha) { - messages.AddError("errors", "Bad captcha!") + messages.AddError("errors", "Bad captcham!") } } content := p.Sanitize(r.FormValue("comment")) @@ -69,12 +77,18 @@ func PostCommentHandler(w http.ResponseWriter, r *http.Request) { messages.AddError("errors", "Comment empty!") } if !messages.HasErrors() { - idNum, err := strconv.Atoi(id) - userID := currentUser.ID - comment := model.Comment{TorrentID: uint(idNum), UserID: userID, Content: content, CreatedAt: time.Now()} + comment := model.Comment{TorrentID: torrent.ID, UserID: userID, Content: content, CreatedAt: time.Now()} + err := db.ORM.Create(&comment).Error + comment.Torrent = &torrent + + url, err := Router.Get("view_torrent").URL("id", strconv.FormatUint(uint64(torrent.ID), 10)) + torrent.Uploader.ParseSettings() + if torrent.Uploader.Settings.Get("new_comment") { + T, _, _ := languages.TfuncAndLanguageWithFallback(torrent.Uploader.Language, torrent.Uploader.Language) // We need to send the notification to every user in their language + notifierService.NotifyUser(torrent.Uploader, comment.Identifier(), fmt.Sprintf(T("new_comment_on_torrent"), torrent.Name), url.String(), torrent.Uploader.Settings.Get("new_comment_email")) + } - err = db.ORM.Create(&comment).Error if err != nil { messages.ImportFromError("errors", err) } @@ -90,7 +104,7 @@ func ReportTorrentHandler(w http.ResponseWriter, r *http.Request) { if userPermission.NeedsCaptcha(currentUser) { userCaptcha := captcha.Extract(r) if !captcha.Authenticate(userCaptcha) { - messages.AddError("errors", "Bad captcha!") + messages.AddError("errors", "Bad captchae!") } } if !messages.HasErrors() { diff --git a/service/notifier/notifier.go b/service/notifier/notifier.go index cd930d24..da64e762 100644 --- a/service/notifier/notifier.go +++ b/service/notifier/notifier.go @@ -6,12 +6,15 @@ import ( ) -func NotifyUser(user *model.User, name string, msg string, url string) { +func NotifyUser(user *model.User, name string, msg string, url string, email bool) { if (user.ID > 0) { notification := model.NewNotification(name, msg, url) notification.UserID = user.ID db.ORM.Create(¬ification) // TODO: Email notification +/* if email { + + }*/ } } diff --git a/service/user/user.go b/service/user/user.go index abc638d3..b6c87768 100644 --- a/service/user/user.go +++ b/service/user/user.go @@ -175,7 +175,7 @@ func UpdateUserCore(user *model.User) (int, error) { } // UpdateUser updates a user. -func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *model.User, id string) (model.User, int, error) { +func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, formSet *formStruct.UserSettingsForm, currentUser *model.User, id string) (model.User, int, error) { var user model.User if db.ORM.First(&user, id).RecordNotFound() { return user, http.StatusNotFound, errors.New("user not found") @@ -206,6 +206,21 @@ func UpdateUser(w http.ResponseWriter, form *formStruct.UserForm, currentUser *m } log.Debugf("form %+v\n", form) modelHelper.AssignValue(&user, form) + + // We set settings here + user.ParseSettings() + user.Settings.Set("new_torrent", formSet.NewTorrent) + user.Settings.Set("new_torrent_email", formSet.NewTorrentEmail) + user.Settings.Set("new_comment", formSet.NewComment) + user.Settings.Set("new_comment_email", formSet.NewCommentEmail) + user.Settings.Set("new_responses", formSet.NewResponses) + user.Settings.Set("new_responses_email", formSet.NewResponsesEmail) + user.Settings.Set("new_follower", formSet.NewFollower) + user.Settings.Set("new_follower_email", formSet.NewFollowerEmail) + user.Settings.Set("followed", formSet.Followed) + user.Settings.Set("followed_email", formSet.FollowedEmail) + user.SaveSettings() + status, err := UpdateUserCore(&user) return user, status, err } diff --git a/templates/_profile_edit.html b/templates/_profile_edit.html index ccbd9a29..0dc4a1ea 100644 --- a/templates/_profile_edit.html +++ b/templates/_profile_edit.html @@ -67,6 +67,169 @@ {{end}} +

{{ call $.T "preferences"}}

+ {{ with .Settings }} + {{ if DefaultUserSettings "new_torrent"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "new_torrent")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{ if DefaultUserSettings "new_torrent_email"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "new_torrent_email")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{ if DefaultUserSettings "new_comment"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "new_comment")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{ if DefaultUserSettings "new_comment_email"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "new_comment_email")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{ if DefaultUserSettings "new_responses"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "new_responses")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{ if DefaultUserSettings "new_responses_email"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "new_responses_email")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{ if DefaultUserSettings "new_follower"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "new_follower")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{ if DefaultUserSettings "new_follower_email"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "new_follower_email")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{ if DefaultUserSettings "followed"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "followed")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{ if DefaultUserSettings "followed_email"}} +
+ +
+
+ +
+ {{ range (index $.FormErrors "followed_email")}} +

{{ . }}

+ {{end}} +
+
+ {{end}} + {{end}} {{ if HasAdmin $.User}}

{{ call $.T "moderation"}}

diff --git a/translations/en-us.all.json b/translations/en-us.all.json index 9a9a77ff..efbb4ff4 100644 --- a/translations/en-us.all.json +++ b/translations/en-us.all.json @@ -782,5 +782,61 @@ { "id": "new_torrent_uploaded", "translation": "New torrent: \"%s\" from %s" + }, + { + "id": "preferences", + "translation": "Preferences" + }, + { + "id": "new_torrent_settings", + "translation": "Be notified when a new torrent is added from a user followed" + }, + { + "id": "new_torrent_email_settings", + "translation": "Be notified by e-mail when a new torrent is added from a user followed" + }, + { + "id": "new_comment_settings", + "translation": "Be notified when there is a new comment on your torrents" + }, + { + "id": "new_comment_email_settings", + "translation": "Be notified by e-mail when there is a new comment on your torrents" + }, + { + "id": "new_responses_settings", + "translation": "Be notified when there is a new response to your comment" + }, + { + "id": "new_responses_email_settings", + "translation": "Be notified by e-mail when there is a new response to your comment" + }, + { + "id": "new_follower_settings", + "translation": "Be notified when you have a new follower" + }, + { + "id": "new_follower_email_settings", + "translation": "Be notified by e-mail when you have a new follower" + }, + { + "id": "followed_settings", + "translation": "Be notified when you have followed someone" + }, + { + "id": "followed_email_settings", + "translation": "Be notified by e-mail when you have followed someone" + }, + { + "id": "yes", + "translation": "Yes" + }, + { + "id": "no", + "translation": "No" + }, + { + "id": "new_comment_on_torrent", + "translation": "New comment on torrent: \"%s\"" } ] diff --git a/util/messages/messages.go b/util/messages/messages.go index 4ad0bc58..af312943 100644 --- a/util/messages/messages.go +++ b/util/messages/messages.go @@ -23,6 +23,9 @@ func GetMessages(r *http.Request) Messages { } func (mes Messages) AddError(name string, msg string) { + if (mes.Errors == nil) { + mes.Errors = make(map[string][]string) + } mes.Errors[name] = append(mes.Errors[name], msg) mes.setMessagesInContext() } @@ -34,6 +37,9 @@ func (mes Messages) ImportFromError(name string, err error) { } func (mes Messages) AddInfo(name string, msg string) { + if (mes.Infos == nil) { + mes.Infos = make(map[string][]string) + } mes.Infos[name] = append(mes.Infos[name], msg) mes.setMessagesInContext() }