Service & repository implementation for CRM field & module
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package repository
|
||||
|
||||
type (
|
||||
repositoryError string
|
||||
)
|
||||
|
||||
const (
|
||||
ErrDatabaseError = repositoryError("DatabaseError")
|
||||
)
|
||||
|
||||
func (e repositoryError) Error() string {
|
||||
return "repository." + string(e)
|
||||
}
|
||||
@@ -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]
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user