09052021
parent
a58aa7306c
commit
8ad6b6e623
|
@ -9,7 +9,7 @@ POST http://localhost:3000/api/v1/users
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
|
|
||||||
{
|
{
|
||||||
"username": "alex",
|
"username": "ben4",
|
||||||
"email": "restapi@roese.dev",
|
"email": "ben4@roese.dev",
|
||||||
"password": "teksmkamsdkasdmaskdmaskdm"
|
"password": "teksmkamsdkasdmaskdmaskdm"
|
||||||
}
|
}
|
10
main.go
10
main.go
|
@ -22,23 +22,17 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.umbach.dev/app-idea/rest-api/routers/config"
|
"git.umbach.dev/app-idea/rest-api/modules/config"
|
||||||
"git.umbach.dev/app-idea/rest-api/routers/database"
|
"git.umbach.dev/app-idea/rest-api/modules/database"
|
||||||
"git.umbach.dev/app-idea/rest-api/routers/router"
|
"git.umbach.dev/app-idea/rest-api/routers/router"
|
||||||
|
|
||||||
_ "github.com/go-sql-driver/mysql"
|
_ "github.com/go-sql-driver/mysql"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/gofiber/fiber/v2/middleware/cors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
|
|
||||||
app.Use(cors.New(cors.Config{
|
|
||||||
AllowOrigins: "*",
|
|
||||||
AllowHeaders: "Origin, Content-Type, Accept",
|
|
||||||
}))
|
|
||||||
|
|
||||||
router.SetupRoutes(app)
|
router.SetupRoutes(app)
|
||||||
|
|
||||||
config.LoadConfig()
|
config.LoadConfig()
|
||||||
|
|
|
@ -5,7 +5,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.umbach.dev/app-idea/rest-api/routers/config"
|
"git.umbach.dev/app-idea/rest-api/modules/config"
|
||||||
|
"git.umbach.dev/app-idea/rest-api/modules/debug"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getConnectionString() string {
|
func getConnectionString() string {
|
||||||
|
@ -15,10 +16,11 @@ func getConnectionString() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDatabase() (*sql.DB, error) {
|
func GetDatabase() (*sql.DB, error) {
|
||||||
db, err := sql.Open("mysql", getConnectionString())
|
db, _ := sql.Open("mysql", getConnectionString())
|
||||||
|
|
||||||
if err != nil {
|
if err := db.Ping(); err != nil {
|
||||||
return db, errors.New("db error")
|
debug.Msg("DB Connection error:", err.Error())
|
||||||
|
return nil, errors.New(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return db, nil
|
return db, nil
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.umbach.dev/app-idea/rest-api/routers/config"
|
"git.umbach.dev/app-idea/rest-api/modules/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Msg(msg ...interface{}) {
|
func Msg(msg ...interface{}) {
|
|
@ -0,0 +1 @@
|
||||||
|
package mailer
|
|
@ -1,19 +1,23 @@
|
||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.umbach.dev/app-idea/rest-api/routers/database"
|
"git.umbach.dev/app-idea/rest-api/modules/database"
|
||||||
"git.umbach.dev/app-idea/rest-api/routers/debug"
|
"git.umbach.dev/app-idea/rest-api/modules/debug"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewUser
|
//err = bcrypt.CompareHashAndPassword(hashedPassword, []byte("hello wolrd"))
|
||||||
|
//fmt.Println(err)
|
||||||
|
|
||||||
func NewUser(c *fiber.Ctx) error {
|
func NewUser(c *fiber.Ctx) error {
|
||||||
// swagger:operation POST /users user usersNewUser
|
// swagger:operation POST /users user usersNewUser
|
||||||
// ---
|
// ---
|
||||||
|
@ -28,25 +32,33 @@ func NewUser(c *fiber.Ctx) error {
|
||||||
// required: true
|
// required: true
|
||||||
// - name: email
|
// - name: email
|
||||||
// in: query
|
// in: query
|
||||||
// description: email of the user (length max 200)
|
// description: email of the user (length 3-254)
|
||||||
// type: string
|
// type: string
|
||||||
// required: true
|
// required: true
|
||||||
// - name: password
|
// - name: password
|
||||||
// in: query
|
// in: query
|
||||||
// description: password of the user (length 6-256)
|
// description: password of the user (length 6-250)
|
||||||
// type: string
|
// type: string
|
||||||
// required: true
|
// 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:
|
// responses:
|
||||||
// '200':
|
// '201':
|
||||||
// description: user created
|
// description: user created
|
||||||
// schema:
|
// '400':
|
||||||
// type: object
|
// description: format is not correct
|
||||||
// example:
|
// '422':
|
||||||
// user_hastag: XVLBZG
|
// description: username or/and email already already assigned
|
||||||
// default:
|
|
||||||
// description: unexpected error
|
|
||||||
// schema:
|
|
||||||
// "$ref": "#/definitions/errorModel"
|
|
||||||
type LoginInput struct {
|
type LoginInput struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
@ -55,17 +67,24 @@ func NewUser(c *fiber.Ctx) error {
|
||||||
|
|
||||||
var input LoginInput
|
var input LoginInput
|
||||||
|
|
||||||
// check if given request is complete
|
|
||||||
if err := c.BodyParser(&input); err != nil {
|
if err := c.BodyParser(&input); err != nil {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"status": "error", "message": "Error on login request", "data": err})
|
return c.SendStatus(fiber.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check in database if username and email is available
|
if !isValid(input.Username, 3, 30) || !isEmailValid(input.Email) || !isValid(input.Password, 6, 250) {
|
||||||
|
return c.SendStatus(fiber.StatusForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
db, err := database.GetDatabase()
|
db, err := database.GetDatabase()
|
||||||
|
|
||||||
if db == nil || err != nil {
|
if db == nil || err != nil {
|
||||||
return c.SendString(err.Error())
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
if !isValueAvailable(db, "email", input.Email) {
|
||||||
|
return c.SendStatus(fiber.StatusUnprocessableEntity)
|
||||||
}
|
}
|
||||||
|
|
||||||
password := []byte(input.Password)
|
password := []byte(input.Password)
|
||||||
|
@ -73,38 +92,139 @@ func NewUser(c *fiber.Ctx) error {
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
|
hashedPassword, err := bcrypt.GenerateFromPassword(password, bcrypt.DefaultCost)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
debug.Msg("bcrypt password error", err)
|
||||||
|
return c.SendStatus(fiber.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
//err = bcrypt.CompareHashAndPassword(hashedPassword, []byte("hello wolrd"))
|
|
||||||
//fmt.Println(err)
|
|
||||||
|
|
||||||
user_id := strings.Replace(uuid.New().String(), "-", "", -1)
|
user_id := strings.Replace(uuid.New().String(), "-", "", -1)
|
||||||
user_hashtag := RandomHashtag(6)
|
user_hashtag := RandomHashtag(db, 6)
|
||||||
created := time.Now().Format("2006-02-01 15:04:05")
|
created := time.Now().Format("2006-02-01 15:04:05")
|
||||||
|
|
||||||
sqlStatement, err := db.Prepare("INSERT INTO users (user_id, user_hashtag, username, email, password, created) VALUES (?, ?, ?, ?, ?, ?);")
|
stmt, err := db.Prepare("INSERT INTO users (user_id, user_hashtag, username, email, password, created) VALUES (?, ?, ?, ?, ?, ?);")
|
||||||
sqlStatement.Exec(user_id, user_hashtag, input.Username, input.Email, hashedPassword, created)
|
stmt.Exec(user_id, user_hashtag, input.Username, input.Email, hashedPassword, created)
|
||||||
|
|
||||||
db.Close()
|
stmt.Close()
|
||||||
|
|
||||||
debug.Msg("user created", user_id, user_hashtag, input.Username, input.Email)
|
debug.Msg("user created", user_id, user_hashtag, input.Username, input.Email)
|
||||||
|
|
||||||
return c.JSON(fiber.Map{"status": 1, "user_hashtag": user_hashtag})
|
return c.SendStatus(fiber.StatusCreated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RandomHashtag(n int) string {
|
func RandomHashtag(db *sql.DB, n int) string {
|
||||||
var letters = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
var letters = []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
|
||||||
s := make([]rune, n)
|
s := make([]rune, n)
|
||||||
|
c := make(chan bool)
|
||||||
|
|
||||||
|
for {
|
||||||
|
// TODO: randomness is very bad -> always the same
|
||||||
for i := range s {
|
for i := range s {
|
||||||
s[i] = letters[rand.Intn(len(letters))]
|
s[i] = letters[rand.Intn(len(letters))]
|
||||||
}
|
}
|
||||||
|
|
||||||
//fmt.Println(s)
|
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)
|
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 {
|
func GetUser(c *fiber.Ctx) error {
|
||||||
|
@ -127,6 +247,7 @@ func GetUsers(c *fiber.Ctx) error {
|
||||||
)
|
)
|
||||||
|
|
||||||
rows, err := db.Query("SELECT username FROM users;")
|
rows, err := db.Query("SELECT username FROM users;")
|
||||||
|
fmt.Println("err", err)
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
fmt.Println("reading data:")
|
fmt.Println("reading data:")
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
|
|
20
swagger.yaml
20
swagger.yaml
|
@ -26,24 +26,24 @@ paths:
|
||||||
name: email
|
name: email
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
- description: password of the user (length 6-256)
|
- description: password of the user (length 6-250)
|
||||||
in: query
|
in: query
|
||||||
name: password
|
name: password
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
- description: hashtag of the client (length 1-6, UPPERCASE)
|
||||||
|
in: query
|
||||||
|
name: hashtag
|
||||||
|
type: string
|
||||||
produces:
|
produces:
|
||||||
- application/json
|
- application/json
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"201":
|
||||||
description: user created
|
description: user created
|
||||||
schema:
|
"400":
|
||||||
example:
|
description: format is not correct
|
||||||
user_hastag: XVLBZG
|
"422":
|
||||||
type: object
|
description: username or/and email already already assigned
|
||||||
default:
|
|
||||||
description: unexpected error
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/errorModel'
|
|
||||||
summary: Create new user
|
summary: Create new user
|
||||||
tags:
|
tags:
|
||||||
- user
|
- user
|
||||||
|
|
Loading…
Reference in New Issue