465 lines
13 KiB
Go
465 lines
13 KiB
Go
package main
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"github.com/caarlos0/env/v8"
|
||
"github.com/google/uuid"
|
||
"github.com/gorilla/mux"
|
||
"gorm.io/driver/postgres"
|
||
"gorm.io/gorm"
|
||
"log"
|
||
"net/http"
|
||
"os"
|
||
"os/signal"
|
||
"syscall"
|
||
)
|
||
|
||
type Config struct {
|
||
Port string `env:"USER_HTTP_ADDR" envDefault:"13998"`
|
||
|
||
PgPort string `env:"PG_PORT" envDefault:"5432"`
|
||
PgHost string `env:"PG_HOST" envDefault:"bd2"`
|
||
PgDBName string `env:"PG_DB_NAME" envDefault:"service2"`
|
||
PgUser string `env:"PG_USER" envDefault:"postgres"`
|
||
PgPwd string `env:"PG_PWD" envDefault:"159753"`
|
||
}
|
||
|
||
func main() {
|
||
cfg := Config{}
|
||
if err := env.Parse(&cfg); err != nil {
|
||
log.Fatalf("failed to retrieve env variables, %v", err)
|
||
}
|
||
if err := Run(cfg); err != nil {
|
||
log.Fatal("error running grpc server ", err)
|
||
}
|
||
}
|
||
|
||
type Office struct {
|
||
Id uuid.UUID `json:"id" gorm:"type:uuid;default:uuid_generate_v4();primaryKey"`
|
||
Name string `json:"name" gorm:"name"`
|
||
Adress string `json:"adress" gorm:"adress"`
|
||
Clercs []Clerc `json:"clercs" gorm:"foreignKey:OfficeId;references:Id;constraint:OnDelete:CASCADE"`
|
||
}
|
||
|
||
type Clerc struct {
|
||
Id uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
|
||
Office Office `gorm:"foreignKey:OfficeId"`
|
||
OfficeId uuid.UUID
|
||
}
|
||
|
||
func InitDb(cfg Config) (*gorm.DB, error) {
|
||
dsn := fmt.Sprintf(
|
||
"host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
|
||
cfg.PgHost, cfg.PgUser, cfg.PgPwd, cfg.PgDBName, cfg.PgPort,
|
||
)
|
||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||
if err != nil {
|
||
log.Fatal("Cannot to Connect DataBase", err)
|
||
}
|
||
db.AutoMigrate(&Office{}, &Clerc{})
|
||
return gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||
}
|
||
|
||
type OfficeRepository interface {
|
||
Create(ctx context.Context, o *Office) error
|
||
Get(ctx context.Context, id uuid.UUID) (*Office, error)
|
||
GetList(ctx context.Context) ([]*Office, error)
|
||
Update(ctx context.Context, o *Office) error
|
||
Delete(ctx context.Context, id uuid.UUID) error
|
||
}
|
||
|
||
type ClercRepository interface {
|
||
Create(ctx context.Context, c *Clerc) error
|
||
GetList(ctx context.Context) ([]*Clerc, error)
|
||
}
|
||
|
||
type ClercStorage struct {
|
||
db *gorm.DB
|
||
}
|
||
|
||
func NewCs(db *gorm.DB) *ClercStorage {
|
||
return &ClercStorage{
|
||
db: db,
|
||
}
|
||
}
|
||
|
||
func (cs *ClercStorage) Create(ctx context.Context, clerc *Clerc) error {
|
||
return cs.db.WithContext(ctx).Create(clerc).Error
|
||
}
|
||
|
||
func (cs *ClercStorage) GetList(ctx context.Context) ([]*Clerc, error) {
|
||
clercs := []*Clerc{}
|
||
err := cs.db.WithContext(ctx).Find(&clercs).Error
|
||
return clercs, err
|
||
}
|
||
|
||
type OfficeStorage struct {
|
||
db *gorm.DB
|
||
}
|
||
|
||
func NewOs(db *gorm.DB) *OfficeStorage {
|
||
return &OfficeStorage{
|
||
db: db,
|
||
}
|
||
}
|
||
|
||
func (os *OfficeStorage) Create(ctx context.Context, clerc *Office) error {
|
||
return os.db.WithContext(ctx).Create(clerc).Error
|
||
}
|
||
|
||
func (os *OfficeStorage) Get(ctx context.Context, id uuid.UUID) (*Office, error) {
|
||
c := new(Office)
|
||
err := os.db.WithContext(ctx).First(c, id).Error
|
||
return c, err
|
||
}
|
||
|
||
func (os *OfficeStorage) GetList(ctx context.Context) ([]*Office, error) {
|
||
offices := []*Office{}
|
||
err := os.db.WithContext(ctx).Find(&offices).Error
|
||
return offices, err
|
||
}
|
||
|
||
func (os *OfficeStorage) Update(ctx context.Context, office *Office) error {
|
||
return os.db.WithContext(ctx).Save(office).Error
|
||
}
|
||
|
||
func (os *OfficeStorage) Delete(ctx context.Context, id uuid.UUID) error {
|
||
c := new(Office)
|
||
return os.db.WithContext(ctx).Where("id = ?", id).Delete(c).Error
|
||
}
|
||
|
||
type Service struct {
|
||
officerep OfficeRepository
|
||
clercrep ClercRepository
|
||
config Config
|
||
}
|
||
|
||
func NewServ(cfg Config, officerep OfficeRepository, clercrep ClercRepository) *Service {
|
||
return &Service{
|
||
config: cfg,
|
||
officerep: officerep,
|
||
clercrep: clercrep,
|
||
}
|
||
}
|
||
|
||
func (s *Service) GetHandler() http.Handler {
|
||
router := mux.NewRouter()
|
||
router.HandleFunc("/service2/office/post", s.Post).Methods(http.MethodPost)
|
||
router.HandleFunc("/service2/office/get", s.Get).Methods(http.MethodGet)
|
||
router.HandleFunc("/service2/office/getall", s.GetAll).Methods(http.MethodGet)
|
||
router.HandleFunc("/service2/office/put", s.Put).Methods(http.MethodPut)
|
||
router.HandleFunc("/service2/office/delete", s.Delete).Methods(http.MethodDelete)
|
||
router.HandleFunc("/service2/office/patch", s.Patch).Methods(http.MethodPatch)
|
||
return router
|
||
}
|
||
|
||
type PostRequest struct {
|
||
Name string `json:"name"`
|
||
Adress string `json:"adress"`
|
||
}
|
||
|
||
func (s *Service) Post(w http.ResponseWriter, r *http.Request) {
|
||
req := &PostRequest{}
|
||
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
|
||
log.Println("Не удалось разкодировать запрос", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
o := Office{
|
||
Name: req.Name,
|
||
Adress: req.Adress,
|
||
}
|
||
err := s.officerep.Create(r.Context(), &o)
|
||
if err != nil {
|
||
log.Println("Не удалось создать офис", err)
|
||
w.WriteHeader(http.StatusInternalServerError)
|
||
return
|
||
}
|
||
w.WriteHeader(http.StatusCreated)
|
||
w.Header().Set("Content-Type", "application/json")
|
||
_ = json.NewEncoder(w).Encode(o)
|
||
}
|
||
|
||
type ClercResponse struct {
|
||
Clercs []ClercReq `json:"clerks"`
|
||
}
|
||
|
||
type ClercReq struct {
|
||
Id string `json:"id"`
|
||
Name string `json:"name"`
|
||
Post string `json:"post"`
|
||
OfficeId string `json:"office_id"`
|
||
}
|
||
|
||
type GetResponse struct {
|
||
Id string `json:"id"`
|
||
Name string `json:"name"`
|
||
Adress string `json:"adress"`
|
||
Clercs []ClercReq `json:"clercs"`
|
||
}
|
||
|
||
func (s *Service) Get(w http.ResponseWriter, r *http.Request) {
|
||
id := r.URL.Query().Get("id")
|
||
uuid, err := uuid.Parse(id)
|
||
if err != nil {
|
||
log.Println("Не удалось конвертировать строку в uuid", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
o, err := s.officerep.Get(r.Context(), uuid)
|
||
if err != nil {
|
||
log.Println("Не удалось получить запись офиса", err)
|
||
w.WriteHeader(http.StatusNotFound)
|
||
return
|
||
}
|
||
url := "http://nginx/service1/clerc/getall"
|
||
response, err := http.Get(url)
|
||
if err != nil {
|
||
fmt.Println("Error:", err)
|
||
return
|
||
}
|
||
defer response.Body.Close()
|
||
/*body, err := ioutil.ReadAll(response.Body)
|
||
if err != nil {
|
||
log.Println("Не удалось прочитать body из Get response с первого сервиса", err)
|
||
w.WriteHeader(http.StatusInternalServerError)
|
||
return
|
||
}*/
|
||
var clercsreq []ClercReq
|
||
if err := json.NewDecoder(response.Body).Decode(&clercsreq); err != nil {
|
||
log.Println("Не удалось разпарсить ответ с 1 сервиса", err)
|
||
w.WriteHeader(http.StatusInternalServerError)
|
||
return
|
||
}
|
||
//var clerksResponse ClercResponse
|
||
/*err = json.Unmarshal(body, clercsreq)
|
||
if err != nil {
|
||
log.Println("Не удалось разпарсить ответ с 1 сервиса", err)
|
||
w.WriteHeader(http.StatusInternalServerError)
|
||
return
|
||
}*/
|
||
|
||
cs, err := s.clercrep.GetList(r.Context())
|
||
if err != nil {
|
||
log.Println("Не удалось получить записи клерков из бд", err)
|
||
w.WriteHeader(http.StatusNotFound)
|
||
return
|
||
}
|
||
clercsid := make([]string, len(cs))
|
||
for _, c := range cs {
|
||
if o.Id == c.OfficeId {
|
||
clercsid = append(clercsid, c.Id.String())
|
||
}
|
||
}
|
||
|
||
clercs := make([]ClercReq, len(o.Clercs))
|
||
for _, clercid := range clercsid {
|
||
for _, c := range clercsreq {
|
||
if clercid == c.Id {
|
||
clercs = append(clercs, c)
|
||
}
|
||
}
|
||
}
|
||
|
||
w.WriteHeader(http.StatusOK)
|
||
w.Header().Set("Content-Type", "application/json")
|
||
_ = json.NewEncoder(w).Encode(&GetResponse{
|
||
Id: o.Id.String(),
|
||
Name: o.Name,
|
||
Adress: o.Adress,
|
||
Clercs: clercs,
|
||
})
|
||
}
|
||
|
||
func (s *Service) GetAll(w http.ResponseWriter, r *http.Request) {
|
||
offices, err := s.officerep.GetList(r.Context())
|
||
if err != nil {
|
||
log.Println("Не удалось получить записи офисов из бд", err)
|
||
w.WriteHeader(http.StatusNotFound)
|
||
return
|
||
}
|
||
clercs, err := s.clercrep.GetList(r.Context())
|
||
if err != nil {
|
||
log.Println("Не удалось получить записи клерков из бд", err)
|
||
w.WriteHeader(http.StatusNotFound)
|
||
return
|
||
}
|
||
//log.Println(clercs)
|
||
for i, o := range offices {
|
||
for _, c := range clercs {
|
||
if o.Id == c.OfficeId {
|
||
offices[i].Clercs = append(offices[i].Clercs, *c)
|
||
}
|
||
}
|
||
}
|
||
w.WriteHeader(http.StatusOK)
|
||
w.Header().Set("Content-Type", "application/json")
|
||
_ = json.NewEncoder(w).Encode(offices)
|
||
}
|
||
|
||
type PatchRequest struct {
|
||
OfficeId string `json:"office_id"`
|
||
ClercId string `json:"clerc_id"`
|
||
}
|
||
|
||
func (s *Service) Patch(w http.ResponseWriter, r *http.Request) {
|
||
log.Println("Использована функция добавления клерка в офис")
|
||
req := &PatchRequest{}
|
||
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
|
||
log.Println("Не удалось разкодировать запрос", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
log.Println(req)
|
||
uuidOffice, err := uuid.Parse(req.OfficeId)
|
||
if err != nil {
|
||
log.Println("Не удалось преобразовать строку в uuid", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
uuidClerc, err := uuid.Parse(req.ClercId)
|
||
if err != nil {
|
||
log.Println("Не удалось преобразовать строку в uuid", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
log.Println(uuidOffice)
|
||
o, err := s.officerep.Get(r.Context(), uuidOffice)
|
||
if err != nil {
|
||
log.Println("Не удалось получить запись офиса из бд", err)
|
||
w.WriteHeader(http.StatusInternalServerError)
|
||
return
|
||
}
|
||
log.Println(*o)
|
||
clerc := &Clerc{
|
||
Id: uuidClerc,
|
||
Office: *o,
|
||
}
|
||
/*o.Clercs = append(o.Clercs, *clerc)
|
||
err = s.officerep.Update(r.Context(), o)
|
||
if err != nil {
|
||
log.Println("Не удалось обновить информации об офисе")
|
||
w.WriteHeader(http.StatusInternalServerError)
|
||
return
|
||
}*/
|
||
err = s.clercrep.Create(r.Context(), clerc)
|
||
if err != nil {
|
||
log.Println("Не удалось создать запись о клерке", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
log.Println(*clerc)
|
||
w.WriteHeader(http.StatusOK)
|
||
}
|
||
|
||
type PutRequest struct {
|
||
Id string `json:"id"`
|
||
Name string `json:"name"`
|
||
Adress string `json:"adress"`
|
||
}
|
||
|
||
func (s *Service) Put(w http.ResponseWriter, r *http.Request) {
|
||
req := &PutRequest{}
|
||
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
|
||
log.Println("Не удалось разкодировать запрос", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
uuid, err := uuid.Parse(req.Id)
|
||
if err != nil {
|
||
log.Println("Не удалось преобразовать строку в uuid", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
o, err := s.officerep.Get(r.Context(), uuid)
|
||
if err != nil {
|
||
log.Println("Не удалось получить запись офиса из бд", err)
|
||
w.WriteHeader(http.StatusInternalServerError)
|
||
return
|
||
}
|
||
o.Name = req.Name
|
||
o.Adress = req.Adress
|
||
err = s.officerep.Update(r.Context(), o)
|
||
if err != nil {
|
||
log.Println("Не удалось обновить запись об офисе", err)
|
||
w.WriteHeader(http.StatusNotFound)
|
||
return
|
||
}
|
||
o2, err := s.officerep.Get(r.Context(), uuid)
|
||
if err != nil {
|
||
log.Println("Не удалось получить запись офиса из бд", err)
|
||
w.WriteHeader(http.StatusInternalServerError)
|
||
return
|
||
}
|
||
w.WriteHeader(http.StatusOK)
|
||
w.Header().Set("Content-Type", "application/json")
|
||
_ = json.NewEncoder(w).Encode(o2)
|
||
}
|
||
|
||
type DeleteRequest struct {
|
||
Id string `json:"id"`
|
||
}
|
||
|
||
func (s *Service) Delete(w http.ResponseWriter, r *http.Request) {
|
||
req := &DeleteRequest{}
|
||
if err := json.NewDecoder(r.Body).Decode(req); err != nil {
|
||
log.Println("Не удалось разкодировать запрос", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
uuid, err := uuid.Parse(req.Id)
|
||
if err != nil {
|
||
log.Println("Не удалось конвертировать строку в uuid", err)
|
||
w.WriteHeader(http.StatusBadRequest)
|
||
return
|
||
}
|
||
err = s.officerep.Delete(r.Context(), uuid)
|
||
if err != nil {
|
||
log.Println("Не удалось удалить запись об офисе", err)
|
||
w.WriteHeader(http.StatusNotFound)
|
||
return
|
||
}
|
||
w.WriteHeader(http.StatusOK)
|
||
}
|
||
|
||
func Run(cfg Config) error {
|
||
db, err := InitDb(cfg)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
serv := NewServ(cfg, NewOs(db), NewCs(db))
|
||
s := &http.Server{
|
||
Addr: ":13998", //"0.0.0.0:%d", cfg.Port),
|
||
Handler: serv.GetHandler(),
|
||
}
|
||
s.SetKeepAlivesEnabled(true)
|
||
ctx, cancel := context.WithCancel(context.Background())
|
||
|
||
go func() {
|
||
log.Printf("starting http server at %d", cfg.Port)
|
||
if err := s.ListenAndServe(); err != nil {
|
||
log.Fatal(err)
|
||
}
|
||
|
||
}()
|
||
|
||
gracefullyShutdown(ctx, cancel, s)
|
||
|
||
return nil
|
||
|
||
}
|
||
|
||
func gracefullyShutdown(ctx context.Context, cancel context.CancelFunc, server *http.Server) {
|
||
ch := make(chan os.Signal, 1)
|
||
signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
|
||
defer signal.Stop(ch)
|
||
<-ch
|
||
if err := server.Shutdown(ctx); err != nil {
|
||
log.Print(err)
|
||
}
|
||
cancel()
|
||
}
|