test of a lightest formula of code

This commit is contained in:
mr
2024-11-28 11:05:54 +01:00
parent 15ca06aba8
commit 2816e3ea35
36 changed files with 574 additions and 783 deletions

View File

@@ -1,7 +1,7 @@
package collaborative_area
import (
"encoding/json"
"slices"
"time"
"cloud.o-forge.io/core/oc-lib/models/collaborative_area/rules/rule"
@@ -10,7 +10,6 @@ import (
w "cloud.o-forge.io/core/oc-lib/models/workflow"
"cloud.o-forge.io/core/oc-lib/models/workspace"
"cloud.o-forge.io/core/oc-lib/tools"
"github.com/google/uuid"
)
type CollaborativeAreaRule struct {
@@ -34,7 +33,7 @@ type CollaborativeArea struct {
Attributes map[string]interface{} `json:"attributes,omitempty" bson:"attributes,omitempty"` // Attributes is the attributes of the workspace (TODO)
Workspaces []string `json:"workspaces" bson:"workspaces"` // Workspaces is the workspaces of the workspace
Workflows []string `json:"workflows" bson:"workflows"` // Workflows is the workflows of the workspace
Peers []string `json:"peers" bson:"peers"` // Peers is the peers of the workspace
AllowedPeersGroup map[string][]string `json:"allowed_peers_group,omitempty" bson:"allowed_peers_group,omitempty"` // AllowedPeersGroup is the group of allowed peers
Rules []string `json:"rules" bson:"rules,omitempty"` // Rules is the rules of the workspace
SharedRules []*rule.Rule `json:"shared_rules,omitempty" bson:"-"` // SharedRules is the shared rules of the workspace
@@ -43,41 +42,31 @@ type CollaborativeArea struct {
SharedPeers []*peer.Peer `json:"shared_peers,omitempty" bson:"-"` // SharedPeers is the shared peers of the workspace
}
func (ao *CollaborativeArea) GetID() string {
return ao.UUID
}
func (r *CollaborativeArea) GenerateID() {
if r.UUID == "" {
r.UUID = uuid.New().String()
func (ao *CollaborativeArea) VerifyAuth(peerID string, groups []string) bool {
if ao.AllowedPeersGroup != nil && len(ao.AllowedPeersGroup) > 0 {
if grps, ok := ao.AllowedPeersGroup[peerID]; ok {
if slices.Contains(grps, "*") {
return true
}
for _, grp := range grps {
if slices.Contains(groups, grp) {
return true
}
}
}
}
return false
}
func (d *CollaborativeArea) GetName() string {
return d.Name
}
func (d *CollaborativeArea) GetAccessor(caller *tools.HTTPCaller) utils.Accessor {
data := New() // Create a new instance of the accessor
data.Init(tools.COLLABORATIVE_AREA, caller) // Initialize the accessor with the SHARED_WORKSPACE model type
func (d *CollaborativeArea) GetAccessor(peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
data := New(peerID, groups) // Create a new instance of the accessor
data.Init(tools.COLLABORATIVE_AREA, peerID, groups, caller) // Initialize the accessor with the SHARED_WORKSPACE model type
return data
}
func (dma *CollaborativeArea) Deserialize(j map[string]interface{}) utils.DBObject {
b, err := json.Marshal(j)
if err != nil {
return nil
func (d *CollaborativeArea) Trim() *CollaborativeArea {
if ok, _ := (&peer.Peer{AbstractObject: utils.AbstractObject{UUID: d.CreatorID}}).IsMySelf(); !ok {
d.AllowedPeersGroup = map[string][]string{}
}
json.Unmarshal(b, dma)
return dma
}
func (dma *CollaborativeArea) Serialize() map[string]interface{} {
var m map[string]interface{}
b, err := json.Marshal(dma)
if err != nil {
return nil
}
json.Unmarshal(b, &m)
return m
return d
}

View File

@@ -6,6 +6,7 @@ import (
"slices"
"time"
"cloud.o-forge.io/core/oc-lib/config"
"cloud.o-forge.io/core/oc-lib/dbs"
"cloud.o-forge.io/core/oc-lib/dbs/mongo"
"cloud.o-forge.io/core/oc-lib/models/collaborative_area/rules/rule"
@@ -19,19 +20,30 @@ import (
// SharedWorkspace is a struct that represents a collaborative area
type collaborativeAreaMongoAccessor struct {
utils.AbstractAccessor // AbstractAccessor contains the basic fields of an accessor (model, caller)
workspaceAccessor utils.Accessor
workflowAccessor utils.Accessor
peerAccessor utils.Accessor
ruleAccessor utils.Accessor
}
// New creates a new instance of the collaborativeAreaMongoAccessor
func New() *collaborativeAreaMongoAccessor {
return &collaborativeAreaMongoAccessor{}
func New(peerID string, groups []string) *collaborativeAreaMongoAccessor {
return &collaborativeAreaMongoAccessor{
workspaceAccessor: (&workspace.Workspace{}).GetAccessor(peerID, groups, nil),
workflowAccessor: (&w.Workflow{}).GetAccessor(peerID, groups, nil),
peerAccessor: (&peer.Peer{}).GetAccessor(peerID, groups, nil),
ruleAccessor: (&rule.Rule{}).GetAccessor(peerID, groups, nil),
}
}
// DeleteOne deletes a collaborative area from the database, given its ID, it automatically share to peers if the workspace is shared
func (wfa *collaborativeAreaMongoAccessor) DeleteOne(id string) (utils.DBObject, int, error) {
set, code, _ := wfa.LoadOne(id)
if code == 200 { // always delete on peers than recreate
wfa.deleteToPeer(set.(*CollaborativeArea))
set, code, err := wfa.LoadOne(id)
if code != 200 {
return nil, code, err
}
wfa.deleteToPeer(set.(*CollaborativeArea))
wfa.sharedWorkflow(&CollaborativeArea{}, id) // create all shared workflows
wfa.sharedWorkspace(&CollaborativeArea{}, id) // create all collaborative areas
return wfa.GenericDeleteOne(id, wfa) // then add on yours
@@ -42,20 +54,19 @@ sharedWorkspace is a function that shares the collaborative area to the peers
*/
func (wfa *collaborativeAreaMongoAccessor) sharedWorkspace(shared *CollaborativeArea, id string) {
eldest, code, _ := wfa.LoadOne(id) // get the eldest
accessor := (&workspace.Workspace{}).GetAccessor(nil)
if code == 200 {
eld := eldest.(*CollaborativeArea)
if eld.Workspaces != nil { // update all your workspaces in the eldest by replacing shared ref by an empty string
for _, v := range eld.Workspaces {
accessor.UpdateOne(&workspace.Workspace{Shared: ""}, v)
wfa.workspaceAccessor.UpdateOne(&workspace.Workspace{Shared: ""}, v)
if wfa.Caller != nil || wfa.Caller.URLS == nil || wfa.Caller.URLS[tools.WORKSPACE] == nil {
continue
}
paccess := (&peer.Peer{}) // send to all peers
for _, p := range shared.Peers { // delete the collaborative area on the peer
b, err := paccess.LaunchPeerExecution(p, v, tools.WORKSPACE, tools.DELETE, nil, wfa.Caller)
paccess := (&peer.Peer{}) // send to all peers
for k := range shared.AllowedPeersGroup { // delete the collaborative area on the peer
b, err := paccess.LaunchPeerExecution(k, v, tools.WORKSPACE, tools.DELETE, nil, wfa.Caller)
if err != nil && b == nil {
wfa.Logger.Error().Msg("Could not send to peer " + p + ". Error: " + err.Error())
wfa.Logger.Error().Msg("Could not send to peer " + k + ". Error: " + err.Error())
}
}
}
@@ -63,20 +74,20 @@ func (wfa *collaborativeAreaMongoAccessor) sharedWorkspace(shared *Collaborative
}
if shared.Workspaces != nil {
for _, v := range shared.Workspaces { // update all the collaborative areas
workspace, code, _ := accessor.UpdateOne(&workspace.Workspace{Shared: shared.UUID}, v) // add the shared ref to workspace
workspace, code, _ := wfa.workspaceAccessor.UpdateOne(&workspace.Workspace{Shared: shared.UUID}, v) // add the shared ref to workspace
if wfa.Caller != nil || wfa.Caller.URLS == nil || wfa.Caller.URLS[tools.WORKSPACE] == nil {
continue
}
for _, p := range shared.Peers {
for k := range shared.AllowedPeersGroup {
if code != 200 {
continue
}
paccess := (&peer.Peer{}) // send to all peers, add the collaborative area on the peer
s := workspace.Serialize()
s["name"] = fmt.Sprintf("%v", s["name"]) + "_" + p
b, err := paccess.LaunchPeerExecution(p, v, tools.WORKSPACE, tools.POST, s, wfa.Caller)
s := workspace.Serialize(workspace)
s["name"] = fmt.Sprintf("%v", s["name"]) + "_" + k
b, err := paccess.LaunchPeerExecution(k, v, tools.WORKSPACE, tools.POST, s, wfa.Caller)
if err != nil && b == nil {
wfa.Logger.Error().Msg("Could not send to peer " + p + ". Error: " + err.Error())
wfa.Logger.Error().Msg("Could not send to peer " + k + ". Error: " + err.Error())
}
}
}
@@ -87,13 +98,12 @@ func (wfa *collaborativeAreaMongoAccessor) sharedWorkspace(shared *Collaborative
// sharedWorkflow is a function that shares the shared workflow to the peers
func (wfa *collaborativeAreaMongoAccessor) sharedWorkflow(shared *CollaborativeArea, id string) {
accessor := (&w.Workflow{}).GetAccessor(nil)
eldest, code, _ := wfa.LoadOne(id) // get the eldest
if code == 200 {
eld := eldest.(*CollaborativeArea)
if eld.Workflows != nil {
for _, v := range eld.Workflows {
data, code, _ := accessor.LoadOne(v)
data, code, _ := wfa.workflowAccessor.LoadOne(v)
if code == 200 {
s := data.(*w.Workflow)
new := []string{}
@@ -104,15 +114,15 @@ func (wfa *collaborativeAreaMongoAccessor) sharedWorkflow(shared *CollaborativeA
} // kick the shared reference in your old shared workflow
n := &w.Workflow{}
n.Shared = new
accessor.UpdateOne(n, v)
wfa.workflowAccessor.UpdateOne(n, v)
if wfa.Caller != nil || wfa.Caller.URLS == nil || wfa.Caller.URLS[tools.WORKFLOW] == nil {
continue
}
paccess := (&peer.Peer{}) // send to all peers
for _, p := range shared.Peers { // delete the shared workflow on the peer
b, err := paccess.LaunchPeerExecution(p, v, tools.WORKFLOW, tools.DELETE, nil, wfa.Caller)
paccess := (&peer.Peer{}) // send to all peers
for k := range shared.AllowedPeersGroup { // delete the shared workflow on the peer
b, err := paccess.LaunchPeerExecution(k, v, tools.WORKFLOW, tools.DELETE, nil, wfa.Caller)
if err != nil && b == nil {
wfa.Logger.Error().Msg("Could not send to peer " + p + ". Error: " + err.Error())
wfa.Logger.Error().Msg("Could not send to peer " + k + ". Error: " + err.Error())
}
}
}
@@ -121,23 +131,23 @@ func (wfa *collaborativeAreaMongoAccessor) sharedWorkflow(shared *CollaborativeA
}
if shared.Workflows != nil { // update all the shared workflows
for _, v := range shared.Workflows {
data, code, _ := accessor.LoadOne(v)
data, code, _ := wfa.workflowAccessor.LoadOne(v)
if code == 200 {
s := data.(*w.Workflow)
if !slices.Contains(s.Shared, id) {
s.Shared = append(s.Shared, id)
workflow, code, _ := accessor.UpdateOne(s, v)
workflow, code, _ := wfa.workflowAccessor.UpdateOne(s, v)
if wfa.Caller != nil || wfa.Caller.URLS == nil || wfa.Caller.URLS[tools.WORKFLOW] == nil {
continue
}
paccess := (&peer.Peer{})
for _, p := range shared.Peers { // send to all peers
for k := range shared.AllowedPeersGroup { // send to all peers
if code == 200 {
s := workflow.Serialize() // add the shared workflow on the peer
s["name"] = fmt.Sprintf("%v", s["name"]) + "_" + p
b, err := paccess.LaunchPeerExecution(p, shared.UUID, tools.WORKFLOW, tools.POST, s, wfa.Caller)
s := workflow.Serialize(workflow) // add the shared workflow on the peer
s["name"] = fmt.Sprintf("%v", s["name"]) + "_" + k
b, err := paccess.LaunchPeerExecution(k, shared.UUID, tools.WORKFLOW, tools.POST, s, wfa.Caller)
if err != nil && b == nil {
wfa.Logger.Error().Msg("Could not send to peer " + p + ". Error: " + err.Error())
wfa.Logger.Error().Msg("Could not send to peer " + k + ". Error: " + err.Error())
}
}
}
@@ -155,13 +165,13 @@ func (wfa *collaborativeAreaMongoAccessor) deleteToPeer(shared *CollaborativeAre
return
}
paccess := (&peer.Peer{})
for _, v := range shared.Peers {
if ok, _ := (&peer.Peer{AbstractObject: utils.AbstractObject{UUID: v}}).IsMySelf(); ok {
for k, _ := range shared.AllowedPeersGroup {
if ok, _ := (&peer.Peer{AbstractObject: utils.AbstractObject{UUID: k}}).IsMySelf(); ok {
continue
}
b, err := paccess.LaunchPeerExecution(v, shared.UUID, tools.COLLABORATIVE_AREA, tools.DELETE, nil, wfa.Caller)
b, err := paccess.LaunchPeerExecution(k, shared.UUID, tools.COLLABORATIVE_AREA, tools.DELETE, nil, wfa.Caller)
if err != nil && b == nil {
wfa.Logger.Error().Msg("Could not send to peer " + v + ". Error: " + err.Error())
wfa.Logger.Error().Msg("Could not send to peer " + k + ". Error: " + err.Error())
}
}
}
@@ -173,22 +183,21 @@ func (wfa *collaborativeAreaMongoAccessor) sendToPeer(shared *CollaborativeArea)
}
paccess := (&peer.Peer{})
for _, v := range shared.Peers {
if ok, _ := (&peer.Peer{AbstractObject: utils.AbstractObject{UUID: v}}).IsMySelf(); ok || shared.IsSent {
for k := range shared.AllowedPeersGroup {
if ok, _ := (&peer.Peer{AbstractObject: utils.AbstractObject{UUID: k}}).IsMySelf(); ok || shared.IsSent {
continue
}
shared.IsSent = true
b, err := paccess.LaunchPeerExecution(v, v, tools.COLLABORATIVE_AREA, tools.POST, shared.Serialize(), wfa.Caller)
b, err := paccess.LaunchPeerExecution(k, k, tools.COLLABORATIVE_AREA, tools.POST, shared.Serialize(shared), wfa.Caller)
if err != nil && b == nil {
wfa.Logger.Error().Msg("Could not send to peer " + v + ". Error: " + err.Error())
wfa.Logger.Error().Msg("Could not send to peer " + k + ". Error: " + err.Error())
}
}
}
// UpdateOne updates a collaborative area in the database, given its ID and the new data, it automatically share to peers if the workspace is shared
func (wfa *collaborativeAreaMongoAccessor) UpdateOne(set utils.DBObject, id string) (utils.DBObject, int, error) {
res, code, err := wfa.GenericUpdateOne(set.(*CollaborativeArea), id, wfa, &CollaborativeArea{})
fmt.Println("UpdateOne", set, res, code, err)
res, code, err := wfa.GenericUpdateOne(set.(*CollaborativeArea).Trim(), id, wfa, &CollaborativeArea{})
// wfa.deleteToPeer(res.(*CollaborativeArea)) // delete the collaborative area on the peer
wfa.sharedWorkflow(res.(*CollaborativeArea), id) // replace all shared workflows
wfa.sharedWorkspace(res.(*CollaborativeArea), id) // replace all collaborative areas (not shared worspace obj but workspace one)
@@ -198,9 +207,14 @@ func (wfa *collaborativeAreaMongoAccessor) UpdateOne(set utils.DBObject, id stri
// StoreOne stores a collaborative area in the database, it automatically share to peers if the workspace is shared
func (wfa *collaborativeAreaMongoAccessor) StoreOne(data utils.DBObject) (utils.DBObject, int, error) {
_, id := (&peer.Peer{}).IsMySelf() // get the local peer
data.(*CollaborativeArea).CreatorID = id // set the creator id
data.(*CollaborativeArea).Peers = append(data.(*CollaborativeArea).Peers, id) // add the creator id to the peers
_, id := (&peer.Peer{}).IsMySelf() // get the local peer
data.(*CollaborativeArea).CreatorID = id // set the creator id
// add the creator id to the peers
if config.GetConfig().Whitelist {
data.(*CollaborativeArea).AllowedPeersGroup[id] = []string{"*"}
} else {
data.(*CollaborativeArea).AllowedPeersGroup[id] = []string{}
}
// then reset the shared fields
if data.(*CollaborativeArea).Workspaces == nil {
data.(*CollaborativeArea).Workspaces = []string{}
@@ -219,12 +233,12 @@ func (wfa *collaborativeAreaMongoAccessor) StoreOne(data utils.DBObject) (utils.
}
data.(*CollaborativeArea).CollaborativeAreaRule.CreatedAt = time.Now().UTC()
// retrieve or proper peer
dd, code, err := (&peer.Peer{}).GetAccessor(nil).Search(nil, "0")
dd, code, err := wfa.peerAccessor.Search(nil, "0")
if code != 200 || len(dd) == 0 {
return nil, code, errors.New("Could not retrieve the peer" + err.Error())
}
data.(*CollaborativeArea).CollaborativeAreaRule.Creator = dd[0].GetID()
d, code, err := wfa.GenericStoreOne(data.(*CollaborativeArea), wfa)
d, code, err := wfa.GenericStoreOne(data.(*CollaborativeArea).Trim(), wfa)
if code == 200 {
wfa.sharedWorkflow(d.(*CollaborativeArea), d.GetID()) // create all shared workflows
wfa.sharedWorkspace(d.(*CollaborativeArea), d.GetID()) // create all collaborative areas
@@ -240,8 +254,7 @@ func (wfa *collaborativeAreaMongoAccessor) CopyOne(data utils.DBObject) (utils.D
// enrich is a function that enriches the CollaborativeArea with the shared objects
func (wfa *collaborativeAreaMongoAccessor) enrich(sharedWorkspace *CollaborativeArea) *CollaborativeArea {
access := (&workspace.Workspace{}).GetAccessor(nil)
res, code, _ := access.Search(&dbs.Filters{
res, code, _ := wfa.workspaceAccessor.Search(&dbs.Filters{
Or: map[string][]dbs.Filter{
"abstractobject.id": {{Operator: dbs.IN.String(), Value: sharedWorkspace.Workspaces}},
},
@@ -251,8 +264,7 @@ func (wfa *collaborativeAreaMongoAccessor) enrich(sharedWorkspace *Collaborative
sharedWorkspace.SharedWorkspaces = append(sharedWorkspace.SharedWorkspaces, r.(*workspace.Workspace))
}
}
access = (&w.Workflow{}).GetAccessor(nil)
res, code, _ = access.Search(&dbs.Filters{
res, code, _ = wfa.workflowAccessor.Search(&dbs.Filters{
Or: map[string][]dbs.Filter{
"abstractobject.id": {{Operator: dbs.IN.String(), Value: sharedWorkspace.Workflows}},
},
@@ -262,10 +274,13 @@ func (wfa *collaborativeAreaMongoAccessor) enrich(sharedWorkspace *Collaborative
sharedWorkspace.SharedWorkflows = append(sharedWorkspace.SharedWorkflows, r.(*w.Workflow))
}
}
access = (&peer.Peer{}).GetAccessor(nil)
res, code, _ = access.Search(&dbs.Filters{
peerskey := []string{}
for k := range sharedWorkspace.AllowedPeersGroup {
peerskey = append(peerskey, k)
}
res, code, _ = wfa.peerAccessor.Search(&dbs.Filters{
Or: map[string][]dbs.Filter{
"abstractobject.id": {{Operator: dbs.IN.String(), Value: sharedWorkspace.Peers}},
"abstractobject.id": {{Operator: dbs.IN.String(), Value: peerskey}},
},
}, "")
if code == 200 {
@@ -273,8 +288,7 @@ func (wfa *collaborativeAreaMongoAccessor) enrich(sharedWorkspace *Collaborative
sharedWorkspace.SharedPeers = append(sharedWorkspace.SharedPeers, r.(*peer.Peer))
}
}
access = (&rule.Rule{}).GetAccessor(nil)
res, code, _ = access.Search(&dbs.Filters{
res, code, _ = wfa.ruleAccessor.Search(&dbs.Filters{
Or: map[string][]dbs.Filter{
"abstractobject.id": {{Operator: dbs.IN.String(), Value: sharedWorkspace.Rules}},
},
@@ -296,6 +310,9 @@ func (wfa *collaborativeAreaMongoAccessor) LoadOne(id string) (utils.DBObject, i
return nil, code, err
}
res_mongo.Decode(&sharedWorkspace)
if !sharedWorkspace.VerifyAuth(wfa.PeerID, wfa.Groups) {
return nil, 403, errors.New("You are not allowed to access this collaborative area")
}
return wfa.enrich(&sharedWorkspace), 200, nil // enrich the collaborative area
}
@@ -312,6 +329,9 @@ func (wfa collaborativeAreaMongoAccessor) LoadAll() ([]utils.ShallowDBObject, in
return nil, 404, err
}
for _, r := range results {
if !r.VerifyAuth(wfa.PeerID, wfa.Groups) {
continue
}
objs = append(objs, wfa.enrich(&r)) // enrich the collaborative area
}
return objs, 200, nil
@@ -337,6 +357,9 @@ func (wfa *collaborativeAreaMongoAccessor) Search(filters *dbs.Filters, search s
return nil, 404, err
}
for _, r := range results {
if !r.VerifyAuth(wfa.PeerID, wfa.Groups) {
continue
}
objs = append(objs, wfa.enrich(&r)) // enrich the collaborative area
}
return objs, 200, nil

View File

@@ -1,8 +1,6 @@
package rule
import (
"encoding/json"
"cloud.o-forge.io/core/oc-lib/models/utils"
"cloud.o-forge.io/core/oc-lib/tools"
"github.com/google/uuid"
@@ -18,39 +16,12 @@ type Rule struct {
Actions []string `json:"actions,omitempty" bson:"actions,omitempty"` // NOT DEFINITIVE TO SPECIFICATION
}
func (ao *Rule) GetID() string {
return ao.UUID
}
func (r *Rule) GenerateID() {
r.UUID = uuid.New().String()
}
func (d *Rule) GetName() string {
return d.Name
}
func (d *Rule) GetAccessor(caller *tools.HTTPCaller) utils.Accessor {
func (d *Rule) GetAccessor(peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
data := New()
data.Init(tools.RULE, caller)
data.Init(tools.RULE, peerID, groups, caller)
return data
}
func (dma *Rule) Deserialize(j map[string]interface{}) utils.DBObject {
b, err := json.Marshal(j)
if err != nil {
return nil
}
json.Unmarshal(b, dma)
return dma
}
func (dma *Rule) Serialize() map[string]interface{} {
var m map[string]interface{}
b, err := json.Marshal(dma)
if err != nil {
return nil
}
json.Unmarshal(b, &m)
return m
}

View File

@@ -1,11 +1,8 @@
package shallow_collaborative_area
import (
"encoding/json"
"cloud.o-forge.io/core/oc-lib/models/utils"
"cloud.o-forge.io/core/oc-lib/tools"
"github.com/google/uuid"
)
type ShallowCollaborativeArea struct {
@@ -21,41 +18,8 @@ type ShallowCollaborativeArea struct {
Rules []string `json:"rules,omitempty" bson:"rules,omitempty"`
}
func (ao *ShallowCollaborativeArea) GetID() string {
return ao.UUID
}
func (r *ShallowCollaborativeArea) GenerateID() {
if r.UUID == "" {
r.UUID = uuid.New().String()
}
}
func (d *ShallowCollaborativeArea) GetName() string {
return d.Name
}
func (d *ShallowCollaborativeArea) GetAccessor(caller *tools.HTTPCaller) utils.Accessor {
func (d *ShallowCollaborativeArea) GetAccessor(peerID string, groups []string, caller *tools.HTTPCaller) utils.Accessor {
data := New()
data.Init(tools.COLLABORATIVE_AREA, caller)
data.Init(tools.COLLABORATIVE_AREA, peerID, groups, caller)
return data
}
func (dma *ShallowCollaborativeArea) Deserialize(j map[string]interface{}) utils.DBObject {
b, err := json.Marshal(j)
if err != nil {
return nil
}
json.Unmarshal(b, dma)
return dma
}
func (dma *ShallowCollaborativeArea) Serialize() map[string]interface{} {
var m map[string]interface{}
b, err := json.Marshal(dma)
if err != nil {
return nil
}
json.Unmarshal(b, &m)
return m
}