197 lines
5.1 KiB
Go
197 lines
5.1 KiB
Go
package user
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.umbach.dev/app-idea/rest-api/modules/database"
|
|
"git.umbach.dev/app-idea/rest-api/modules/rabbitmq"
|
|
"git.umbach.dev/app-idea/rest-api/modules/structs"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/google/uuid"
|
|
log "github.com/sirupsen/logrus"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type RegisterInput struct {
|
|
Username string `json:"username"`
|
|
Email string `json:"email"`
|
|
Password string `json:"password"`
|
|
Hashtag string `json:"hashtag"`
|
|
LanguageId int `json:"languageId"`
|
|
}
|
|
|
|
func NewUser(c *fiber.Ctx) error {
|
|
// swagger:operation POST /users User user
|
|
// ---
|
|
// summary: Create new user
|
|
// produces:
|
|
// - application/json
|
|
// parameters:
|
|
// - name: username
|
|
// in: query
|
|
// description: username of the user (length 3-30)
|
|
// type: string
|
|
// required: true
|
|
// - name: email
|
|
// in: query
|
|
// description: email of the user (length 3-255)
|
|
// type: string
|
|
// required: true
|
|
// - name: password
|
|
// in: query
|
|
// description: password (base64) of the user (length 6-250)
|
|
// type: string
|
|
// required: true
|
|
// - name: hashtag
|
|
// in: query
|
|
// description: hashtag of the client (length 2-6, UPPERCASE (Letters, Numbers))
|
|
// type: string
|
|
// - name: avatar_url
|
|
// in: query
|
|
// description: avatar url of the client
|
|
// type: string
|
|
// - name: location
|
|
// in: query
|
|
// description: location of the client (length 1-20) (for example Frankfurt)
|
|
// type: string
|
|
// responses:
|
|
// '201':
|
|
// "$ref": "#/definitions/User"
|
|
// '400':
|
|
// description: format is not correct
|
|
// '422':
|
|
// description: username, email or/and hashtag already assigned
|
|
|
|
var input RegisterInput
|
|
|
|
if err := c.BodyParser(&input); err != nil {
|
|
log.Debugln("bodyParser failed:", err)
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
decodedPassword, err := base64.StdEncoding.DecodeString(input.Password)
|
|
|
|
if err != nil {
|
|
log.Debugln("base64 decoding failed:", err)
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
input.Password = string(decodedPassword)
|
|
|
|
if !isUsernameValid(input.Username) || !isEmailValid(input.Email) || !isPasswordValid(input.Password) {
|
|
return c.SendStatus(fiber.StatusForbidden)
|
|
}
|
|
|
|
user := structs.User{Email: input.Email}
|
|
db := database.DB
|
|
|
|
if !isEmailAvailable(db, user.Email) {
|
|
return c.SendStatus(fiber.StatusUnprocessableEntity)
|
|
}
|
|
|
|
if input.Hashtag == "" {
|
|
input.Hashtag, err = generateRandomHashtag(db, 6)
|
|
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
} else if !isHashtagValid(db, 1, input.Hashtag) {
|
|
return c.SendStatus(fiber.StatusUnprocessableEntity)
|
|
}
|
|
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
|
|
|
|
if err != nil {
|
|
log.Warnln("Failed to bcrypt password", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
now := time.Now()
|
|
|
|
user.Id = strings.Replace(uuid.New().String(), "-", "", -1)
|
|
user.Hashtag = input.Hashtag
|
|
user.Name = input.Username
|
|
user.Password = string(hashedPassword)
|
|
user.LanguageId = input.LanguageId
|
|
user.State = 1
|
|
user.LastLogin = now
|
|
user.CreatedAt = now
|
|
|
|
res := db.Create(&user)
|
|
|
|
if res.Error != nil {
|
|
log.Warnln("Failed to insert user to db:", res.Error)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
userActionId, err := createUserAction(user.Id)
|
|
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
rabbitmq.PublishMail(user.Email, 0, user.LanguageId, json.RawMessage(`{"name": "`+user.Name+`",
|
|
"email": "`+user.Email+`",
|
|
"url": "http://localhost:3000/api/v1/user/action/0/`+userActionId+`"}`))
|
|
|
|
sessionId, err := createUserSession(db, user.Id, c.IP(), string(c.Context().UserAgent()))
|
|
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
expires := getUserSessionExpiresTime()
|
|
cfg := cfg.Settings.Cookies
|
|
|
|
c.Cookie(&fiber.Cookie{Name: cfg.SessionId, Value: sessionId, Secure: true, HTTPOnly: true, Expires: expires})
|
|
c.Cookie(&fiber.Cookie{Name: cfg.Username, Value: input.Username, Secure: true, Expires: expires})
|
|
c.Cookie(&fiber.Cookie{Name: cfg.UserHashtag, Value: input.Hashtag, Secure: true, Expires: expires})
|
|
|
|
log.Debugln("user created", user)
|
|
|
|
return c.SendStatus(fiber.StatusCreated)
|
|
}
|
|
|
|
func ActivateUser(c *fiber.Ctx) error {
|
|
// swagger:operation POST /user/action/{actionType}/{actionId} User activation
|
|
// ---
|
|
// summary: Activate user
|
|
// parameters:
|
|
// - name: id
|
|
// in: query
|
|
// description: action id
|
|
// type: string
|
|
// required: true
|
|
// responses:
|
|
// '200':
|
|
// description: User was activated
|
|
// '401':
|
|
// description: action Id is incorrect or expired
|
|
|
|
db := database.DB
|
|
|
|
deleteExpiredUserActions(db)
|
|
|
|
userAction := structs.UserAction{Id: c.Params("actionId")}
|
|
|
|
log.Infoln("activate user", c.Params("actionType"), c.Params("actionId"))
|
|
|
|
db.Select("user_id").Where("id = ?", c.Params("actionId")).Find(&userAction)
|
|
|
|
log.Infoln("usA", userAction)
|
|
|
|
if userAction.UserId == "" {
|
|
log.Info("StatusUnauthorized")
|
|
return c.SendStatus(fiber.StatusUnauthorized)
|
|
}
|
|
|
|
db.Delete(userAction)
|
|
|
|
db.Model(structs.User{Id: userAction.UserId}).Update("state", 0)
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|