Albirew/nyaa-pantsu
Archivé
1
0
Bifurcation 0

User Settings Notification (WIP)

Cette révision appartient à :
akuma06 2017-05-21 18:13:28 +02:00
Parent 8081e0b639
révision 32c51a57cb
6 fichiers modifiés avec 105 ajouts et 40 suppressions

13
config/notifications.go Fichier normal
Voir le fichier

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

Voir le fichier

@ -24,6 +24,7 @@ type User struct {
ApiToken string `gorm:"column:api_token"` ApiToken string `gorm:"column:api_token"`
ApiTokenExpiry time.Time `gorm:"column:api_token_expiry"` ApiTokenExpiry time.Time `gorm:"column:api_token_expiry"`
Language string `gorm:"column:language"` Language string `gorm:"column:language"`
UserSettings string `gorm:"column:settings"`
// TODO: move this to PublicUser // TODO: move this to PublicUser
Likings []User // Don't work `gorm:"foreignkey:user_id;associationforeignkey:follower_id;many2many:user_follows"` 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 MD5 string `json:"md5" gorm:"column:md5"` // Hash of email address, used for Gravatar
Torrents []Torrent `gorm:"ForeignKey:UploaderID"` 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 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 { type UserJSON struct {
@ -99,6 +101,10 @@ type UserUploadsOld struct {
TorrentId uint `gorm:"column:torrent_id"` TorrentId uint `gorm:"column:torrent_id"`
} }
type UserSettings struct {
settings map[string]interface{} `json:"settings"`
}
func (c UserUploadsOld) TableName() string { func (c UserUploadsOld) TableName() string {
// is this needed here? // is this needed here?
return config.UploadsOldTableName return config.UploadsOldTableName
@ -115,3 +121,26 @@ func (u *User) ToJSON() UserJSON {
} }
return json 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)
}

Voir le fichier

@ -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)) 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 userService.GetLikings(user) // We populate the liked field for users
if len(user.Likings) > 0 { // If we are followed by at least someone if len(user.Likings) > 0 { // If we are followed by at least someone
for _, follower := range user.Likings { 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())
}
} }
} }
} }

Voir le fichier

@ -137,40 +137,42 @@ func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) {
NotFoundHandler(w, r) NotFoundHandler(w, r)
return return
} }
messages := msg.GetMessages(r)
userForm := form.UserForm{} userForm := form.UserForm{}
err := form.NewErrors() userSettingsForm := form.UserSettingsForm{}
infos := form.NewInfos()
T := languages.GetTfuncFromRequest(r) T := languages.GetTfuncFromRequest(r)
if len(r.PostFormValue("email")) > 0 { 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 { 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(&userForm, r)
modelHelper.BindValueForm(&userSettingsForm, r)
if !userPermission.HasAdmin(currentUser) { if !userPermission.HasAdmin(currentUser) {
userForm.Username = userProfile.Username userForm.Username = userProfile.Username
userForm.Status = userProfile.Status userForm.Status = userProfile.Status
} else { } else {
if userProfile.Status != userForm.Status && userForm.Status == 2 { 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) modelHelper.ValidateForm(&userForm, &messages)
if len(err) == 0 { if !messages.HasErrors() {
if userForm.Email != userProfile.Email { if userForm.Email != userProfile.Email {
userService.SendVerificationToUser(*currentUser, userForm.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 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, currentUser, id)
if errorUser != nil { if errorUser != nil {
err["errors"] = append(err["errors"], errorUser.Error()) messages.ImportFromError("errors", errorUser)
} else { } 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), CommonTemplateVariables: NewCommonVariables(r),
UserProfile: &userProfile, UserProfile: &userProfile,
UserForm: userForm, UserForm: userForm,
FormErrors: err, FormErrors: messages.GetAllErrors(),
FormInfos: infos, FormInfos: messages.GetAllInfos(),
Languages: availableLanguages, Languages: availableLanguages,
} }
errorTmpl := viewProfileEditTemplate.ExecuteTemplate(w, "index.html", upev) errorTmpl := viewProfileEditTemplate.ExecuteTemplate(w, "index.html", upev)

Voir le fichier

@ -4,33 +4,34 @@ import (
"regexp" "regexp"
"github.com/NyaaPantsu/nyaa/util/log" "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 EMAIL_REGEX = `(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})`
const USERNAME_REGEX = `(\W)` 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) exp, errorRegex := regexp.Compile(EMAIL_REGEX)
if regexpCompiled := log.CheckError(errorRegex); regexpCompiled { if regexpCompiled := log.CheckError(errorRegex); regexpCompiled {
if exp.MatchString(email) { if exp.MatchString(email) {
return true, err return true
} }
} }
err["email"] = append(err["email"], "Email Address is not valid") mes.AddError("email", "Email Address is not valid")
return false, err 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) exp, errorRegex := regexp.Compile(USERNAME_REGEX)
if regexpCompiled := log.CheckError(errorRegex); regexpCompiled { if regexpCompiled := log.CheckError(errorRegex); regexpCompiled {
if exp.MatchString(username) { if exp.MatchString(username) {
err["username"] = append(err["username"], "Username contains illegal characters") mes.AddError("username", "Username contains illegal characters")
return false, err return false
} }
} else { } else {
return false, err return false
} }
return true, err return true
} }
func NewErrors() map[string][]string { func NewErrors() map[string][]string {
@ -73,6 +74,20 @@ type UserForm struct {
Status int `form:"status" default:"0"` 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. // PasswordForm is used when updating a user password.
type PasswordForm struct { type PasswordForm struct {
CurrentPassword string `form:"currentPassword"` CurrentPassword string `form:"currentPassword"`

Voir le fichier

@ -3,6 +3,7 @@ package modelHelper
import ( import (
"fmt" "fmt"
"github.com/NyaaPantsu/nyaa/util/log" "github.com/NyaaPantsu/nyaa/util/log"
msg "github.com/NyaaPantsu/nyaa/util/messages"
"net/http" "net/http"
"reflect" "reflect"
"strconv" "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() formElem := reflect.ValueOf(form).Elem()
for i := 0; i < formElem.NumField(); i++ { for i := 0; i < formElem.NumField(); i++ {
typeField := formElem.Type().Field(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 if tag.Get("len_min") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) { // Check minimum length
lenMin, _ := strconv.Atoi(tag.Get("len_min")) lenMin, _ := strconv.Atoi(tag.Get("len_min"))
if formElem.Field(i).Len() < lenMin { 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 if tag.Get("len_max") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) { // Check maximum length
lenMax, _ := strconv.Atoi(tag.Get("len_max")) lenMax, _ := strconv.Atoi(tag.Get("len_max"))
if formElem.Field(i).Len() > lenMax { 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) { if tag.Get("equalInput") != "" && (tag.Get("needed") != "" || formElem.Field(i).Len() > 0) {
otherInput := formElem.FieldByName(tag.Get("equalInput")) otherInput := formElem.FieldByName(tag.Get("equalInput"))
if formElem.Field(i).Interface() != otherInput.Interface() { 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() { switch typeField.Type.Name() {
case "string": case "string":
if tag.Get("equal") != "" && formElem.Field(i).String() != tag.Get("equal") { 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() == "" { 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") != "" { if formElem.Field(i).String() == "" && tag.Get("default") != "" {
formElem.Field(i).SetString(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 if tag.Get("equal") != "" { // Check minimum length
equal, _ := strconv.Atoi(tag.Get("equal")) equal, _ := strconv.Atoi(tag.Get("equal"))
if formElem.Field(i).Int() > int64(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 { 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") != "" { if formElem.Field(i).Interface == nil && tag.Get("default") != "" {
defaultValue, _ := strconv.Atoi(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 if tag.Get("equal") != "" { // Check minimum length
equal, _ := strconv.Atoi(tag.Get("equal")) equal, _ := strconv.Atoi(tag.Get("equal"))
if formElem.Field(i).Float() != float64(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 { 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") != "" { if formElem.Field(i).Interface == nil && tag.Get("default") != "" {
defaultValue, _ := strconv.Atoi(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 if tag.Get("equal") != "" { // Check minimum length
equal, _ := strconv.ParseBool(tag.Get("equal")) equal, _ := strconv.ParseBool(tag.Get("equal"))
if formElem.Field(i).Bool() != 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
} }