Skip to content

Commit

Permalink
add postman collection for test project
Browse files Browse the repository at this point in the history
  • Loading branch information
nvcnvn committed Jun 29, 2020
1 parent 279096d commit 3efab0e
Show file tree
Hide file tree
Showing 9 changed files with 439 additions and 0 deletions.
21 changes: 21 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- users definition

CREATE TABLE users (
id TEXT NOT NULL,
password TEXT NOT NULL,
max_todo INTEGER DEFAULT 5 NOT NULL,
CONSTRAINT users_PK PRIMARY KEY (id)
);

INSERT INTO users (id, password, max_todo) VALUES('firstUser', 'example', 5);

-- tasks definition

CREATE TABLE tasks (
id TEXT NOT NULL,
content TEXT NOT NULL,
user_id TEXT NOT NULL,
created_date TEXT NOT NULL,
CONSTRAINT tasks_PK PRIMARY KEY (id),
CONSTRAINT tasks_FK FOREIGN KEY (user_id) REFERENCES users(id)
);
Binary file added data.db
Binary file not shown.
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module github.com/manabie-com/togo

go 1.14

require (
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/google/uuid v1.1.1
github.com/mattn/go-sqlite3 v1.14.0
)
16 changes: 16 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/dgrijalva/jwt-go v1.0.2 h1:KPldsxuKGsS2FPWsNeg9ZO18aCrGKujPoWXn2yo+KQM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
178 changes: 178 additions & 0 deletions internal/services/tasks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package services

import (
"context"
"database/sql"
"encoding/json"
"log"
"net/http"
"time"

jwt "github.com/dgrijalva/jwt-go"
"github.com/google/uuid"
"github.com/manabie-com/togo/internal/storages"
sqllite "github.com/manabie-com/togo/internal/storages/sqlite"
)

// ToDoService implement HTTP server
type ToDoService struct {
JWTKey string
Store *sqllite.LiteDB
}

func (s *ToDoService) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
log.Println(req.Method, req.URL.Path)
switch req.URL.Path {
case "/login":
s.getAuthToken(resp, req)
return
case "/tasks":
var ok bool
req, ok = s.validToken(req)
if !ok {
resp.WriteHeader(http.StatusUnauthorized)
return
}

switch req.Method {
case http.MethodGet:
s.listTasks(resp, req)
case http.MethodPost:
s.addTask(resp, req)
}
return
}
}

func (s *ToDoService) getAuthToken(resp http.ResponseWriter, req *http.Request) {
id := value(req, "user_id")
if !s.Store.ValidateUser(req.Context(), id, value(req, "password")) {
resp.WriteHeader(http.StatusUnauthorized)
json.NewEncoder(resp).Encode(map[string]string{
"error": "incorrect user_id/pwd",
})
return
}
resp.Header().Set("Content-Type", "application/json")

token, err := s.createToken(id.String)
if err != nil {
resp.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(resp).Encode(map[string]string{
"error": err.Error(),
})
return
}

json.NewEncoder(resp).Encode(map[string]string{
"data": token,
})
}

func (s *ToDoService) listTasks(resp http.ResponseWriter, req *http.Request) {
id, _ := userIDFromCtx(req.Context())
tasks, err := s.Store.RetrieveTasks(
req.Context(),
sql.NullString{
String: id,
Valid: true,
},
value(req, "created_date"),
)

resp.Header().Set("Content-Type", "application/json")

if err != nil {
resp.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(resp).Encode(map[string]string{
"error": err.Error(),
})
return
}

json.NewEncoder(resp).Encode(map[string][]*storages.Task{
"data": tasks,
})
}

func (s *ToDoService) addTask(resp http.ResponseWriter, req *http.Request) {
t := &storages.Task{}
err := json.NewDecoder(req.Body).Decode(t)
defer req.Body.Close()
if err != nil {
resp.WriteHeader(http.StatusInternalServerError)
return
}

now := time.Now()
userID, _ := userIDFromCtx(req.Context())
t.ID = uuid.New().String()
t.UserID = userID
t.CreatedDate = now.Format("2006-01-02")

resp.Header().Set("Content-Type", "application/json")

err = s.Store.AddTask(req.Context(), t)
if err != nil {
resp.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(resp).Encode(map[string]string{
"error": err.Error(),
})
return
}

json.NewEncoder(resp).Encode(map[string]*storages.Task{
"data": t,
})
}

func value(req *http.Request, p string) sql.NullString {
return sql.NullString{
String: req.FormValue(p),
Valid: true,
}
}

func (s *ToDoService) createToken(id string) (string, error) {
atClaims := jwt.MapClaims{}
atClaims["user_id"] = id
atClaims["exp"] = time.Now().Add(time.Minute * 15).Unix()
at := jwt.NewWithClaims(jwt.SigningMethodHS256, atClaims)
token, err := at.SignedString([]byte(s.JWTKey))
if err != nil {
return "", err
}
return token, nil
}

func (s *ToDoService) validToken(req *http.Request) (*http.Request, bool) {
token := req.Header.Get("Authorization")
claims := make(jwt.MapClaims)
t, err := jwt.ParseWithClaims(token, claims, func(*jwt.Token) (interface{}, error) {
return []byte(s.JWTKey), nil
})
if err != nil {
log.Println(err)
return req, false
}

if !t.Valid {
return req, false
}

id, ok := claims["user_id"].(string)
if !ok {
return req, false
}

req = req.WithContext(context.WithValue(req.Context(), userAuthKey(0), id))
return req, true
}

type userAuthKey int8

func userIDFromCtx(ctx context.Context) (string, bool) {
v := ctx.Value(userAuthKey(0))
id, ok := v.(string)
return id, ok
}
15 changes: 15 additions & 0 deletions internal/storages/entities.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package storages

// Task reflects tasks in DB
type Task struct {
ID string `json:"id"`
Content string `json:"content"`
UserID string `json:"user_id"`
CreatedDate string `json:"created_date"`
}

// User reflects users data from DB
type User struct {
ID string
Password string
}
63 changes: 63 additions & 0 deletions internal/storages/sqlite/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package sqllite

import (
"context"
"database/sql"

"github.com/manabie-com/togo/internal/storages"
)

// LiteDB for working with sqllite
type LiteDB struct {
DB *sql.DB
}

// RetrieveTasks returns tasks if match userID AND createDate.
func (l *LiteDB) RetrieveTasks(ctx context.Context, userID, createdDate sql.NullString) ([]*storages.Task, error) {
stmt := `SELECT id, content, user_id, created_date FROM tasks WHERE user_id = ? AND created_date = ?`
rows, err := l.DB.QueryContext(ctx, stmt, userID, createdDate)
if err != nil {
return nil, err
}
defer rows.Close()

var tasks []*storages.Task
for rows.Next() {
t := &storages.Task{}
err := rows.Scan(&t.ID, &t.Content, &t.UserID, &t.CreatedDate)
if err != nil {
return nil, err
}
tasks = append(tasks, t)
}

if err := rows.Err(); err != nil {
return nil, err
}

return tasks, nil
}

// AddTask adds a new task to DB
func (l *LiteDB) AddTask(ctx context.Context, t *storages.Task) error {
stmt := `INSERT INTO tasks (id, content, user_id, created_date) VALUES (?, ?, ?, ?)`
_, err := l.DB.ExecContext(ctx, stmt, &t.ID, &t.Content, &t.UserID, &t.CreatedDate)
if err != nil {
return err
}

return nil
}

// ValidateUser returns tasks if match userID AND password
func (l *LiteDB) ValidateUser(ctx context.Context, userID, pwd sql.NullString) bool {
stmt := `SELECT id FROM users WHERE id = ? AND password = ?`
row := l.DB.QueryRowContext(ctx, stmt, userID, pwd)
u := &storages.User{}
err := row.Scan(&u.ID)
if err != nil {
return false
}

return true
}
26 changes: 26 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"database/sql"
"log"
"net/http"

"github.com/manabie-com/togo/internal/services"
sqllite "github.com/manabie-com/togo/internal/storages/sqlite"

_ "github.com/mattn/go-sqlite3"
)

func main() {
db, err := sql.Open("sqlite3", "./data.db")
if err != nil {
log.Fatal("error opening db", err)
}

http.ListenAndServe(":5050", &services.ToDoService{
JWTKey: "wqGyEBBfPK9w3Lxw",
Store: &sqllite.LiteDB{
DB: db,
},
})
}
Loading

0 comments on commit 3efab0e

Please sign in to comment.