Skip to content

Commit

Permalink
Issue-75, handlers and service layers created, bugs fixed, new SQL sc…
Browse files Browse the repository at this point in the history
…ripts created

`signup_handlers.go`: handlers layer, handle errors function declared
`models.go`: added struct `SignupRepository`, corrected mistakes (`ID` type string -> int),
db tags added, columns `UpdatedAt`, `CreatedAt`, `GeneratedAt` were changed from type string to type time.Time
`type.go`: db tags added, columns `UpdatedAt`, `CreatedAt` were changed from type string to type time.Time
`router.go`: inits routers
`credentials_repository.go`: updated
`signup_repository.go`: updated, modified with TextArray, `InsertUser` was moved from `signup_repository.go` into `users_repository.go`
`users_repository.go`: updated, `InsertUser` was moved from `signup_repository.go` into `users_repository.go`
`000005_re-creation_role.down.sql`: fixed bugs
`000005_re-creation_role.up.sql`: fixed bugs
`000006_change_id.up.sql`: drops unique `mobile_phone` constraint, `id` type in tables `credentials` and `email_verification_tokens` changed into integer
`000006_change_id.down.sql`: rolls back
`service.go`: service layer, added transactions
`data.go`: validates user's entered data
`email.go`: validates user's entered email
`errors.go`: contains validation errors
`ims-api.yaml`: updated
  • Loading branch information
DubBro authored and taaraora committed Jun 4, 2020
1 parent 163a825 commit dd58889
Show file tree
Hide file tree
Showing 18 changed files with 583 additions and 107 deletions.
13 changes: 9 additions & 4 deletions api/ims/ims-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ info:
paths:
/signup:
post:
description: This endpoint handles user registartion requests, sent from sign-up form
operationId: signUp
description: This endpoint handles user registration requests, sent from sign-up form
operationId: SignUp
requestBody:
content:
application/json:
Expand Down Expand Up @@ -70,7 +70,7 @@ paths:
/email/available:
get:
description: This endpoint compares user's entered email with existing emails and displays an error if there is the same in DB
operationId: emailAvailable
operationId: EmailAvailable
parameters:
- in: query
name: email
Expand All @@ -90,7 +90,7 @@ paths:
/users/emailVerificationToken/verify:
get:
description: To complete the registration you need to confirm your email with token
operationId: emailVerificationToken
operationId: EmailVerificationToken
parameters:
- in: query
name: token
Expand Down Expand Up @@ -275,17 +275,22 @@ components:
firstName:
type: string
maxLength: 255
minLength: 1
description: User's first name
lastName:
type: string
maxLength: 255
minLength: 1
description: User's last name
email:
type: string
maxLength: 255
format: email
description: User's email
password:
type: string
maxLength: 255
minLength: 1
format: password
description: User's password
required:
Expand Down
3 changes: 2 additions & 1 deletion cmd/ims/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

package main

import "fmt"

func main() {
fmt.Println("I'm identity management service")
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ require (
github.com/sirupsen/logrus v1.5.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.7.0
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904 // indirect
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904
gopkg.in/yaml.v2 v2.2.8
)
139 changes: 139 additions & 0 deletions pkg/ims/api/handlers/signup_handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package handlers

import (
"fmt"
"github.com/sirupsen/logrus"

"encoding/json"
"errors"
"io/ioutil"
"net/http"

"github.com/gorilla/mux"

"github.com/omc-college/management-system/pkg/ims/validation"
"github.com/omc-college/management-system/pkg/ims/models"
"github.com/omc-college/management-system/pkg/ims/repository/postgresql"
"github.com/omc-college/management-system/pkg/ims/service"
)

type SignUpHandler struct {
SignUpService *service.SignUpService
}

func NewSignUpHandler(service *service.SignUpService) *SignUpHandler {
return &SignUpHandler{
SignUpService: service,
}
}

// handleError handles existing error in handlers
func handleError(err error, w http.ResponseWriter) {
var error models.Error
var queryErr *postgresql.QueryError
var scanErr *postgresql.ScanError

if errors.As(err, &queryErr) {
error = models.Error{http.StatusInternalServerError, queryErr.Message}
} else if errors.As(err, &scanErr) {
error = models.Error{http.StatusInternalServerError, scanErr.Message}
} else if errors.Is(err, validation.ErrNoSymbols) || errors.Is(err, validation.ErrToMuchSymbols) {
error = models.Error{http.StatusBadRequest, err.Error()}
} else if errors.Is(err, validation.ErrEmailExists) || errors.Is(err, validation.ErrInvalidEmail){
error = models.Error{http.StatusBadRequest, err.Error()}
} else {
error = models.Error{http.StatusInternalServerError, err.Error()}
}

logrus.Errorf(error.Message)
w.WriteHeader(error.Code)
json.NewEncoder(w).Encode(error)
}

func (h *SignUpHandler)SignUp(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")

var request models.SignupRequest
var err error

body, err := ioutil.ReadAll(r.Body)
if err != nil {
handleError(err, w)
return
}

err = json.Unmarshal(body, &request)
if err != nil {
handleError(err, w)
return
}

err = r.Body.Close()
if err != nil {
handleError(err, w)
return
}

err = validation.Data(&request)
if err != nil {
handleError(err, w)
return
}

err = h.SignUpService.SignUp(&request)
if err != nil {
handleError(err, w)
return
}

}

func (h *SignUpHandler)EmailAvailable(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")

var err error

params := mux.Vars(r)

if params["email"] == "" {
err = validation.ErrNoSymbols
handleError(err, w)
return
}

result, err := h.SignUpService.EmailAvailable(params["email"])
if err != nil {
handleError(err, w)
return
} else if result == true {
err = validation.ErrEmailExists
handleError(err, w)
return
} else {
fmt.Fprintf(w, "email is not occupied")
}
}

func (h *SignUpHandler) CheckEmailVerificationToken(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")

var tok models.EmailVerificationTokens
var err error

params := mux.Vars(r)

if params["verification_token"] == "" {
err = validation.ErrNoSymbols
handleError(err, w)
return
}

tok.VerificationToken = params["verification_token"]

err = h.SignUpService.EmailVerificationToken(&tok)
if err != nil {
handleError(err, w)
return
}

}
24 changes: 24 additions & 0 deletions pkg/ims/api/routers/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package routers

import (
"net/http"

"github.com/gorilla/mux"

"github.com/omc-college/management-system/pkg/ims/service"
"github.com/omc-college/management-system/pkg/ims/api/handlers"
)

//NewSignUpRouter inits Sign Up router
func NewSignUpRouter (service *service.SignUpService) *mux.Router {

signUpHandler := handlers.NewSignUpHandler(service)

router := mux.NewRouter()

router.HandleFunc("/signup", signUpHandler.SignUp).Methods(http.MethodPost)
router.HandleFunc("/email/available/{email}", signUpHandler.EmailAvailable).Methods(http.MethodGet)
router.HandleFunc("/users/emailVerificationToken/verify/{verification_token}", signUpHandler.CheckEmailVerificationToken).Methods(http.MethodGet)

return router
}
43 changes: 26 additions & 17 deletions pkg/ims/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ package models

import (
"github.com/dgrijalva/jwt-go"
"time"
)

type Users struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
MobilePhone string `json:"mobile_phone"`
CreatedAt string `json:"created_at"`
ModifiedAt string `json:"modified_at"`
Roles []string `json:"roles"`
Verified bool `json:"verified"`
type User struct {
ID int `json:"id" db:"id"`
FirstName string `json:"first_name" db:"first_name"`
LastName string `json:"last_name" db:"last_name"`
Email string `json:"email" db:"email"`
MobilePhone string `json:"mobile_phone" db:"mobile_phone"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
ModifiedAt time.Time `json:"modified_at" db:"modified_at"`
Roles []string `json:"roles" db:"roles"`
Verified bool `json:"verified" db:"verified"`
}

type Claims struct {
Expand All @@ -24,19 +25,27 @@ type Claims struct {
}

type Credentials struct {
ID string `json:"id"`
PasswordHash string `json:"password_hash"`
Salt string `json:"salt"`
UpdatedAt string `json:"updated_at"`
ID int `json:"id" db:"id"`
PasswordHash string `json:"password_hash" db:"password_hash"`
Salt string `json:"salt" db:"salt"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}

type EmailVerificationTokens struct {
ID string `json:"id"`
VerificationToken string `json:"verification_token"`
GeneretedAt string `json:"generated_at"`
ID int `json:"id" db:"id"`
VerificationToken string `json:"verification_token" db:"verification_token"`
GeneretedAt string `json:"generated_at" db:"generated_at"`
}

type Error struct {
Code int `json:"code"`
Message string `json:"message"`
}

type SignupRequest struct {
FirstName string `json:"first_name" db:"first_name"`
LastName string `json:"last_name" db:"last_name"`
Email string `json:"email" db:"email"`
Password string `json:"password" db:"password"`
}

28 changes: 14 additions & 14 deletions pkg/ims/repository/postgresql/credentials_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,13 @@ import (
)

type CredRepository struct {
db *sqlx.DB
db sqlx.Ext
}

func NewCredentialsRepository(dbConnURL string) (*CredRepository, error) {
db, err := sqlx.Connect("pgx", dbConnURL)
if err != nil {
return nil, err
}
err = db.Ping()
if err != nil {
return nil, err
}
func NewCredentialsRepository(db sqlx.Ext) *CredRepository {
return &CredRepository{
db: db,
}, nil
}
}

//UpdateCredentials
Expand All @@ -35,22 +27,30 @@ func (cr *CredRepository) UpdateCredentials(c *models.Credentials) error {
}

func (cr *CredRepository) GetCredentialByUserID(usersId string) (*models.Credentials, error) {

c := &models.Credentials{}
err := cr.db.Get(&c, "SELECT * FROM credentials WHERE id=$1", usersId)

result, err := cr.db.Query("SELECT * FROM credentials WHERE id=$1", usersId)
if err != nil {
return nil, err
}

for result.Next() {
err = result.Scan(&c.ID, &c.PasswordHash, &c.Salt, &c.UpdatedAt)
if err != nil {
return nil, err
}
}

return c, nil
}

//InsertCredentials inserts user's credentials into DB
func (cr *CredRepository) InsertCredentials(c *models.Credentials) error {
_, err := cr.db.Exec("INSERT INTO credentials(id, password_hash, salt, updated_at) VALUES($1, $2, $3, CURRENT_TIMESTAMP)", c.ID, c.PasswordHash, c.Salt)
if err != nil {
return err
return QueryError{queryErrorMessage, err}
}

return nil
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BEGIN;

ALTER TABLE users
DROP COLUMN IF EXISTS roles,
DROP COLUMN IF EXISTS roles;

COMMIT;
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ ALTER TABLE users
DROP COLUMN role;

ALTER TABLE users
ADD COLUMN roles []text;

ADD COLUMN roles text[];

COMMIT;
16 changes: 16 additions & 0 deletions pkg/ims/repository/postgresql/migrations/000006_change_id.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
BEGIN;

SELECT MAX(id)+1 FROM credentials;
CREATE SEQUENCE cred_id_seq MINVALUE 1;
ALTER TABLE credentials ALTER id SET DEFAULT nextval('cred_id_seq');
ALTER SEQUENCE cred_id_seq OWNED BY credentials.id;

SELECT MAX(id)+1 FROM email_verification_tokens;
CREATE SEQUENCE token_id_seq MINVALUE 1;
ALTER TABLE email_verification_tokens ALTER id SET DEFAULT nextval('token_id_seq');
ALTER SEQUENCE token_id_seq OWNED BY email_verification_tokens.id;

UPDATE users SET mobile_phone = NULL WHERE mobile_phone = '';
CREATE UNIQUE INDEX mobile_phone ON users (mobile_phone);

COMMIT;
Loading

0 comments on commit dd58889

Please sign in to comment.