Register endpoint working

This commit is contained in:
Lukas Bachschwell 2018-11-13 21:39:04 +01:00
parent 6a6c38f3ee
commit 00f4288c25
4 changed files with 206 additions and 90 deletions

View File

@ -1,6 +1,7 @@
package controllers package controllers
import ( import (
"fmt"
"multitenantStack/models" "multitenantStack/models"
companydb "multitenantStack/services/companydb" companydb "multitenantStack/services/companydb"
@ -9,6 +10,7 @@ import (
"github.com/astaxie/beego/orm" "github.com/astaxie/beego/orm"
jwt "github.com/dgrijalva/jwt-go" jwt "github.com/dgrijalva/jwt-go"
"github.com/kennygrant/sanitize"
) )
// AuthController operations for Auth // AuthController operations for Auth
@ -16,14 +18,18 @@ type AuthController struct {
BaseController BaseController
} }
// AuthResponse the format for all responses from auth
type AuthResponse struct {
Status int `json:"status"`
Jwt string `json:"jwt"`
User models.CompanyUser `json:"user"`
}
// URLMapping ... // URLMapping ...
func (c *AuthController) URLMapping() { func (c *AuthController) URLMapping() {
// This block is used to drastically speed up the annotation -> lookup process // This block is used to drastically speed up the annotation -> lookup process
c.Mapping("Login", c.Login) c.Mapping("Login", c.Login)
c.Mapping("GetOne", c.GetOne) c.Mapping("Register", c.Register)
c.Mapping("GetAll", c.GetAll)
c.Mapping("Put", c.Put)
c.Mapping("Delete", c.Delete)
} }
// Login Get a JWT token for the user // Login Get a JWT token for the user
@ -34,13 +40,6 @@ func (c *AuthController) URLMapping() {
// @Failure 403 body is empty // @Failure 403 body is empty
// @router /login [post] // @router /login [post]
func (c *AuthController) Login() { func (c *AuthController) Login() {
type AuthResponse struct {
Status int `json:"status"`
Jwt string `json:"jwt"`
User models.CompanyUser `json:"user"`
}
if c.Ctx.Input.Method() != "POST" { if c.Ctx.Input.Method() != "POST" {
c.ServeJSONError("Method not allowed") c.ServeJSONError("Method not allowed")
return return
@ -127,52 +126,135 @@ func (c *AuthController) Login() {
c.ServeJSON() c.ServeJSON()
} }
// GetOne ... // Register Register a new company and user, create DB and so on
// @Title GetOne // @Title Create
// @Description get Auth by id // @Description create Auth
// @Param id path string true "The key for staticblock"
// @Success 200 {object} models.Auth
// @Failure 403 :id is empty
// @router /:id [get]
func (c *AuthController) GetOne() {
}
// GetAll ...
// @Title GetAll
// @Description get Auth
// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..."
// @Param fields query string false "Fields returned. e.g. col1,col2 ..."
// @Param sortby query string false "Sorted-by fields. e.g. col1,col2 ..."
// @Param order query string false "Order corresponding to each sortby field, if single value, apply to all sortby fields. e.g. desc,asc ..."
// @Param limit query string false "Limit the size of result set. Must be an integer"
// @Param offset query string false "Start position of result set. Must be an integer"
// @Success 200 {object} models.Auth
// @Failure 403
// @router / [get]
func (c *AuthController) GetAll() {
}
// Put ...
// @Title Put
// @Description update the Auth
// @Param id path string true "The id you want to update"
// @Param body body models.Auth true "body for Auth content" // @Param body body models.Auth true "body for Auth content"
// @Success 200 {object} models.Auth // @Success 201 {object} models.Auth
// @Failure 403 :id is not int // @Failure 403 body is empty
// @router /:id [put] // @router /register [post]
func (c *AuthController) Put() { func (c *AuthController) Register() {
// can be called without jwt token set
// needed data:
// email
// password
// companyname
// optional: username
// Tasks:
// create database
// create user_company_map entry
// create company user
// return jwt token and user profile
if c.Ctx.Input.Method() != "POST" {
c.ServeJSONError("Method not allowed")
return
} }
// Delete ... tokenHeader := c.Ctx.Request.Header.Get("X-JWTtoken")
// @Title Delete if tokenHeader != "" {
// @Description delete the Auth valid, _ := tokenTools.Validate(tokenHeader)
// @Param id path string true "The id you want to delete" if valid {
// @Success 200 {string} delete success! c.ServeJSONError("You are already logged in")
// @Failure 403 id is empty return
// @router /:id [delete] }
func (c *AuthController) Delete() { }
email := c.GetString("email")
password := c.GetString("password")
username := c.GetString("username")
companyname := c.GetString("companyname")
companyname = sanitize.BaseName(companyname)
companyname = fmt.Sprintf("company_%s", companyname)
if email == "" || password == "" || companyname == "" || username == "" {
c.ServeJSONError("Email/Password/Companyname missing")
return
}
systemdb := companydb.GetSystemDatabase()
if systemdb == nil {
c.ServeJSONError("Error retrieving data")
return
}
o, err := orm.NewOrmWithDB("postgres", "default", systemdb)
if err != nil {
c.ServeJSONError("Error retrieving data")
return
}
ucmExists, err := models.GetUserCompanyMapByEmail(o, email)
if err != nil && ucmExists != nil {
c.ServeJSONError("Error: Email exists!")
return
}
if companydb.HasDatabase(companyname) {
c.ServeJSONError("Error: Company exists!")
return
}
var userCompanyMapping models.UserCompanyMap
newHash, _ := tokenTools.HashPassword(password)
userCompanyMapping.PasswordHash = newHash
userCompanyMapping.Company = companyname
userCompanyMapping.Email = email
ucmID, err := models.AddUserCompanyMap(o, &userCompanyMapping)
if err != nil {
c.ServeJSONErrorWithError("Error on saving user", err)
return
}
// Create company
newDB, err := companydb.CreateDatabase(companyname)
if err != nil {
c.ServeJSONErrorWithError("Error on creating DB", err)
return
}
newO, err := orm.NewOrmWithDB("postgres", "default", newDB)
if err != nil {
c.ServeJSONErrorWithError("Error retrieving company data", err)
return
}
var companyUser models.CompanyUser
companyUser.Name = username
companyUser.Profile = "{}"
companyUser.Role = 1 //TODO: replacxe with owner constant
userID, err := models.AddCompanyUser(newO, &companyUser)
if err != nil {
c.ServeJSONError("Error on saving company user")
return
}
// edit usermapping
userCompanyMapping.ID = int(ucmID)
userCompanyMapping.CompanyUserID = int16(userID)
if err := models.UpdateUserCompanyMapById(o, &userCompanyMapping); err != nil {
c.ServeJSONError("Error on saving user")
return
}
tokenString := ""
tokenString = tokenTools.CreateToken(jwt.MapClaims{
"email": email,
"companyName": companyname,
"companyUserID": userCompanyMapping.CompanyUserID,
"exp": time.Now().Unix() + 3600,
})
json := AuthResponse{200, tokenString, companyUser}
c.Data["json"] = &json
c.ServeJSON()
} }

View File

@ -1,6 +1,8 @@
package controllers package controllers
import ( import (
"fmt"
"github.com/astaxie/beego" "github.com/astaxie/beego"
) )
@ -39,6 +41,15 @@ func (c *BaseController) ServeJSONErrorWithCode(errorcode int, message string) {
c.ServeJSON() c.ServeJSON()
} }
// ServeJSONErrorWithError respond with a JSON error and print an error message
func (c *BaseController) ServeJSONErrorWithError(message string, err error) {
message = fmt.Sprintf("%s %s", message, err.Error())
json := JSONBasicResponse{JSONError, message}
c.Data["json"] = &json
///c.Ctx.ResponseWriter.WriteHeader(400)
c.ServeJSON()
}
// ServeJSONSuccess respond with a JSON success message // ServeJSONSuccess respond with a JSON success message
func (c *BaseController) ServeJSONSuccess(message string) { func (c *BaseController) ServeJSONSuccess(message string) {
json := JSONBasicResponse{JSONSuccess, message} json := JSONBasicResponse{JSONSuccess, message}

View File

@ -11,7 +11,7 @@ import (
) )
type UserCompanyMap struct { type UserCompanyMap struct {
ID int `orm:"column(id);pk"` ID int `orm:"column(id)"` // removed pk here to fix postgres error
Email string `orm:"column(email)"` Email string `orm:"column(email)"`
PasswordHash string `orm:"column(password_hash)"` PasswordHash string `orm:"column(password_hash)"`
Company string `orm:"column(company)"` Company string `orm:"column(company)"`

View File

@ -68,8 +68,6 @@ func GetDatabaseWithName(companyName string) (*sql.DB, error) {
return db, nil return db, nil
} }
// TODO: call upper function in this one to reduce code
// GetDatabase Get orm and user information // GetDatabase Get orm and user information
func GetDatabase(tokenString string) (jwt.MapClaims, *sql.DB, error) { func GetDatabase(tokenString string) (jwt.MapClaims, *sql.DB, error) {
// validate token // validate token
@ -86,9 +84,7 @@ func GetDatabase(tokenString string) (jwt.MapClaims, *sql.DB, error) {
return tokenMap, dbs[companyName], nil return tokenMap, dbs[companyName], nil
} }
conStr := fmt.Sprintf("host=127.0.0.1 port=5435 user=postgres password=postgre dbname=%s sslmode=disable", companyName) db, err := GetDatabaseWithName(companyName)
fmt.Println(conStr)
db, err := sql.Open("postgres", conStr)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -97,36 +93,63 @@ func GetDatabase(tokenString string) (jwt.MapClaims, *sql.DB, error) {
return tokenMap, db, nil return tokenMap, db, nil
} }
// CreateDatabase Create a database by copying the template // HasDatabase Check if DB exists
func CreateDatabase(companyName string) { func HasDatabase(dbname string) bool {
/* systemDB := GetSystemDatabase()
if dbs[companyName] != nil { result, err := systemDB.Query("SELECT datname FROM pg_database WHERE datistemplate = false;")
fmt.Println("DB Already open")
return dbs[companyName], nil
}
/*
db, err = sql.Open("postgres", "host=127.0.0.1 port=5435 user=postgres password=postgre dbname=company5 sslmode=disable")
if err != nil { if err != nil {
log.Fatal(err) return false
} }
or, err := orm.NewOrmWithDB("postgres", "temp", db) for result.Next() {
*/ var aDbName string
result.Scan(&aDbName)
if aDbName == dbname {
return true
}
}
return false
}
// CreateDatabase Create a database by copying the template
func CreateDatabase(companyName string) (*sql.DB, error) {
if HasDatabase(companyName) {
return nil, errors.New("DB already exists")
}
systemDB := GetSystemDatabase()
// Takes about 1.2 seconds and we trust companyName to be sanitized in register
queryString := fmt.Sprintf("CREATE DATABASE %s TEMPLATE company_template;", companyName)
_, err := systemDB.Exec(queryString)
if err != nil {
return nil, err
}
db, err := GetDatabaseWithName(companyName)
if err != nil {
return nil, err
}
return db, nil
} }
// DeleteDatabase Delete an entire database, this is very very dangerous :-) // DeleteDatabase Delete an entire database, this is very very dangerous :-)
func DeleteDatabase(token string) { func DeleteDatabase(companyName string) error {
//_, db, err := GetDatabase(token) if !HasDatabase(companyName) {
/* return errors.New("DB does not exist")
remove from map! }
db.Close() systemDB := GetSystemDatabase()
fmt.Println("Closed company5")
//}
res, err := o.Raw("DROP DATABASE company5;").Exec() db, err := GetDatabaseWithName(companyName)
if err == nil { db.Close()
num, _ := res.RowsAffected() delete(dbs, companyName)
fmt.Println("mysql row affected number: ", num) fmt.Println("Closed %s", companyName)
queryString := fmt.Sprintf("DROP DATABASE %s;", companyName)
_, err = systemDB.Exec(queryString)
if err != nil {
return err
} }
*/ return nil
} }