342 lignes
11 Kio
Go
342 lignes
11 Kio
Go
|
package userService
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"net/http"
|
||
|
"strconv"
|
||
|
|
||
|
"golang.org/x/crypto/bcrypt"
|
||
|
|
||
|
"github.com/ewhal/nyaa/config"
|
||
|
"github.com/ewhal/nyaa/db"
|
||
|
"github.com/ewhal/nyaa/model"
|
||
|
"github.com/ewhal/nyaa/util/crypto"
|
||
|
"github.com/ewhal/nyaa/util/log"
|
||
|
"github.com/ewhal/nyaa/util/modelHelper"
|
||
|
"github.com/ewhal/nyaa/util/timeHelper"
|
||
|
)
|
||
|
|
||
|
var userFields []string = []string{"name", "email", "createdAt", "updatedAt"}
|
||
|
|
||
|
// SuggestUsername suggest user's name if user's name already occupied.
|
||
|
func SuggestUsername(username string) string {
|
||
|
var count int
|
||
|
var usernameCandidate string
|
||
|
db.ORM.Model(model.User{}).Where(&model.User{Username: username}).Count(&count)
|
||
|
log.Debugf("count Before : %d", count)
|
||
|
if count == 0 {
|
||
|
return username
|
||
|
} else {
|
||
|
var postfix int
|
||
|
for {
|
||
|
usernameCandidate = username + strconv.Itoa(postfix)
|
||
|
log.Debugf("usernameCandidate: %s\n", usernameCandidate)
|
||
|
db.ORM.Model(model.User{}).Where(&model.User{Username: usernameCandidate}).Count(&count)
|
||
|
log.Debugf("count after : %d\n", count)
|
||
|
postfix = postfix + 1
|
||
|
if count == 0 {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return usernameCandidate
|
||
|
}
|
||
|
|
||
|
// CreateUserFromForm creates a user from a registration form.
|
||
|
func CreateUserFromForm(registrationForm RegistrationForm) (model.User, error) {
|
||
|
var user model.User
|
||
|
log.Debugf("registrationForm %+v\n", registrationForm)
|
||
|
modelHelper.AssignValue(&user, ®istrationForm)
|
||
|
user.Md5 = crypto.GenerateMD5Hash(user.Email) // Gravatar
|
||
|
token, err := crypto.GenerateRandomToken32()
|
||
|
if err != nil {
|
||
|
return user, errors.New("Token not generated.")
|
||
|
}
|
||
|
user.Token = token
|
||
|
user.TokenExpiration = timeHelper.FewDaysLater(config.AuthTokenExpirationDay)
|
||
|
log.Debugf("user %+v\n", user)
|
||
|
if db.ORM.Create(&user).Error != nil {
|
||
|
return user, errors.New("User is not created.")
|
||
|
}
|
||
|
return user, nil
|
||
|
}
|
||
|
|
||
|
// CreateUser creates a user.
|
||
|
func CreateUser(w http.ResponseWriter, r *http.Request) (int, error) {
|
||
|
var user model.User
|
||
|
var registrationForm RegistrationForm
|
||
|
var status int
|
||
|
var err error
|
||
|
|
||
|
modelHelper.BindValueForm(®istrationForm, r)
|
||
|
|
||
|
password, err := bcrypt.GenerateFromPassword([]byte(registrationForm.Password), 10)
|
||
|
if err != nil {
|
||
|
return http.StatusInternalServerError, err
|
||
|
}
|
||
|
registrationForm.Password = string(password)
|
||
|
user, err = CreateUserFromForm(registrationForm)
|
||
|
if err != nil {
|
||
|
return http.StatusInternalServerError, err
|
||
|
}
|
||
|
SendVerificationToUser(user)
|
||
|
status, err = RegisterHandler(w)
|
||
|
return status, err
|
||
|
}
|
||
|
|
||
|
// RetrieveUser retrieves a user.
|
||
|
func RetrieveUser(r *http.Request, id string) (*model.PublicUser, bool, uint, int, error) {
|
||
|
var user model.User
|
||
|
var currentUserId uint
|
||
|
var isAuthor bool
|
||
|
// var publicUser *model.PublicUser
|
||
|
// publicUser.User = &user
|
||
|
if db.ORM.Select(config.UserPublicFields).First(&user, id).RecordNotFound() {
|
||
|
return &model.PublicUser{User: &user}, isAuthor, currentUserId, http.StatusNotFound, errors.New("User is not found.")
|
||
|
}
|
||
|
currentUser, err := CurrentUser(r)
|
||
|
if err == nil {
|
||
|
currentUserId = currentUser.Id
|
||
|
isAuthor = currentUser.Id == user.Id
|
||
|
}
|
||
|
var currentPage int
|
||
|
|
||
|
currentPage = 1
|
||
|
|
||
|
var likings []model.User
|
||
|
var likingCount int
|
||
|
db.ORM.Table("users_followers").Where("users_followers.user_id=?", user.Id).Count(&likingCount)
|
||
|
if err = db.ORM.Limit(config.LikingPerPage).Order(config.LikingOrder).Offset(offset).Select(config.UserPublicFields).
|
||
|
Joins("JOIN users_followers on users_followers.user_id=?", user.Id).
|
||
|
Where("users.id = users_followers.follower_id").
|
||
|
Group("users.id").Find(&likings).Error; err != nil {
|
||
|
log.Fatal(err.Error())
|
||
|
}
|
||
|
user.Likings = likings
|
||
|
var likingList model.LikingList
|
||
|
|
||
|
var liked []model.User
|
||
|
var likedCount int
|
||
|
db.ORM.Table("users_followers").Where("users_followers.follower_id=?", user.Id).Count(&likedCount)
|
||
|
if err = db.ORM.Limit(config.LikedPerPage).Order(config.LikedOrder).Offset(offset).Select(config.UserPublicFields).
|
||
|
Joins("JOIN users_followers on users_followers.follower_id=?", user.Id).
|
||
|
Where("users.id = users_followers.user_id").
|
||
|
Group("users.id").Find(&liked).Error; err != nil {
|
||
|
log.Fatal(err.Error())
|
||
|
}
|
||
|
user.Liked = liked
|
||
|
|
||
|
log.Debugf("user liking %v\n", user.Likings)
|
||
|
log.Debugf("user liked %v\n", user.Liked)
|
||
|
return &model.PublicUser{User: &user}, isAuthor, currentUserId, http.StatusOK, nil
|
||
|
}
|
||
|
|
||
|
// RetrieveUsers retrieves users.
|
||
|
func RetrieveUsers() []*model.PublicUser {
|
||
|
var users []*model.User
|
||
|
var userArr []*model.PublicUser
|
||
|
db.ORM.Select(config.UserPublicFields).Find(&users)
|
||
|
for _, user := range users {
|
||
|
userArr = append(userArr, &model.PublicUser{User: user})
|
||
|
}
|
||
|
return userArr
|
||
|
}
|
||
|
|
||
|
// UpdateUserCore updates a user. (Applying the modifed data of user).
|
||
|
func UpdateUserCore(user *model.User) (int, error) {
|
||
|
user.Md5 = crypto.GenerateMD5Hash(user.Email)
|
||
|
token, err := crypto.GenerateRandomToken32()
|
||
|
if err != nil {
|
||
|
return http.StatusInternalServerError, errors.New("Token not generated.")
|
||
|
}
|
||
|
user.Token = token
|
||
|
user.TokenExpiration = timeHelper.FewDaysLater(config.AuthTokenExpirationDay)
|
||
|
if db.ORM.Save(user).Error != nil {
|
||
|
return http.StatusInternalServerError, errors.New("User is not updated.")
|
||
|
}
|
||
|
return http.StatusOK, nil
|
||
|
}
|
||
|
|
||
|
// UpdateUser updates a user.
|
||
|
func UpdateUser(w http.ResponseWriter, r *http.Request, id string) (*model.User, int, error) {
|
||
|
var user model.User
|
||
|
if db.ORM.First(&user, id).RecordNotFound() {
|
||
|
return &user, http.StatusNotFound, errors.New("User is not found.")
|
||
|
}
|
||
|
switch r.FormValue("type") {
|
||
|
case "password":
|
||
|
var passwordForm PasswordForm
|
||
|
modelHelper.BindValueForm(&passwordForm, r)
|
||
|
log.Debugf("form %+v\n", passwordForm)
|
||
|
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(passwordForm.CurrentPassword))
|
||
|
if err != nil {
|
||
|
log.Error("Password Incorrect.")
|
||
|
return &user, http.StatusInternalServerError, errors.New("User is not updated. Password Incorrect.")
|
||
|
} else {
|
||
|
newPassword, err := bcrypt.GenerateFromPassword([]byte(passwordForm.Password), 10)
|
||
|
if err != nil {
|
||
|
return &user, http.StatusInternalServerError, errors.New("User is not updated. Password not Generated.")
|
||
|
} else {
|
||
|
passwordForm.Password = string(newPassword)
|
||
|
modelHelper.AssignValue(&user, &passwordForm)
|
||
|
}
|
||
|
}
|
||
|
default:
|
||
|
var form UserForm
|
||
|
modelHelper.BindValueForm(&form, binding.Form)
|
||
|
log.Debugf("form %+v\n", form)
|
||
|
modelHelper.AssignValue(&user, &form)
|
||
|
}
|
||
|
|
||
|
status, err := UpdateUserCore(&user)
|
||
|
if err != nil {
|
||
|
return &user, status, err
|
||
|
}
|
||
|
status, err = SetCookie(w, user.Token)
|
||
|
return &user, status, err
|
||
|
}
|
||
|
|
||
|
// DeleteUser deletes a user.
|
||
|
func DeleteUser(w http.ResponseWriter, id string) (int, error) {
|
||
|
var user model.User
|
||
|
if db.ORM.First(&user, id).RecordNotFound() {
|
||
|
return http.StatusNotFound, errors.New("User is not found.")
|
||
|
}
|
||
|
if db.ORM.Delete(&user).Error != nil {
|
||
|
return http.StatusInternalServerError, errors.New("User is not deleted.")
|
||
|
}
|
||
|
status, err := ClearCookie(w)
|
||
|
return status, err
|
||
|
}
|
||
|
|
||
|
// AddRoleToUser adds a role to a user.
|
||
|
func AddRoleToUser(r *http.Request) (int, error) {
|
||
|
var form UserRoleForm
|
||
|
var user model.User
|
||
|
var role model.Role
|
||
|
var roles []model.Role
|
||
|
modelHelper.BindValueForm(&form, r)
|
||
|
|
||
|
if db.ORM.First(&user, form.UserId).RecordNotFound() {
|
||
|
return http.StatusNotFound, errors.New("User is not found.")
|
||
|
}
|
||
|
if db.ORM.First(&role, form.RoleId).RecordNotFound() {
|
||
|
return http.StatusNotFound, errors.New("Role is not found.")
|
||
|
}
|
||
|
log.Debugf("user email : %s", user.Email)
|
||
|
log.Debugf("Role name : %s", role.Name)
|
||
|
db.ORM.Model(&user).Association("Roles").Append(role)
|
||
|
db.ORM.Model(&user).Association("Roles").Find(&roles)
|
||
|
if db.ORM.Save(&user).Error != nil {
|
||
|
return http.StatusInternalServerError, errors.New("Role not appended to user.")
|
||
|
}
|
||
|
return http.StatusOK, nil
|
||
|
}
|
||
|
|
||
|
// RemoveRoleFromUser removes a role from a user.
|
||
|
func RemoveRoleFromUser(w http.ResponseWriter, r *http.Request, userId string, roleId string) (int, error) {
|
||
|
var user model.User
|
||
|
var role model.Role
|
||
|
if db.ORM.First(&user, userId).RecordNotFound() {
|
||
|
return http.StatusNotFound, errors.New("User is not found.")
|
||
|
}
|
||
|
if db.ORM.First(&role, roleId).RecordNotFound() {
|
||
|
return http.StatusNotFound, errors.New("Role is not found.")
|
||
|
}
|
||
|
|
||
|
log.Debugf("user : %v\n", user)
|
||
|
log.Debugf("role : %v\n", role)
|
||
|
if db.ORM.Model(&user).Association("Roles").Delete(role).Error != nil {
|
||
|
return http.StatusInternalServerError, errors.New("Role is not deleted from user.")
|
||
|
}
|
||
|
return http.StatusOK, nil
|
||
|
}
|
||
|
|
||
|
// RetrieveCurrentUser retrieves a current user.
|
||
|
func RetrieveCurrentUser(r *http.Request) (model.User, int, error) {
|
||
|
user, err := CurrentUser(r)
|
||
|
if err != nil {
|
||
|
return user, http.StatusInternalServerError, err
|
||
|
}
|
||
|
return user, http.StatusOK, nil
|
||
|
}
|
||
|
|
||
|
// RetrieveUserByEmail retrieves a user by an email
|
||
|
func RetrieveUserByEmail(email string) (*model.PublicUser, string, int, error) {
|
||
|
var user model.User
|
||
|
if db.ORM.Unscoped().Select(config.UserPublicFields).Where("email like ?", "%"+email+"%").First(&user).RecordNotFound() {
|
||
|
return &model.PublicUser{User: &user}, email, http.StatusNotFound, errors.New("User is not found.")
|
||
|
}
|
||
|
return &model.PublicUser{User: &user}, email, http.StatusOK, nil
|
||
|
}
|
||
|
|
||
|
// RetrieveUsersByEmail retrieves users by an email
|
||
|
func RetrieveUsersByEmail(email string) []*model.PublicUser {
|
||
|
var users []*model.User
|
||
|
var userArr []*model.PublicUser
|
||
|
db.ORM.Select(config.UserPublicFields).Where("email like ?", "%"+email+"%").Find(&users)
|
||
|
for _, user := range users {
|
||
|
userArr = append(userArr, &model.PublicUser{User: user})
|
||
|
}
|
||
|
return userArr
|
||
|
}
|
||
|
|
||
|
// RetrieveUserByUsername retrieves a user by username.
|
||
|
func RetrieveUserByUsername(username string) (*model.PublicUser, string, int, error) {
|
||
|
var user model.User
|
||
|
if db.ORM.Unscoped().Select(config.UserPublicFields).Where("username like ?", "%"+username+"%").First(&user).RecordNotFound() {
|
||
|
return &model.PublicUser{User: &user}, username, http.StatusNotFound, errors.New("User is not found.")
|
||
|
}
|
||
|
return &model.PublicUser{User: &user}, username, http.StatusOK, nil
|
||
|
}
|
||
|
|
||
|
// RetrieveUserForAdmin retrieves a user for an administrator.
|
||
|
func RetrieveUserForAdmin(id string) (model.User, int, error) {
|
||
|
var user model.User
|
||
|
if db.ORM.First(&user, id).RecordNotFound() {
|
||
|
return user, http.StatusNotFound, errors.New("User is not found.")
|
||
|
}
|
||
|
db.ORM.Model(&user).Association("Languages").Find(&user.Languages)
|
||
|
db.ORM.Model(&user).Association("Roles").Find(&user.Roles)
|
||
|
return user, http.StatusOK, nil
|
||
|
}
|
||
|
|
||
|
// RetrieveUsersForAdmin retrieves users for an administrator.
|
||
|
func RetrieveUsersForAdmin() []model.User {
|
||
|
var users []model.User
|
||
|
var userArr []model.User
|
||
|
db.ORM.Find(&users)
|
||
|
for _, user := range users {
|
||
|
db.ORM.Model(&user).Association("Languages").Find(&user.Languages)
|
||
|
db.ORM.Model(&user).Association("Roles").Find(&user.Roles)
|
||
|
userArr = append(userArr, user)
|
||
|
}
|
||
|
return userArr
|
||
|
}
|
||
|
|
||
|
// ActivateUser toggle activation of a user.
|
||
|
func ActivateUser(r *http.Request, id string) (model.User, int, error) {
|
||
|
id := c.Params.ByName("id")
|
||
|
var user model.User
|
||
|
var form ActivateForm
|
||
|
modelHelper.BindValueForm(&form, r)
|
||
|
if db.ORM.First(&user, id).RecordNotFound() {
|
||
|
return user, http.StatusNotFound, errors.New("User is not found.")
|
||
|
}
|
||
|
user.Activation = form.Activation
|
||
|
if db.ORM.Save(&user).Error != nil {
|
||
|
return user, http.StatusInternalServerError, errors.New("User not activated.")
|
||
|
}
|
||
|
return user, http.StatusOK, nil
|
||
|
}
|
||
|
|
||
|
// CreateUserAuthentication creates user authentication.
|
||
|
func CreateUserAuthentication(w http.ResponseWriter, r *http.Request) (int, error) {
|
||
|
var form LoginForm
|
||
|
modelHelper.BindValueForm(&form, r)
|
||
|
email := form.Email
|
||
|
pass := form.Password
|
||
|
status, err := SetCookieHandler(w, email, pass)
|
||
|
return status, err
|
||
|
}
|