Service & repository implementation for CRM field & module

This commit is contained in:
Denis Arh
2018-07-17 11:06:40 +02:00
parent 3bbb094e84
commit 9c05a271f7
7 changed files with 313 additions and 96 deletions
+13
View File
@@ -0,0 +1,13 @@
package repository
type (
repositoryError string
)
const (
ErrDatabaseError = repositoryError("DatabaseError")
)
func (e repositoryError) Error() string {
return "repository." + string(e)
}
+72
View File
@@ -0,0 +1,72 @@
package repository
import (
"context"
"encoding/json"
"fmt"
"github.com/crusttech/crust/crm/types"
"os"
"path"
"path/filepath"
)
const (
// @todo root should be configurable
// @todo move this to db or stack it inside the binary or container
fieldPath = "crm/data/%s.json"
)
type (
field struct{}
)
func Field() field {
return field{}
}
// Finds field by it's name and returns it
func (repo field) FindByName(ctx context.Context, name string) (*types.Field, error) {
return repo.decode(fmt.Sprintf(fieldPath, name))
}
// Returns all known fields
func (repo field) Find(ctx context.Context) ([]*types.Field, error) {
matches, err := filepath.Glob(fmt.Sprintf(fieldPath, "*"))
if err != nil {
return nil, err
}
res := make([]*types.Field, len(matches))
for i, match := range matches {
if res[i], err = repo.decode(match); err != nil {
return nil, err
}
}
return res, nil
}
func (repo field) decode(filepath string) (*types.Field, error) {
file, err := os.Open(filepath)
if err != nil {
// @todo wrap error
return nil, err
}
defer file.Close()
// Preset field's type with name of the file (sans .json)
// if type is explicitly set within the file, it will be overwritten
field := &types.Field{Type: repo.typeFromPath(filepath)}
if err := json.NewDecoder(file).Decode(&field); err != nil {
// @todo wrap error
return nil, err
}
return field, nil
}
// Removes path and extension from full filename
func (repo field) typeFromPath(filepath string) string {
t := path.Base(filepath)
return t[:len(t)-5]
}
+124
View File
@@ -0,0 +1,124 @@
package repository
import (
"context"
"github.com/crusttech/crust/crm/types"
"github.com/titpetric/factory"
)
type (
module struct{}
)
func Module() module {
return module{}
}
func (r module) FindById(ctx context.Context, id uint64) (*types.Module, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, ErrDatabaseError
}
mod := &types.Module{}
if err := db.Get(mod, "SELECT * FROM crm_module WHERE id = ?", id); err != nil {
println(err.Error())
return nil, ErrDatabaseError
} else {
return mod, nil
}
}
func (r module) Find(ctx context.Context) ([]*types.Module, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, ErrDatabaseError
}
mod := make([]*types.Module, 0)
if err := db.Select(&mod, "SELECT * FROM crm_module ORDER BY name ASC"); err != nil {
println(err.Error())
return nil, ErrDatabaseError
} else {
return mod, nil
}
}
func (r module) Create(ctx context.Context, mod *types.Module) (*types.Module, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, ErrDatabaseError
}
mod.SetID(factory.Sonyflake.NextID())
if err := db.Insert("crm_module", mod); err != nil {
return nil, ErrDatabaseError
} else {
return mod, nil
}
}
func (r module) Update(ctx context.Context, mod *types.Module) (*types.Module, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, ErrDatabaseError
}
if err := db.Replace("crm_module", mod); err != nil {
return nil, ErrDatabaseError
} else {
return mod, nil
}
}
func (r module) Delete(ctx context.Context, mod *types.Module) error {
db, err := factory.Database.Get()
if err != nil {
return ErrDatabaseError
}
if _, err := db.Exec("DELETE FROM crm_module WHERE ID = ?", mod.ID); err != nil {
return ErrDatabaseError
} else {
return nil
}
}
//func (r module) Edit(r *moduleEditRequest) (interface{}, error) {
// db, err := factory.Database.Get()
// if err != nil {
// return nil, err
// }
//
// m := module{}.New()
// m.SetID(r.id).SetName(r.name)
// if m.GetID() > 0 {
// return m, db.Replace("crm_module", m)
// }
// m.SetID(factory.Sonyflake.NextID())
// return m, db.Insert("crm_module", m)
//}
//
//func (r module) ContentList(r *moduleContentListRequest) (interface{}, error) {
// db, err := factory.Database.Get()
// if err != nil {
// return nil, err
// }
//
// if r.id > 0 {
// m := ModuleContentRow{}.New()
// return m, db.Get(m, "select * from crm_module id=?", r.id)
// }
//
// res := make([]ModuleContentRow, 0)
// err = db.Select(&res, "select * from crm_module order by name asc")
// return res, err
//}
//
//func (r module) ContentEdit(r *moduleContentEditRequest) (interface{}, error) {
// return nil, errors.New("Not implemented: module.content/edit")
//}
//
//func (r module) ContentDelete(r *moduleContentDeleteRequest) (interface{}, error) {
// return nil, errors.New("Not implemented: module.content/delete")
//}
+9 -7
View File
@@ -3,31 +3,33 @@ package rest
import (
"github.com/pkg/errors"
"context"
"github.com/crusttech/crust/crm/rest/server"
"github.com/crusttech/crust/crm/service"
"github.com/crusttech/crust/crm/types"
)
var _ = errors.Wrap
type (
Field struct {
service FieldInterface
service fieldService
}
FieldInterface interface {
List() (interface{}, error)
Type(id string) (interface{}, error)
fieldService interface {
FindByName(context.Context, string) (*types.Field, error)
Find(context.Context) ([]*types.Field, error)
}
)
func (Field) New() *Field {
return &Field{service.Field{}.New()}
return &Field{service: service.Field()}
}
func (self *Field) List(_ *server.FieldListRequest) (interface{}, error) {
return self.service.List()
return self.service.Find(context.TODO())
}
func (self *Field) Type(r *server.FieldTypeRequest) (interface{}, error) {
return self.service.Type(r.ID)
return self.service.FindByName(context.TODO(), r.ID)
}
+27 -39
View File
@@ -2,65 +2,53 @@ package rest
import (
"github.com/pkg/errors"
"github.com/titpetric/factory"
"context"
"github.com/crusttech/crust/crm/rest/server"
"github.com/crusttech/crust/crm/service"
"github.com/crusttech/crust/crm/types"
)
var _ = errors.Wrap
type Module struct{}
type (
Module struct {
service moduleService
}
moduleService interface {
FindById(context.Context, uint64) (*types.Module, error)
Find(context.Context) ([]*types.Module, error)
Create(context.Context, *types.Module) (*types.Module, error)
Update(context.Context, *types.Module) (*types.Module, error)
Delete(context.Context, *types.Module) error
}
)
func (Module) New() *Module {
return &Module{}
return &Module{
service: service.Module(),
}
}
func (*Module) List(r *server.ModuleListRequest) (interface{}, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, err
}
if r.ID > 0 {
m := types.Module{}.New()
return m, db.Get(m, "select * from crm_module id=?", r.ID)
}
res := make([]Module, 0)
err = db.Select(&res, "select * from crm_module order by name asc")
return res, err
func (c *Module) List(r *server.ModuleListRequest) (interface{}, error) {
return c.service.Find(context.TODO())
}
func (*Module) Edit(r *server.ModuleEditRequest) (interface{}, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, err
}
func (c *Module) Edit(r *server.ModuleEditRequest) (interface{}, error) {
m := types.Module{}.New()
m.SetID(r.ID).SetName(r.Name)
if m.GetID() > 0 {
return m, db.Replace("crm_module", m)
return c.service.Update(context.TODO(), m)
}
m.SetID(factory.Sonyflake.NextID())
return m, db.Insert("crm_module", m)
return c.service.Create(context.TODO(), m)
}
func (*Module) ContentList(r *server.ModuleContentListRequest) (interface{}, error) {
db, err := factory.Database.Get()
if err != nil {
return nil, err
}
if r.ID > 0 {
m := types.ModuleContentRow{}.New()
return m, db.Get(m, "select * from crm_module id=?", r.ID)
}
res := make([]types.ModuleContentRow, 0)
err = db.Select(&res, "select * from crm_module order by name asc")
return res, err
return nil, errors.New("Not implemented: Module.content/edit")
}
func (*Module) ContentEdit(r *server.ModuleContentEditRequest) (interface{}, error) {
+20 -50
View File
@@ -1,62 +1,32 @@
package service
import (
"encoding/json"
"os"
"path"
"path/filepath"
"github.com/pkg/errors"
_ "github.com/crusttech/crust/crm/types"
"context"
"github.com/crusttech/crust/crm/repository"
"github.com/crusttech/crust/crm/types"
)
var _ = errors.Wrap
type (
fieldType struct {
repository fieldTypeRepository
}
type Field struct{}
fieldTypeRepository interface {
FindByName(context.Context, string) (*types.Field, error)
Find(context.Context) ([]*types.Field, error)
}
)
func (Field) New() *Field {
return &Field{}
func Field() fieldType {
return fieldType{
repository: repository.Field(),
}
}
func (*Field) List() (interface{}, error) {
matches, err := filepath.Glob("../crm/data/*.json")
if err != nil {
return nil, err
}
res := make([]interface{}, 0)
for _, match := range matches {
t := path.Base(match)
t = t[:len(t)-5]
params, err := decodeJSON(match)
if err != nil {
return nil, errors.Wrap(err, "Error when parsing "+match)
}
params["type"] = t
res = append(res, params)
}
return res, nil
func (svc fieldType) FindByName(ctx context.Context, name string) (*types.Field, error) {
return svc.repository.FindByName(ctx, name)
}
func (*Field) Type(id string) (interface{}, error) {
if id == "" {
return nil, errors.New("Missing id parameter")
}
params, err := decodeJSON("../crm/data/" + id + ".json")
if err != nil {
return nil, errors.Wrap(err, "Error reading field type: "+id)
}
params["type"] = id
return params, nil
}
func decodeJSON(filename string) (map[string]interface{}, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
result := make(map[string]interface{})
return result, json.NewDecoder(file).Decode(&result)
func (svc fieldType) Find(ctx context.Context) ([]*types.Field, error) {
return svc.repository.Find(ctx)
}
+48
View File
@@ -0,0 +1,48 @@
package service
import (
"context"
"github.com/crusttech/crust/crm/repository"
"github.com/crusttech/crust/crm/types"
)
type (
module struct {
repository moduleRepository
}
moduleRepository interface {
FindById(context.Context, uint64) (*types.Module, error)
Find(context.Context) ([]*types.Module, error)
Create(context.Context, *types.Module) (*types.Module, error)
Update(context.Context, *types.Module) (*types.Module, error)
Delete(context.Context, *types.Module) error
}
)
func Module() module {
return module{
repository: repository.Module(),
}
}
func (svc module) FindById(ctx context.Context, id uint64) (*types.Module, error) {
return svc.repository.FindById(ctx, id)
}
func (svc module) Find(ctx context.Context) ([]*types.Module, error) {
return svc.repository.Find(ctx)
}
func (svc module) Create(ctx context.Context, mod *types.Module) (*types.Module, error) {
return svc.repository.Create(ctx, mod)
}
func (svc module) Update(ctx context.Context, mod *types.Module) (*types.Module, error) {
return svc.repository.Update(ctx, mod)
}
func (svc module) Delete(ctx context.Context, mod *types.Module) error {
return svc.repository.Delete(ctx, mod)
}