HW12 completed
parent
acc97b1ac9
commit
73a669ab90
|
@ -3,6 +3,7 @@ package app
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/logger"
|
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/logger"
|
||||||
store "github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/storage"
|
store "github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/storage"
|
||||||
|
@ -40,7 +41,18 @@ func (a *App) Handler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func (a *App) LoggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
func (a *App) LoggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
a.Logger.Infof("receive %s request from IP %s", r.Method, r.RemoteAddr)
|
start := time.Now()
|
||||||
|
defer func() {
|
||||||
|
var path, useragent string
|
||||||
|
if r.URL != nil {
|
||||||
|
path = r.URL.Path
|
||||||
|
}
|
||||||
|
if len(r.UserAgent()) > 0 {
|
||||||
|
useragent = r.UserAgent()
|
||||||
|
}
|
||||||
|
latency := time.Since(start)
|
||||||
|
a.Logger.Infof("receive %s request from IP: %s on path: %s, duration: %s useragent: %s ", r.Method, r.RemoteAddr, path, latency, useragent)
|
||||||
|
}()
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,11 +66,6 @@ func (l *Logger) Fatalf(format string, args ...interface{}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func validLevel(level string) bool {
|
func validLevel(level string) bool {
|
||||||
l := []string{"debug", "info", "warn", "error", "fatal"}
|
var l = map[string]int{"debug": 1, "info": 1, "warn": 1, "error": 1, "fatal": 1}
|
||||||
for _, v := range l {
|
return l[strings.ToLower(level)] == 1
|
||||||
if strings.ToLower(level) == v {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
@ -11,13 +10,10 @@ import (
|
||||||
type Server struct {
|
type Server struct {
|
||||||
server *http.Server
|
server *http.Server
|
||||||
app app.App
|
app app.App
|
||||||
ctx context.Context
|
|
||||||
cancel context.CancelFunc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(app *app.App, address string, port string) *Server {
|
func NewServer(app *app.App, address string, port string) *Server {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
return &Server{server: &http.Server{Addr: net.JoinHostPort(address, port), Handler: app.LoggingMiddleware(app.Handler)}, app: *app}
|
||||||
return &Server{server: &http.Server{Addr: net.JoinHostPort(address, port), Handler: app.LoggingMiddleware(app.Handler)}, app: *app, ctx: ctx, cancel: cancel}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Start() error {
|
func (s *Server) Start() error {
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
package event
|
package event
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type Event struct {
|
type Event struct {
|
||||||
Title string
|
Title string
|
||||||
Date string
|
Date time.Time
|
||||||
|
Latency time.Duration
|
||||||
|
Note string
|
||||||
|
UserID int64
|
||||||
|
NotifyTime time.Duration
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package memorystorage
|
package memory
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
|
@ -0,0 +1,60 @@
|
||||||
|
package memory
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/storage/event"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const dateTimeLayout = "2006-01-02 15:04:00 -0700"
|
||||||
|
|
||||||
|
func TestMemoryStorage(t *testing.T) {
|
||||||
|
s := New()
|
||||||
|
dateParced1, _ := time.Parse(dateTimeLayout, "11.11.1111")
|
||||||
|
dateParced2, _ := time.Parse(dateTimeLayout, "22.11.22222")
|
||||||
|
|
||||||
|
t.Run("Empty storage", func(t *testing.T) {
|
||||||
|
require.Equal(t, 0, len(s.Events))
|
||||||
|
})
|
||||||
|
id, err := s.Create(event.Event{Title: "event1", Date: dateParced1})
|
||||||
|
|
||||||
|
t.Run("Create events", func(t *testing.T) {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(s.Events))
|
||||||
|
require.Equal(t, event.Event{Title: "event1", Date: dateParced1}, s.Events[id])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Update event", func(t *testing.T) {
|
||||||
|
err := s.Update(id, event.Event{Title: "event1_modifyed", Date: dateParced2})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(s.Events))
|
||||||
|
require.Equal(t, event.Event{Title: "event1_modifyed", Date: dateParced2}, s.Events[id])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("List event", func(t *testing.T) {
|
||||||
|
res, err := s.List()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(res))
|
||||||
|
require.Equal(t, event.Event{Title: "event1_modifyed", Date: dateParced2}, res[id])
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get event by ID", func(t *testing.T) {
|
||||||
|
res, ok := s.GetByID(id)
|
||||||
|
require.Equal(t, ok, true)
|
||||||
|
require.Equal(t, event.Event{Title: "event1_modifyed", Date: dateParced2}, res)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Get event by fake ID", func(t *testing.T) {
|
||||||
|
res, ok := s.GetByID(53663)
|
||||||
|
require.Equal(t, ok, false)
|
||||||
|
require.Equal(t, event.Event{}, res)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Delete event", func(t *testing.T) {
|
||||||
|
err := s.Delete(id)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 0, len(s.Events))
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -1,56 +0,0 @@
|
||||||
package memorystorage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/storage/event"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMemoryStorage(t *testing.T) {
|
|
||||||
s := New()
|
|
||||||
|
|
||||||
t.Run("Empty storage", func(t *testing.T) {
|
|
||||||
require.Equal(t,0, len(s.Events))
|
|
||||||
})
|
|
||||||
|
|
||||||
id,err:=s.Create(event.Event{ Title:"event1",Date:"11.11.1111" })
|
|
||||||
|
|
||||||
t.Run("Create events", func(t *testing.T) {
|
|
||||||
require.NoError(t,err)
|
|
||||||
require.Equal(t,1, len(s.Events))
|
|
||||||
require.Equal(t,event.Event{ Title:"event1",Date:"11.11.1111" }, s.Events[id])
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Update event", func(t *testing.T) {
|
|
||||||
err:=s.Update(id,event.Event{ Title:"event1_modifyed",Date:"22.11.22222" })
|
|
||||||
require.NoError(t,err)
|
|
||||||
require.Equal(t,1, len(s.Events))
|
|
||||||
require.Equal(t,event.Event{ Title:"event1_modifyed",Date:"22.11.22222" }, s.Events[id])
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("List event", func(t *testing.T) {
|
|
||||||
res,err:=s.List()
|
|
||||||
require.NoError(t,err)
|
|
||||||
require.Equal(t,1, len(res))
|
|
||||||
require.Equal(t,event.Event{ Title:"event1_modifyed",Date:"22.11.22222" }, res[id])
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Get event by ID", func(t *testing.T) {
|
|
||||||
res,ok := s.GetByID(id)
|
|
||||||
require.Equal(t,ok,true)
|
|
||||||
require.Equal(t,event.Event{ Title:"event1_modifyed",Date:"22.11.22222" }, res)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Get event by fake ID", func(t *testing.T) {
|
|
||||||
res,ok := s.GetByID(53663)
|
|
||||||
require.Equal(t,ok,false)
|
|
||||||
require.Equal(t,event.Event{}, res)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("Delete event", func(t *testing.T) {
|
|
||||||
err := s.Delete(id)
|
|
||||||
require.NoError(t,err)
|
|
||||||
require.Equal(t,0, len(s.Events))
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,11 +1,14 @@
|
||||||
package sqlstorage
|
package sql
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/storage/event"
|
"github.com/tiburon-777/HW_OTUS/hw12_13_14_15_calendar/internal/storage/event"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const dateTimeLayout = "2006-01-02 15:04:00 -0700"
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
User string
|
User string
|
||||||
Pass string
|
Pass string
|
||||||
|
@ -37,9 +40,15 @@ func (s *Storage) Close() error {
|
||||||
|
|
||||||
func (s *Storage) Create(event event.Event) (int64, error) {
|
func (s *Storage) Create(event event.Event) (int64, error) {
|
||||||
res, err := s.db.Exec(
|
res, err := s.db.Exec(
|
||||||
`INSERT INTO events (title, date) VALUES ($1, $2)`,
|
`INSERT INTO events
|
||||||
|
(title, date, latency, note, userID, notifyTime) VALUES
|
||||||
|
($1, $2, $3, $4, $5, $6)`,
|
||||||
event.Title,
|
event.Title,
|
||||||
event.Date,
|
event.Date.Format(dateTimeLayout),
|
||||||
|
event.Latency,
|
||||||
|
event.Note,
|
||||||
|
event.UserID,
|
||||||
|
event.NotifyTime,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
|
@ -49,9 +58,15 @@ func (s *Storage) Create(event event.Event) (int64, error) {
|
||||||
|
|
||||||
func (s *Storage) Update(id int64, event event.Event) error {
|
func (s *Storage) Update(id int64, event event.Event) error {
|
||||||
_, err := s.db.Exec(
|
_, err := s.db.Exec(
|
||||||
`UPDATE events set title=$1, date=$2 where id=$3`,
|
`UPDATE events set
|
||||||
|
title=$1, date=$2, latency=$3, note=$4, userID=$5, notifyTime=$6
|
||||||
|
where id=$7`,
|
||||||
event.Title,
|
event.Title,
|
||||||
event.Date,
|
event.Date.Format(dateTimeLayout),
|
||||||
|
event.Latency,
|
||||||
|
event.Note,
|
||||||
|
event.UserID,
|
||||||
|
event.NotifyTime,
|
||||||
id,
|
id,
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
|
@ -68,32 +83,43 @@ func (s *Storage) Delete(id int64) error {
|
||||||
func (s *Storage) List() (map[int64]event.Event, error) {
|
func (s *Storage) List() (map[int64]event.Event, error) {
|
||||||
res := make(map[int64]event.Event)
|
res := make(map[int64]event.Event)
|
||||||
results, err := s.db.Query(
|
results, err := s.db.Query(
|
||||||
`SELECT (id,title,date) from events ORDER BY id`)
|
`SELECT (id,title,date,latency,note,userID,notifyTime) from events ORDER BY id`)
|
||||||
if err != nil || results.Err() != nil {
|
if err != nil {
|
||||||
return res, err
|
return map[int64]event.Event{}, err
|
||||||
}
|
}
|
||||||
defer results.Close()
|
defer results.Close()
|
||||||
for results.Next() {
|
for results.Next() {
|
||||||
var tmp struct {
|
var id int64
|
||||||
id int64
|
var evt event.Event
|
||||||
title string
|
var dateRaw string
|
||||||
date string
|
err = results.Scan(&id, &evt.Title, &dateRaw, &evt.Latency, &evt.Note, &evt.UserID, &evt.NotifyTime)
|
||||||
}
|
|
||||||
err = results.Scan(&tmp.id, &tmp.title, &tmp.date)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, err
|
return map[int64]event.Event{}, err
|
||||||
}
|
}
|
||||||
res[tmp.id] = event.Event{Title: tmp.title, Date: tmp.date}
|
evt.Date, err = time.Parse(dateTimeLayout, dateRaw)
|
||||||
|
if err != nil {
|
||||||
|
return map[int64]event.Event{}, err
|
||||||
|
}
|
||||||
|
res[id] = evt
|
||||||
|
}
|
||||||
|
if results.Err() != nil {
|
||||||
|
return map[int64]event.Event{}, results.Err()
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Storage) GetByID(id int64) (event.Event, bool) {
|
func (s *Storage) GetByID(id int64) (event.Event, bool) {
|
||||||
var res event.Event
|
var res event.Event
|
||||||
|
var dateRaw string
|
||||||
err := s.db.QueryRow(
|
err := s.db.QueryRow(
|
||||||
`SELECT (title,date) from events where id=$1`, id).Scan(res.Title, res.Date)
|
`SELECT (id,title,date,latency,note,userID,notifyTime) from events where id=$1`, id).Scan(res.Title, dateRaw, res.Latency, res.Note, res.UserID, res.NotifyTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, false
|
return res, false
|
||||||
}
|
}
|
||||||
|
dateParced, err := time.Parse(dateTimeLayout, dateRaw)
|
||||||
|
if err != nil {
|
||||||
|
return res, false
|
||||||
|
}
|
||||||
|
res.Date = dateParced
|
||||||
return res, true
|
return res, true
|
||||||
}
|
}
|
|
@ -3,7 +3,11 @@
|
||||||
CREATE TABLE events (
|
CREATE TABLE events (
|
||||||
id int(16) NOT NULL AUTO_INCREMENT,
|
id int(16) NOT NULL AUTO_INCREMENT,
|
||||||
title varchar(255) NOT NULL,
|
title varchar(255) NOT NULL,
|
||||||
date varchar(255) NOT NULL,
|
date datetime NOT NULL,
|
||||||
|
latency int(16) NOT NULL,
|
||||||
|
note text,
|
||||||
|
userID int(16),
|
||||||
|
notifyTime int(16)
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;;
|
||||||
-- +goose StatementEnd
|
-- +goose StatementEnd
|
||||||
|
|
Loading…
Reference in New Issue