364 lines
7.8 KiB
Go
364 lines
7.8 KiB
Go
package user
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/json"
|
|
"errors"
|
|
"math/big"
|
|
"regexp"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"git.umbach.dev/app-idea/rest-api/modules/config"
|
|
"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"
|
|
"git.umbach.dev/app-idea/rest-api/modules/utils"
|
|
"github.com/gofiber/fiber/v2"
|
|
log "github.com/sirupsen/logrus"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var cfg = &config.Cfg
|
|
|
|
func generateRandomString(n int, t int) (string, error) {
|
|
var letters string
|
|
|
|
if t == 1 {
|
|
letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
|
} else {
|
|
letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
}
|
|
|
|
r := make([]byte, n)
|
|
|
|
for i := 0; i < n; i++ {
|
|
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
r[i] = letters[num.Int64()]
|
|
}
|
|
|
|
return string(r), nil
|
|
}
|
|
|
|
func generateRandomHashtag(db *gorm.DB, n int) (string, error) {
|
|
c := make(chan bool)
|
|
var s string
|
|
var err error
|
|
|
|
for {
|
|
s, err = generateRandomString(6, 0)
|
|
|
|
if err != nil {
|
|
log.Warnln("error generating hashtag:", err)
|
|
return "", err
|
|
}
|
|
|
|
go func() {
|
|
c <- isHashtagValid(db, 0, s)
|
|
}()
|
|
|
|
if msg := <-c; msg {
|
|
break
|
|
}
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func isHashtagValid(db *gorm.DB, t int, h string) bool {
|
|
if t == 1 && !isUpper(h) || len(h) < 2 || len(h) > 6 {
|
|
return false
|
|
}
|
|
|
|
var res string
|
|
|
|
db.Raw("SELECT hashtag FROM users WHERE hashtag = ?", h).Scan(&res)
|
|
|
|
if res == "" {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
func isUpper(s string) bool {
|
|
for _, r := range s {
|
|
if !unicode.IsUpper(r) && unicode.IsLetter(r) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func isUsernameValid(u string) bool {
|
|
if len(u) < int(cfg.Settings.Lengths.UsernameMinLen) || len(u) > int(cfg.Settings.Lengths.UsernameMaxLen) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
var emailRegex = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
|
|
|
func isEmailValid(e string) bool {
|
|
if len(e) < int(cfg.Settings.Lengths.EmailMinLen) || len(e) > int(cfg.Settings.Lengths.EmailMaxLen) {
|
|
return false
|
|
}
|
|
return emailRegex.MatchString(e)
|
|
}
|
|
|
|
func isPasswordValid(p string) bool {
|
|
if len(p) < int(cfg.Settings.Lengths.PasswordMinLen) || len(p) > int(cfg.Settings.Lengths.PasswordMaxLen) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func isEmailAvailable(db *gorm.DB, email string) bool {
|
|
var res string
|
|
|
|
db.Raw("SELECT email FROM users WHERE email = ?", email).Scan(&res)
|
|
|
|
if res == "" {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
func getUserIdBySessionId(sessionId string) (string, error) {
|
|
db := database.DB
|
|
session := structs.Session{}
|
|
|
|
db.Select("user_id").Where(cfg.Settings.Cookies.SessionId+" = ?", sessionId).Find(&session)
|
|
|
|
return session.UserId, nil
|
|
}
|
|
|
|
func GetUserById(c *fiber.Ctx) error {
|
|
// swagger:operation GET /users User user
|
|
// ---
|
|
// summary: Informations about an user by id (except password)
|
|
// parameters:
|
|
// - name: v
|
|
// in: query
|
|
// description: Example -> { "v"; ["name", "state", "language_id"] }
|
|
// type: string
|
|
// required: true
|
|
// responses:
|
|
// '200':
|
|
// description: User informations
|
|
// '400':
|
|
// description: Values wrong format
|
|
|
|
return userInfos(c, c.Params("id"))
|
|
}
|
|
|
|
func GetUser(c *fiber.Ctx) error {
|
|
// swagger:operation GET /user User user
|
|
// ---
|
|
// summary: Informations about the user (except password)
|
|
// parameters:
|
|
// - name: v
|
|
// in: query
|
|
// description: Example -> { "v"; ["name", "state", "language_id"] }
|
|
// type: string
|
|
// required: true
|
|
// responses:
|
|
// '200':
|
|
// description: User informations
|
|
// '400':
|
|
// description: Values wrong format
|
|
|
|
return userInfos(c, "")
|
|
}
|
|
|
|
func userInfos(c *fiber.Ctx, userId string) error {
|
|
type Input struct {
|
|
Values []string `json:"v"`
|
|
}
|
|
|
|
var input Input
|
|
|
|
if err := c.BodyParser(&input); err != nil {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
value := strings.Join(input.Values, ",")
|
|
|
|
if strings.Contains(value, "password") {
|
|
return c.SendStatus(fiber.StatusForbidden)
|
|
}
|
|
|
|
db := database.DB
|
|
|
|
if userId == "" {
|
|
var err error
|
|
|
|
userId, err = getUserIdBySessionId(c.Cookies(cfg.Settings.Cookies.SessionId))
|
|
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
}
|
|
|
|
user := map[string]interface{}{}
|
|
|
|
res := db.Model(&structs.User{}).Select(value).First(&user, "id = ?", userId)
|
|
|
|
if res.Error != nil {
|
|
return c.SendStatus(fiber.StatusBadRequest)
|
|
}
|
|
|
|
return c.JSON(&user)
|
|
}
|
|
|
|
func GetUserBySessionId(sessionId string) (structs.User, error) {
|
|
db := database.DB
|
|
user := structs.User{}
|
|
userId, err := getUserIdBySessionId(sessionId)
|
|
|
|
if err != nil {
|
|
return user, err
|
|
}
|
|
|
|
err = db.Where("id = ?", userId).First(&user).Error
|
|
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return user, err
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
func deleteUser(c *fiber.Ctx) error {
|
|
userAction := structs.UserAction{Id: c.Params("actionId")}
|
|
|
|
db := database.DB
|
|
|
|
db.First(&userAction)
|
|
|
|
db.Delete(&structs.User{Id: userAction.UserId})
|
|
db.Where("user_id = ?", userAction.UserId).Delete(&structs.Session{})
|
|
db.Delete(&userAction)
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func DeleteUser(c *fiber.Ctx) error {
|
|
user, err := GetUserBySessionId(c.Cookies(cfg.Settings.Cookies.SessionId))
|
|
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
userActivationId, err := createUserAction(user.Id)
|
|
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
user.State = 2
|
|
|
|
db := database.DB
|
|
|
|
db.Save(&user)
|
|
|
|
rabbitmq.PublishMail(structs.RabbitmqMailMessage{Mail: user.Email, TemplateId: 1, LanguageId: user.LanguageId, BodyData: json.RawMessage(`{"name": "` + user.Name + `",
|
|
"email": "` + user.Email + `",
|
|
"url": "http://localhost:3000/api/v1/user/action/1/` + userActivationId + `"}`)})
|
|
|
|
return c.SendStatus(fiber.StatusOK)
|
|
}
|
|
|
|
func GetUsers(c *fiber.Ctx) error {
|
|
db := database.DB
|
|
|
|
log.Info("here")
|
|
|
|
users := []structs.APIUser{}
|
|
|
|
db.Model(&structs.User{}).Find(&users)
|
|
|
|
return c.JSON(users)
|
|
}
|
|
|
|
func UpdateUser(c *fiber.Ctx) error {
|
|
file, err := c.FormFile("image")
|
|
|
|
if err != nil {
|
|
log.Debugln("FormFile err", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
bytes, err := utils.FormFileToBytes(file)
|
|
|
|
if err != nil {
|
|
log.Debugln("formFileToBytes err", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
log.Info(len(bytes))
|
|
|
|
user, err := GetUserBySessionId(c.Cookies(config.Cfg.Settings.Cookies.SessionId))
|
|
|
|
if err != nil {
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
// update user avatar
|
|
filename, err := UpdateAvatar(c.Cookies(config.Cfg.Settings.Cookies.SessionId), user, bytes, file.Filename)
|
|
|
|
if err != nil {
|
|
log.Debugln("savepic err", err)
|
|
return c.SendStatus(fiber.StatusInternalServerError)
|
|
}
|
|
|
|
return c.JSON(fiber.Map{"filename": filename})
|
|
}
|
|
|
|
func UpdateAvatar(sessionId string, user structs.User, bytes []byte, filename string) (string, error) {
|
|
newFilename := strings.Replace("avatar"+filename, "-", "", -1)
|
|
|
|
rabbitmq.PublishPicture(structs.RabbitmqPictureMessage{Picture: bytes, UserId: user.Id, Filename: newFilename})
|
|
|
|
db := database.DB
|
|
|
|
res := db.Model(&structs.User{}).Where("id = ?", user.Id).Update("avatar_url", newFilename)
|
|
|
|
// TODO: delete old avatar from storage server
|
|
|
|
if res.Error != nil {
|
|
log.Warnln("Failed to insert user to db:", res.Error)
|
|
return "", res.Error
|
|
}
|
|
|
|
return newFilename, nil
|
|
}
|
|
|
|
/*
|
|
func GetUsers(c *fiber.Ctx) error {
|
|
|
|
list := []string{}
|
|
/*
|
|
var (
|
|
name string
|
|
)*/
|
|
/*
|
|
rows, err := db.Query("SELECT username FROM users;")
|
|
fmt.Println("err", err)
|
|
defer rows.Close()
|
|
fmt.Println("reading data:")
|
|
for rows.Next() {
|
|
err := rows.Scan(&name)
|
|
fmt.Printf("Data row = (%s, %s)\n", name, err)
|
|
list = append(list, name)
|
|
}
|
|
err = rows.Err()*/
|
|
/*
|
|
return c.JSON(list)
|
|
}
|
|
*/
|