package user import ( "database/sql" "fmt" "math/rand" "regexp" "strings" "time" "git.umbach.dev/app-idea/rest-api/modules/database" "git.umbach.dev/app-idea/rest-api/modules/debug" "github.com/gofiber/fiber/v2" "github.com/google/uuid" "golang.org/x/crypto/bcrypt" ) //err = bcrypt.CompareHashAndPassword(hashedPassword, []byte("hello wolrd")) //fmt.Println(err) 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-254) // type: string // required: true // - name: password // in: query // description: password of the user (length 6-250) // type: string // required: true // - name: hashtag // in: query // description: hashtag of the client (length 1-6, UPPERCASE) // 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 // '400': // description: format is not correct // '422': // description: username or/and email already already assigned type LoginInput struct { Username string `json:"username"` Email string `json:"email"` Password string `json:"password"` } var input LoginInput if err := c.BodyParser(&input); err != nil { return c.SendStatus(fiber.StatusBadRequest) } if !isValid(input.Username, 3, 30) || !isEmailValid(input.Email) || !isValid(input.Password, 6, 250) { return c.SendStatus(fiber.StatusForbidden) } db, err := database.GetDatabase() if db == nil || err != nil { return c.SendStatus(fiber.StatusInternalServerError) } defer db.Close() if !isValueAvailable(db, "email", input.Email) { return c.SendStatus(fiber.StatusUnprocessableEntity) } password := []byte(input.Password) hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost) if err != nil { debug.Msg("bcrypt password error", err) return c.SendStatus(fiber.StatusInternalServerError) } user_id := strings.Replace(uuid.New().String(), "-", "", -1) user_hashtag := RandomHashtag(db, 6) created := time.Now().Format("2006-02-01 15:04:05") stmt, err := db.Prepare("INSERT INTO users (user_id, user_hashtag, username, email, password, created) VALUES (?, ?, ?, ?, ?, ?);") stmt.Exec(user_id, user_hashtag, input.Username, input.Email, hashedPassword, created) stmt.Close() debug.Msg("user created", user_id, user_hashtag, input.Username, input.Email) return c.SendStatus(fiber.StatusCreated) } func RandomHashtag(db *sql.DB, n int) string { var letters = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ") s := make([]rune, n) c := make(chan bool) for { // TODO: randomness is very bad -> always the same for i := range s { s[i] = letters[rand.Intn(len(letters))] } fmt.Println(string(s)) go func() { fmt.Println("conncur", string(s)) err := db.QueryRow("SELECT user_hashtag FROM users WHERE user_hashtag = ?", string(s)).Scan(&s) fmt.Println("ErrNoRows?", err == sql.ErrNoRows) if err == sql.ErrNoRows { c <- true } else { c <- false } }() msg := <-c fmt.Println("msg", msg) if msg { break } } fmt.Println("r string", string(s)) return string(s) /* err := db.QueryRow("SELECT user_hashtag FROM users WHERE user_hashtag = ?", s).Scan(&s) if err == sql.ErrNoRows { return true } return false return string(s) */ } func isValid(s string, min int, max int) bool { if len(s) < min || len(s) > max { 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) < 3 || len(e) > 254 { return false } return emailRegex.MatchString(e) } func isValueAvailable(db *sql.DB, t string, v string) bool { q := fmt.Sprintf("SELECT %s FROM users WHERE %s = ?", t, t) err := db.QueryRow(q, v).Scan(&v) fmt.Println(err == sql.ErrNoRows) if err == sql.ErrNoRows { return true } return false /* if email == "" { return true } return false */ /* ctx := context.Background() tsql := fmt.Sprintf("SELECT email FROM users WHERE email = '%s'", e) rows, err := db.QueryContext(ctx, tsql) if err != nil { panic(err) } fmt.Println("rows", rows) defer rows.Close() var count int for rows.Next() { var email string err := rows.Scan(&email) if err != nil { panic(err) } fmt.Printf("Email: %s \n", email) count++ } fmt.Println(count) */ } func GetUser(c *fiber.Ctx) error { return c.SendString("user") } func GetUsers(c *fiber.Ctx) error { db, err := database.GetDatabase() // c.Params("id") if db == nil || err != nil { return c.SendString("db 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() fmt.Println("Done") return c.JSON(list) }