appidea-restapi/routers/api/v1/user/register.go

194 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 usersNewUser
// ---
// 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':
// description: user created
// "$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)
}
// account activation via email
userActivationId, err := createUserActivation(user.Id)
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
type JsonMessage struct {
Key string `json:"k"`
Mail string `json:"m"`
TemplateId int `json:"t"`
LanguageId int `json:"l"`
BodyData *json.RawMessage `json:"d"`
}
bodyData := json.RawMessage(`{"name": "` + user.Name + `",
"email": "` + user.Email + `",
"url": "http://localhost:3000/api/v1/user/activate/` + userActivationId + `"}`)
js := JsonMessage{Key: "mykey", Mail: "app@roese.dev", TemplateId: 0, LanguageId: user.LanguageId, BodyData: &bodyData}
reqBody, err := json.MarshalIndent(&js, "", "\t")
if err != nil {
log.Infoln("error reqBody", err)
}
rabbitmq.Publish(string(reqBody))
/*resp, err := http.Post(cfg.Mail.Host+"/send", "application/json", bytes.NewBuffer(reqBody))
if err != nil {
log.Infoln("err http post", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Infoln("err reading body", err)
}
log.Infoln("body", body)
log.Infoln("StatusCode", resp.StatusCode)*/
sessionId, err := createUserSession(db, user.Id, c.IP(), string(c.Context().UserAgent()))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
expires := getUserSessionExpiresTime()
c.Cookie(&fiber.Cookie{Name: "session_id", Value: sessionId, Secure: true, HTTPOnly: true, Expires: expires})
c.Cookie(&fiber.Cookie{Name: "username", Value: input.Username, Secure: true, Expires: expires})
c.Cookie(&fiber.Cookie{Name: "user_hashtag", Value: input.Hashtag, Secure: true, Expires: expires})
log.Debugln("user created", user)
return c.SendStatus(fiber.StatusCreated)
}