2017-05-06 21:21:39 +02:00
package userService
import (
"errors"
2017-05-09 01:56:57 +02:00
"fmt"
2017-05-06 21:21:39 +02:00
"net/http"
"strconv"
2017-05-08 19:26:29 +02:00
"time"
2017-05-06 21:21:39 +02:00
"github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
2017-05-07 00:10:40 +02:00
formStruct "github.com/ewhal/nyaa/service/user/form"
2017-05-06 21:21:39 +02:00
"github.com/ewhal/nyaa/util/crypto"
"github.com/ewhal/nyaa/util/log"
"github.com/ewhal/nyaa/util/modelHelper"
"github.com/ewhal/nyaa/util/timeHelper"
2017-05-09 01:56:57 +02:00
"golang.org/x/crypto/bcrypt"
2017-05-06 21:21:39 +02:00
)
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
}
2017-05-08 22:12:57 +02:00
2017-05-07 21:14:32 +02:00
func CheckEmail ( email string ) bool {
2017-05-08 22:12:57 +02:00
if len ( email ) == 0 {
return true
}
2017-05-07 21:14:32 +02:00
var count int
2017-05-08 22:12:57 +02:00
db . ORM . Model ( model . User { } ) . Where ( "email = ?" , email ) . Count ( & count )
2017-05-07 21:14:32 +02:00
if count == 0 {
2017-05-08 22:12:57 +02:00
return false // duplicate
2017-05-07 21:14:32 +02:00
}
return true
}
2017-05-08 22:12:57 +02:00
2017-05-06 21:21:39 +02:00
// CreateUserFromForm creates a user from a registration form.
2017-05-07 00:10:40 +02:00
func CreateUserFromForm ( registrationForm formStruct . RegistrationForm ) ( model . User , error ) {
2017-05-06 21:21:39 +02:00
var user model . User
log . Debugf ( "registrationForm %+v\n" , registrationForm )
modelHelper . AssignValue ( & user , & registrationForm )
2017-05-09 03:36:48 +02:00
user . Md5 = crypto . GenerateMD5Hash ( user . Email ) // Gravatar
2017-05-06 21:21:39 +02:00
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
2017-05-07 00:10:40 +02:00
var registrationForm formStruct . RegistrationForm
2017-05-06 21:21:39 +02:00
var status int
var err error
2017-05-09 01:56:57 +02:00
2017-05-06 21:21:39 +02:00
modelHelper . BindValueForm ( & registrationForm , r )
2017-05-07 21:14:32 +02:00
usernameCandidate := SuggestUsername ( registrationForm . Username )
2017-05-09 01:56:57 +02:00
if usernameCandidate != registrationForm . Username {
2017-05-07 21:14:32 +02:00
return http . StatusInternalServerError , fmt . Errorf ( "Username already taken, you can choose: %s" , usernameCandidate )
}
if CheckEmail ( registrationForm . Email ) {
return http . StatusInternalServerError , errors . New ( "Email Address already in our database!" )
}
2017-05-06 21:21:39 +02:00
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 )
2017-05-06 22:27:21 +02:00
status , err = RegisterHandler ( w , r )
2017-05-06 21:21:39 +02:00
return status , err
}
// RetrieveUser retrieves a user.
func RetrieveUser ( r * http . Request , id string ) ( * model . PublicUser , bool , uint , int , error ) {
2017-05-08 20:21:11 +02:00
var user model . User
2017-05-06 21:21:39 +02:00
var currentUserId uint
var isAuthor bool
// var publicUser *model.PublicUser
// publicUser.User = &user
2017-05-08 22:33:40 +02:00
if db . ORM . First ( & user , id ) . RecordNotFound ( ) {
2017-05-08 20:21:11 +02:00
return nil , isAuthor , currentUserId , http . StatusNotFound , errors . New ( "User is not found." )
2017-05-06 21:21:39 +02:00
}
currentUser , err := CurrentUser ( r )
if err == nil {
currentUserId = currentUser . Id
isAuthor = currentUser . Id == user . Id
}
2017-05-08 20:21:11 +02:00
return & model . PublicUser { User : & user } , isAuthor , currentUserId , http . StatusOK , nil
2017-05-06 21:21:39 +02:00
}
// RetrieveUsers retrieves users.
func RetrieveUsers ( ) [ ] * model . PublicUser {
var users [ ] * model . User
var userArr [ ] * model . PublicUser
2017-05-08 22:33:40 +02:00
db . ORM . Find ( & users )
2017-05-06 21:21:39 +02:00
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 ) {
2017-05-09 03:36:48 +02:00
user . Md5 = crypto . GenerateMD5Hash ( user . Email )
2017-05-06 21:21:39 +02:00
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." )
}
2017-05-08 19:26:29 +02:00
user . UpdatedAt = time . Now ( )
2017-05-06 21:21:39 +02:00
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" :
2017-05-07 00:10:40 +02:00
var passwordForm formStruct . PasswordForm
2017-05-06 21:21:39 +02:00
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 :
2017-05-07 00:10:40 +02:00
var form formStruct . UserForm
2017-05-06 22:27:21 +02:00
modelHelper . BindValueForm ( & form , r )
2017-05-06 21:21:39 +02:00
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
}
// 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
2017-05-08 22:33:40 +02:00
if db . ORM . Unscoped ( ) . Where ( "email = ?" , email ) . First ( & user ) . RecordNotFound ( ) {
2017-05-06 21:21:39 +02:00
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
2017-05-08 22:33:40 +02:00
db . ORM . Where ( "email = ?" , email ) . Find ( & users )
2017-05-06 21:21:39 +02:00
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
2017-05-08 22:33:40 +02:00
if db . ORM . Where ( "username = ?" , username ) . First ( & user ) . RecordNotFound ( ) {
2017-05-06 21:21:39 +02:00
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
2017-05-09 07:21:14 +02:00
if db . ORM . Preload ( "Torrents" ) . First ( & user , id ) . RecordNotFound ( ) {
2017-05-06 21:21:39 +02:00
return user , http . StatusNotFound , errors . New ( "User is not found." )
}
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 {
2017-05-08 19:26:29 +02:00
db . ORM . Model ( & user )
2017-05-09 03:36:48 +02:00
db . ORM . Model ( & user ) . Related ( "Torrents" ) . Find ( & model . Torrents { } )
2017-05-06 21:21:39 +02:00
userArr = append ( userArr , user )
}
return userArr
}
// CreateUserAuthentication creates user authentication.
func CreateUserAuthentication ( w http . ResponseWriter , r * http . Request ) ( int , error ) {
2017-05-07 00:10:40 +02:00
var form formStruct . LoginForm
2017-05-06 21:21:39 +02:00
modelHelper . BindValueForm ( & form , r )
2017-05-08 00:21:31 +02:00
username := form . Username
2017-05-06 21:21:39 +02:00
pass := form . Password
2017-05-08 00:21:31 +02:00
status , err := SetCookieHandler ( w , username , pass )
2017-05-06 21:21:39 +02:00
return status , err
}