create ticket
This commit is contained in:
parent
6dfcd7bbed
commit
7ab03b279c
22
app/app.go
22
app/app.go
@ -1,14 +1,16 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bitbucket.org/BlackBroker/heruvym/dal"
|
||||||
|
"bitbucket.org/BlackBroker/heruvym/middleware"
|
||||||
|
"bitbucket.org/BlackBroker/heruvym/service"
|
||||||
"bitbucket.org/BlackBroker/heruvym/version"
|
"bitbucket.org/BlackBroker/heruvym/version"
|
||||||
"github.com/skeris/authService/router"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/BlackBroker/trashlog/wrappers/zaptg"
|
"github.com/BlackBroker/trashlog/wrappers/zaptg"
|
||||||
"github.com/skeris/appInit"
|
"github.com/skeris/appInit"
|
||||||
"github.com/skeris/authService/http_middleware"
|
"github.com/skeris/authService/router"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@ -112,13 +114,25 @@ func New(ctx context.Context, opts interface{}) (appInit.CommonApp, error) {
|
|||||||
logger := hlog.New(zapLogger)
|
logger := hlog.New(zapLogger)
|
||||||
logger.Emit(InfoSvcStarted{})
|
logger.Emit(InfoSvcStarted{})
|
||||||
|
|
||||||
apiMux := router.NewRouter(http.DefaultServeMux)
|
apiMux := router.NewRouter(http.NewServeMux())
|
||||||
|
|
||||||
|
database, err := dal.New(
|
||||||
|
ctx,
|
||||||
|
options.MongoURI,
|
||||||
|
"support",
|
||||||
|
logger,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
heruvym := service.New(database, logger)
|
||||||
|
|
||||||
interrupt := make(chan os.Signal, 1)
|
interrupt := make(chan os.Signal, 1)
|
||||||
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Handler: http_middleware.Wrap(apiMux, zapLogger),
|
Handler: http_middleware.Wrap(heruvym.Register(apiMux), zapLogger),
|
||||||
Addr: fmt.Sprintf(":%s", options.NumberPortLocal),
|
Addr: fmt.Sprintf(":%s", options.NumberPortLocal),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
58
dal/dal.go
58
dal/dal.go
@ -11,12 +11,15 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const collMessages = "messages"
|
const (
|
||||||
|
collMessages = "messages"
|
||||||
|
collTickets = "tickets"
|
||||||
|
)
|
||||||
|
|
||||||
type DAL struct {
|
type DAL struct {
|
||||||
logger hlog.Logger
|
logger hlog.Logger
|
||||||
col *mongo.Collection
|
colMsg, colTck *mongo.Collection
|
||||||
client *mongo.Client
|
client *mongo.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrorConnectToDB struct {
|
type ErrorConnectToDB struct {
|
||||||
@ -31,7 +34,7 @@ type ErrorPingDB struct {
|
|||||||
|
|
||||||
type InfoPing struct {
|
type InfoPing struct {
|
||||||
MongoURI string
|
MongoURI string
|
||||||
Nanoseconds int
|
Nanoseconds int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
@ -48,7 +51,7 @@ func New(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
before := time.Now().Nanosecond()
|
before := time.Now().Unix()
|
||||||
|
|
||||||
if err := client.Ping(ctx, readpref.PrimaryPreferred()); err != nil {
|
if err := client.Ping(ctx, readpref.PrimaryPreferred()); err != nil {
|
||||||
log.Emit(ErrorPingDB{
|
log.Emit(ErrorPingDB{
|
||||||
@ -61,32 +64,33 @@ func New(
|
|||||||
|
|
||||||
log.Emit(InfoPing{
|
log.Emit(InfoPing{
|
||||||
MongoURI: mongoURI,
|
MongoURI: mongoURI,
|
||||||
Nanoseconds: time.Now().Nanosecond() - before,
|
Nanoseconds: time.Now().Unix() - before,
|
||||||
})
|
})
|
||||||
|
|
||||||
return &DAL{
|
return &DAL{
|
||||||
client: client,
|
client: client,
|
||||||
col: client.Database(database).Collection(collMessages),
|
colMsg: client.Database(database).Collection(collMessages),
|
||||||
|
colTck: client.Database(database).Collection(collTickets),
|
||||||
logger: log.Module("DAL"),
|
logger: log.Module("DAL"),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ErrorInsert struct {
|
type ErrorInsert struct {
|
||||||
Err error
|
Err error
|
||||||
UserID, SessionID string
|
UserID, SessionID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DAL) PutMessage(
|
func (d *DAL) PutMessage(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
title, message, userID, sessionID string,
|
message, userID, sessionID, ticketID string,
|
||||||
files []string,
|
files []string,
|
||||||
) error {
|
) error {
|
||||||
|
|
||||||
if _, err := d.col.InsertOne(ctx, &model.Message{
|
if _, err := d.colMsg.InsertOne(ctx, &model.Message{
|
||||||
ID: xid.New().String(),
|
ID: xid.New().String(),
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
SessionID: sessionID,
|
SessionID: sessionID,
|
||||||
Title: title,
|
TicketID: ticketID,
|
||||||
Message: message,
|
Message: message,
|
||||||
Files: files,
|
Files: files,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
@ -102,3 +106,31 @@ func (d *DAL) PutMessage(
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *DAL) CreateTicket(
|
||||||
|
ctx context.Context,
|
||||||
|
userID,
|
||||||
|
sessionID,
|
||||||
|
title string,
|
||||||
|
) (string, error) {
|
||||||
|
|
||||||
|
tiketID := xid.New().String()
|
||||||
|
|
||||||
|
if _, err := d.colTck.InsertOne(ctx, &model.Ticket{
|
||||||
|
ID: tiketID,
|
||||||
|
UserID: userID,
|
||||||
|
SessionID: sessionID,
|
||||||
|
Title: title,
|
||||||
|
CreatedAt: time.Time{},
|
||||||
|
}); err != nil {
|
||||||
|
d.logger.Emit(ErrorInsert{
|
||||||
|
Err: err,
|
||||||
|
UserID: userID,
|
||||||
|
SessionID: sessionID,
|
||||||
|
})
|
||||||
|
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tiketID, nil
|
||||||
|
}
|
||||||
|
5
go.mod
5
go.mod
@ -3,12 +3,15 @@ module bitbucket.org/BlackBroker/heruvym
|
|||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
bitbucket.org/skeris/profile v0.0.0-20210410182208-cf9db6d1452d
|
bitbucket.org/skeris/profile v0.0.0-20210411000338-496c859828a5 // indirect
|
||||||
github.com/BlackBroker/trashlog v0.0.0-20210406151703-e2c4874359bf
|
github.com/BlackBroker/trashlog v0.0.0-20210406151703-e2c4874359bf
|
||||||
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/rs/xid v1.3.0
|
github.com/rs/xid v1.3.0
|
||||||
github.com/skeris/appInit v0.1.0
|
github.com/skeris/appInit v0.1.0
|
||||||
github.com/skeris/authService v1.1.1 // indirect
|
github.com/skeris/authService v1.1.1 // indirect
|
||||||
|
github.com/skeris/identity v0.0.7 // indirect
|
||||||
|
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33 // indirect
|
||||||
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf
|
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf
|
||||||
go.mongodb.org/mongo-driver v1.5.1
|
go.mongodb.org/mongo-driver v1.5.1
|
||||||
go.uber.org/zap v1.16.0
|
go.uber.org/zap v1.16.0
|
||||||
|
16
go.sum
16
go.sum
@ -1,5 +1,9 @@
|
|||||||
bitbucket.org/skeris/profile v0.0.0-20210410182208-cf9db6d1452d h1:WAp3CsNISnHvvbn60wYK2AbCYb/UxGk+6EkiTQFX7mw=
|
bitbucket.org/skeris/profile v0.0.0-20210410182208-cf9db6d1452d h1:WAp3CsNISnHvvbn60wYK2AbCYb/UxGk+6EkiTQFX7mw=
|
||||||
bitbucket.org/skeris/profile v0.0.0-20210410182208-cf9db6d1452d/go.mod h1:nFz19Zl7b9CNqFXWDdvJKrFS7S/th4dX3GnP5F0Yu5M=
|
bitbucket.org/skeris/profile v0.0.0-20210410182208-cf9db6d1452d/go.mod h1:nFz19Zl7b9CNqFXWDdvJKrFS7S/th4dX3GnP5F0Yu5M=
|
||||||
|
bitbucket.org/skeris/profile v0.0.0-20210410222825-ad4fbe380f68 h1:OquUpSs9fjMRMzRErW3a2o3FF9QbKjBzvveT4MPnsY0=
|
||||||
|
bitbucket.org/skeris/profile v0.0.0-20210410222825-ad4fbe380f68/go.mod h1:nFz19Zl7b9CNqFXWDdvJKrFS7S/th4dX3GnP5F0Yu5M=
|
||||||
|
bitbucket.org/skeris/profile v0.0.0-20210411000338-496c859828a5 h1:nAtrodBJM8auGMZB4IrLFmdM/VpDsXjycC+e53SFNJ0=
|
||||||
|
bitbucket.org/skeris/profile v0.0.0-20210411000338-496c859828a5/go.mod h1:nFz19Zl7b9CNqFXWDdvJKrFS7S/th4dX3GnP5F0Yu5M=
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||||
@ -62,6 +66,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
|
||||||
|
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
@ -187,6 +193,10 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|||||||
github.com/mailjet/mailjet-apiv3-go v0.0.0-20201009050126-c24bc15a9394/go.mod h1:ogN8Sxy3n5VKLhQxbtSBM3ICG/VgjXS/akQJIoDSrgA=
|
github.com/mailjet/mailjet-apiv3-go v0.0.0-20201009050126-c24bc15a9394/go.mod h1:ogN8Sxy3n5VKLhQxbtSBM3ICG/VgjXS/akQJIoDSrgA=
|
||||||
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
|
||||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||||
|
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||||
|
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
|
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||||
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
|
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
|
||||||
github.com/minio/minio-go/v7 v7.0.10/go.mod h1:td4gW1ldOsj1PbSNS+WYK43j+P1XVhX/8W8awaYlBFo=
|
github.com/minio/minio-go/v7 v7.0.10/go.mod h1:td4gW1ldOsj1PbSNS+WYK43j+P1XVhX/8W8awaYlBFo=
|
||||||
@ -248,8 +258,11 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
|||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33 h1:N9f/Q+2Ssa+yDcbfaoLTYvXmdeyUUxsJKdPUVsjSmiA=
|
||||||
|
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33/go.mod h1:rpcH99JknBh8seZmlOlUg51gasZH6QH34oXNsIwYT6E=
|
||||||
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf h1:TJJm6KcBssmbWzplF5lzixXl1RBAi/ViPs1GaSOkhwo=
|
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf h1:TJJm6KcBssmbWzplF5lzixXl1RBAi/ViPs1GaSOkhwo=
|
||||||
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf/go.mod h1:1FsorU3vnXO9xS9SrhUp8fRb/6H/Zfll0rPt1i4GWaA=
|
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf/go.mod h1:1FsorU3vnXO9xS9SrhUp8fRb/6H/Zfll0rPt1i4GWaA=
|
||||||
|
github.com/themakers/identity v0.0.0-20200703212242-9142bb6b35e1 h1:DuzLgIqC0AxW3Gy+Mhwn15R9KvFe8nifO6Pbe3j07Ng=
|
||||||
github.com/themakers/identity v0.0.0-20200703212242-9142bb6b35e1/go.mod h1:lHYuLs7VL+KVZpEzfXnrv8YwlGXcuZgUZjV5pSRb+Fc=
|
github.com/themakers/identity v0.0.0-20200703212242-9142bb6b35e1/go.mod h1:lHYuLs7VL+KVZpEzfXnrv8YwlGXcuZgUZjV5pSRb+Fc=
|
||||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
@ -398,6 +411,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@ -414,6 +428,8 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091 h1:DMyOG0U+gKfu8JZzg2UQe9MeaC1X+xQWlAKcRnjxjCw=
|
||||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b h1:ggRgirZABFolTmi3sn6Ivd9SipZwLedQ5wR0aAKnFxU=
|
||||||
|
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
119
jwt_adapter/jwt_adapter.go
Normal file
119
jwt_adapter/jwt_adapter.go
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
package jwt_adapter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
"github.com/rs/xid"
|
||||||
|
"github.com/skeris/identity/cookie"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ cookie.Cookie = new(JwtAdapter)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
aS := os.Getenv("JWT_SECRET")
|
||||||
|
if len(aS) != 0 {
|
||||||
|
accessSecret = aS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type JwtAdapter struct {
|
||||||
|
ID string
|
||||||
|
Session string
|
||||||
|
User string
|
||||||
|
|
||||||
|
Tariff uint8
|
||||||
|
|
||||||
|
Created int64
|
||||||
|
LastSeen int64
|
||||||
|
jwt.StandardClaims
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JwtAdapter) Init() {
|
||||||
|
if c.ID == "" {
|
||||||
|
c.ID = xid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Session = xid.New().String()
|
||||||
|
c.User = ""
|
||||||
|
c.Tariff = uint8(0)
|
||||||
|
|
||||||
|
t := Timestamp()
|
||||||
|
c.Created = t
|
||||||
|
c.LastSeen = t
|
||||||
|
}
|
||||||
|
|
||||||
|
func Get(ctx context.Context) *JwtAdapter {
|
||||||
|
if adapter, ok := ctx.Value(DefaultHeaderKey).(*JwtAdapter); ok {
|
||||||
|
return adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JwtAdapter) SetUserID(id string) {
|
||||||
|
c.User = id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JwtAdapter) GetUserID() string {
|
||||||
|
return c.User
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JwtAdapter) GetTariff() uint8 {
|
||||||
|
return c.Tariff
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JwtAdapter) SetTariff(status uint8) {
|
||||||
|
c.Tariff = status
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JwtAdapter) GetSessionID() string {
|
||||||
|
return c.Session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *JwtAdapter) SetSessionID(id string) {
|
||||||
|
c.Session = id
|
||||||
|
c.User = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultAccessSecret = "awesomeAC"
|
||||||
|
DefaultHeaderKey = "Authorization"
|
||||||
|
)
|
||||||
|
|
||||||
|
var accessSecret = DefaultAccessSecret
|
||||||
|
|
||||||
|
func (c *JwtAdapter) Encode() (string, error) {
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
|
||||||
|
ss, err := token.SignedString([]byte(accessSecret))
|
||||||
|
|
||||||
|
return ss, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func Decode(tokenString string) (*JwtAdapter, error) {
|
||||||
|
claims := JwtAdapter{}
|
||||||
|
|
||||||
|
token, err := jwt.ParseWithClaims(tokenString, &claims, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
//Make sure that the token method conform to "SigningMethodHMAC"
|
||||||
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||||
|
}
|
||||||
|
return []byte(accessSecret), nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := token.Claims.(jwt.Claims); !ok && !token.Valid {
|
||||||
|
return nil, fmt.Errorf("ErrorNoValidClaims")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Timestamp() int64 {
|
||||||
|
return time.Now().UnixNano() / int64(time.Millisecond)
|
||||||
|
}
|
66
middleware/hijack/response_writer.go
Normal file
66
middleware/hijack/response_writer.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package hijack
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
func New(w http.ResponseWriter, commit func(http.ResponseWriter)) (http.ResponseWriter, func()) {
|
||||||
|
responseWriter := &responseWriter{
|
||||||
|
commit: commit,
|
||||||
|
w: w,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := w.(http.Hijacker); ok {
|
||||||
|
return &responseWriterHijacker{
|
||||||
|
responseWriter: responseWriter,
|
||||||
|
}, responseWriter.ensureCommitted
|
||||||
|
} else {
|
||||||
|
return responseWriter, responseWriter.ensureCommitted
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ http.ResponseWriter = new(responseWriter)
|
||||||
|
var _ http.ResponseWriter = new(responseWriterHijacker)
|
||||||
|
var _ http.Hijacker = new(responseWriterHijacker)
|
||||||
|
|
||||||
|
type responseWriter struct {
|
||||||
|
commit func(http.ResponseWriter)
|
||||||
|
w http.ResponseWriter
|
||||||
|
hijacked bool
|
||||||
|
writeOnce sync.Once
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriter) ensureCommitted() {
|
||||||
|
rw.writeOnce.Do(func() {
|
||||||
|
if rw.hijacked {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rw.commit(rw.w)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriter) Header() http.Header {
|
||||||
|
return rw.w.Header()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriter) Write(data []byte) (int, error) {
|
||||||
|
rw.ensureCommitted()
|
||||||
|
return rw.w.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriter) WriteHeader(status int) {
|
||||||
|
rw.ensureCommitted()
|
||||||
|
rw.w.WriteHeader(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
type responseWriterHijacker struct {
|
||||||
|
*responseWriter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rw *responseWriterHijacker) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
|
rw.hijacked = true
|
||||||
|
return rw.w.(http.Hijacker).Hijack()
|
||||||
|
}
|
234
middleware/http_middleware.go
Normal file
234
middleware/http_middleware.go
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
package http_middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bitbucket.org/BlackBroker/heruvym/jwt_adapter"
|
||||||
|
"bitbucket.org/BlackBroker/heruvym/middleware/hijack"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/skeris/authService/errors"
|
||||||
|
"net/http"
|
||||||
|
"runtime/debug"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MiddlewareFunc func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)
|
||||||
|
|
||||||
|
type AfterFunc func(ctx context.Context, r *http.Request) (context.Context, error)
|
||||||
|
|
||||||
|
type SetCookieValueFunc func(w http.ResponseWriter, value string)
|
||||||
|
|
||||||
|
func DefaultChain(
|
||||||
|
log *zap.Logger,
|
||||||
|
recFn RecoverFunc,
|
||||||
|
afn AfterFunc,
|
||||||
|
setCookieValue SetCookieValueFunc,
|
||||||
|
mws ...MiddlewareFunc,
|
||||||
|
) http.HandlerFunc {
|
||||||
|
return Chain(
|
||||||
|
append(
|
||||||
|
[]MiddlewareFunc{
|
||||||
|
MiddlewareRecovery(log, recFn),
|
||||||
|
MiddlewareLogger(log),
|
||||||
|
DefaultCookieAndRecoveryMiddleware(
|
||||||
|
log,
|
||||||
|
recFn, afn, setCookieValue,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
mws...,
|
||||||
|
)...,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultCookieAndRecoveryMiddleware(
|
||||||
|
log *zap.Logger,
|
||||||
|
recFn RecoverFunc,
|
||||||
|
afn AfterFunc,
|
||||||
|
setCookieValue SetCookieValueFunc,
|
||||||
|
) MiddlewareFunc {
|
||||||
|
|
||||||
|
const headerKey = jwt_adapter.DefaultHeaderKey
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
|
var err error
|
||||||
|
cookie := &jwt_adapter.JwtAdapter{}
|
||||||
|
tokenHeader := r.Header.Get(headerKey)
|
||||||
|
|
||||||
|
if tokenHeader == "" {
|
||||||
|
fmt.Println("ERROR NO authHEader")
|
||||||
|
cookie.Init()
|
||||||
|
} else {
|
||||||
|
|
||||||
|
splitted := strings.Split(tokenHeader, " ")
|
||||||
|
if len(splitted) != 2 {
|
||||||
|
w.WriteHeader(http.StatusForbidden)
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenPart := splitted[1]
|
||||||
|
|
||||||
|
cookie, err = jwt_adapter.Decode(tokenPart)
|
||||||
|
if err != nil {
|
||||||
|
cookie.Init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recovery := struct {
|
||||||
|
val interface{}
|
||||||
|
trace string
|
||||||
|
}{}
|
||||||
|
|
||||||
|
ctx := context.WithValue(r.Context(), headerKey, cookie)
|
||||||
|
|
||||||
|
if afn != nil {
|
||||||
|
c, err := afn(ctx, r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
ctx = c
|
||||||
|
}
|
||||||
|
|
||||||
|
w, commit := hijack.New(w, func(w http.ResponseWriter) {
|
||||||
|
cookie.LastSeen = jwt_adapter.Timestamp()
|
||||||
|
if val, err := cookie.Encode(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
} else {
|
||||||
|
setCookieValue(w, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
if recovery.val != nil {
|
||||||
|
log.Error("handler recovered", zap.Any("recovered", recovery.val))
|
||||||
|
code, message := recFn(recovery.val, ctx)
|
||||||
|
w.WriteHeader(code)
|
||||||
|
if _, err := fmt.Fprint(w, message); err != nil {
|
||||||
|
log.Error("error writing panic response", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if rec := recover(); rec != nil {
|
||||||
|
recovery.val = rec
|
||||||
|
recovery.trace = string(debug.Stack())
|
||||||
|
}
|
||||||
|
commit()
|
||||||
|
}()
|
||||||
|
|
||||||
|
next(w, r.WithContext(ctx))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Chain(mws ...MiddlewareFunc) http.HandlerFunc {
|
||||||
|
if len(mws) == 0 {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {}
|
||||||
|
}
|
||||||
|
h := link(mws[len(mws)-1], nil)
|
||||||
|
for i := len(mws) - 2; i >= 0; i-- {
|
||||||
|
mw := mws[i]
|
||||||
|
|
||||||
|
h = link(mw, h)
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
func link(mw MiddlewareFunc, next http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mw(w, r, next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecoverFunc func(rec interface{}, ctx context.Context) (code int, message string)
|
||||||
|
|
||||||
|
func MiddlewareRecovery(log *zap.Logger, recFn RecoverFunc) MiddlewareFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
|
defer func() {
|
||||||
|
if rec := recover(); rec != nil {
|
||||||
|
code, message := recFn(rec, r.Context())
|
||||||
|
w.WriteHeader(code)
|
||||||
|
if _, err := fmt.Fprint(w, message); err != nil {
|
||||||
|
log.Error("error writing panic response", zap.Error(err))
|
||||||
|
}
|
||||||
|
log.Error("panic in http handler", zap.Int("code", code), zap.String("message", message), zap.Any("recovered", rec))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
next(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func MiddlewareLogger(log *zap.Logger) MiddlewareFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
|
log.Debug("http request", zap.String("url", r.URL.String()))
|
||||||
|
next(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Handler(h http.HandlerFunc) MiddlewareFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
|
h.ServeHTTP(w, r)
|
||||||
|
if next != nil {
|
||||||
|
next(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Wrap(mux *http.ServeMux, logger *zap.Logger) http.HandlerFunc {
|
||||||
|
return DefaultChain(
|
||||||
|
logger,
|
||||||
|
func(rec interface{}, ctx context.Context) (int, string) {
|
||||||
|
var (
|
||||||
|
code int
|
||||||
|
message string
|
||||||
|
)
|
||||||
|
|
||||||
|
if err, ok := rec.(error); ok {
|
||||||
|
if v, ok := errors.IsForbidden(err); ok {
|
||||||
|
code = http.StatusForbidden
|
||||||
|
message = v.Error()
|
||||||
|
} else if v, ok := errors.IsUnauthenticated(err); ok {
|
||||||
|
code = http.StatusUnauthorized
|
||||||
|
message = v.Error()
|
||||||
|
} else {
|
||||||
|
code = http.StatusInternalServerError
|
||||||
|
message = err.Error()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
code = http.StatusInternalServerError
|
||||||
|
message = fmt.Sprintf("%v", rec)
|
||||||
|
}
|
||||||
|
|
||||||
|
return code, message
|
||||||
|
},
|
||||||
|
nil,
|
||||||
|
func(w http.ResponseWriter, val string) {
|
||||||
|
var setFn func(key, value string)
|
||||||
|
if w.Header().Get(jwt_adapter.DefaultHeaderKey) == "" {
|
||||||
|
setFn = w.Header().Add
|
||||||
|
} else {
|
||||||
|
setFn = w.Header().Set
|
||||||
|
}
|
||||||
|
|
||||||
|
setFn(jwt_adapter.DefaultHeaderKey, fmt.Sprintf("Bearer %s", val))
|
||||||
|
},
|
||||||
|
Handler((func() http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
//todo specify origins
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||||||
|
w.Header().Set("Access-Control-Expose-Headers", "*")
|
||||||
|
|
||||||
|
if r.Method == "OPTIONS" {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
|
||||||
|
w.Header().Set("Pragma", "no-cache")
|
||||||
|
w.Header().Set("Expires", "0")
|
||||||
|
|
||||||
|
mux.ServeHTTP(w, r)
|
||||||
|
|
||||||
|
}
|
||||||
|
})()))
|
||||||
|
}
|
@ -3,14 +3,23 @@ package model
|
|||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
|
ID string `bson:"_id"`
|
||||||
|
TicketID string `bson:"TicketID"`
|
||||||
|
UserID string `bson:"UserID"`
|
||||||
|
SessionID string `bson:"SessionID"`
|
||||||
|
|
||||||
|
Message string `bson:"Messsage"`
|
||||||
|
Files []string `bson:"Files"`
|
||||||
|
|
||||||
|
CreatedAt time.Time `bson:"CreatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Ticket struct {
|
||||||
ID string `bson:"_id"`
|
ID string `bson:"_id"`
|
||||||
UserID string `bson:"UserID"`
|
UserID string `bson:"UserID"`
|
||||||
SessionID string `bson:"SessionID"`
|
SessionID string `bson:"SessionID"`
|
||||||
|
|
||||||
Title string `bson:"Title"`
|
Title string `bson:"Title"`
|
||||||
Message string `bson:"Messsage"`
|
|
||||||
|
|
||||||
Files []string `bson:"Files"`
|
|
||||||
|
|
||||||
CreatedAt time.Time `bson:"CreatedAt"`
|
CreatedAt time.Time `bson:"CreatedAt"`
|
||||||
}
|
}
|
||||||
|
13
service/errors.go
Normal file
13
service/errors.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
type ErrorClose struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorMarshal struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorWrite struct {
|
||||||
|
Err error
|
||||||
|
}
|
111
service/service.go
Normal file
111
service/service.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bitbucket.org/BlackBroker/heruvym/dal"
|
||||||
|
"bitbucket.org/BlackBroker/heruvym/jwt_adapter"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/themakers/hlog"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Heruvym struct {
|
||||||
|
logger hlog.Logger
|
||||||
|
dal *dal.DAL
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(dataAccessLayer *dal.DAL, log hlog.Logger) *Heruvym {
|
||||||
|
return &Heruvym{
|
||||||
|
logger: log.Module("Service"),
|
||||||
|
dal: dataAccessLayer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Heruvym) Register(m *http.ServeMux) *http.ServeMux {
|
||||||
|
|
||||||
|
m.HandleFunc("/create", h.CreateTicket)
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateTicketReq struct {
|
||||||
|
Title string `json:"Title"`
|
||||||
|
Message string `json:"Message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateTicketResp struct {
|
||||||
|
Ticket string `json:"Ticket"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Heruvym) CreateTicket(w http.ResponseWriter, r *http.Request) {
|
||||||
|
defer func() {
|
||||||
|
if err := r.Body.Close(); err != nil {
|
||||||
|
h.logger.Emit(ErrorClose{
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var request CreateTicketReq
|
||||||
|
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||||
|
http.Error(w, "Invalid json", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.Title == "" {
|
||||||
|
http.Error(w, "No Title", http.StatusNoContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.Message == "" {
|
||||||
|
http.Error(w, "No Message", http.StatusNoContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
session := jwt_adapter.Get(ctx)
|
||||||
|
|
||||||
|
if session == nil {
|
||||||
|
http.Error(w, "No session", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ticketID, err := h.dal.CreateTicket(
|
||||||
|
ctx,
|
||||||
|
session.User,
|
||||||
|
session.ID,
|
||||||
|
request.Title,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "CannotCreateTicket", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.dal.PutMessage(ctx,
|
||||||
|
request.Message,
|
||||||
|
session.User,
|
||||||
|
session.Session,
|
||||||
|
ticketID,
|
||||||
|
[]string{},
|
||||||
|
); err != nil {
|
||||||
|
http.Error(w, "CannotCreateMessage", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := json.Marshal(CreateTicketResp{Ticket: ticketID})
|
||||||
|
if err != nil {
|
||||||
|
h.logger.Emit(ErrorMarshal{
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
http.Error(w, "CannotMarshalMessage", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := w.Write(response); err != nil {
|
||||||
|
h.logger.Emit(ErrorMarshal{
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
64
test/main_test.go
Normal file
64
test/main_test.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bitbucket.org/BlackBroker/heruvym/app"
|
||||||
|
"bitbucket.org/BlackBroker/heruvym/service"
|
||||||
|
"bitbucket.org/skeris/profile/jwt_adapter"
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/themakers/bdd"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTicket(t *testing.T) {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
bdd.Scenario(t, "SupportChat", func(t *testing.T, runID string) {
|
||||||
|
go func () {
|
||||||
|
_, err := app.New(ctx, app.Options{
|
||||||
|
MongoURI: "mongodb://localhost:27017",
|
||||||
|
NumberPortLocal: "1488",
|
||||||
|
LoggerDevMode: false,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
|
|
||||||
|
bdd.Act(t, "client", func() {
|
||||||
|
bdd.Test(t, "CreateTicket", func() {
|
||||||
|
buf, err := json.Marshal(service.CreateTicketReq{
|
||||||
|
Title: "TestTitle",
|
||||||
|
Message: "test",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err :=http.NewRequestWithContext(
|
||||||
|
ctx,
|
||||||
|
"POST",
|
||||||
|
"http://localhost:1488/create", bytes.NewBuffer(buf))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add(jwt_adapter.DefaultHeaderKey, "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6ImMxcDM0YjhqZHBmOG04Zm43cnIwIiwiU2Vzc2lvbiI6ImMxcDM0YjhqZHBmOG04Zm43cnJnIiwiVXNlciI6IiIsIlRhcmlmZiI6MCwiQ3JlYXRlZCI6MTYxODA5NjY4NTc4MCwiTGFzdFNlZW4iOjE2MTgwOTY2ODU3ODF9.ciJoJiOxzIPv0LY4h3rG8Tf3AsSBXXLcYEpyN9mIki0")
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
panic("NotAccepted")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user