feat: organizations and API keys

This commit is contained in:
2023-04-27 07:09:10 +02:00
parent 504f40902e
commit 554a6c252f
22 changed files with 2469 additions and 199 deletions
+57 -6
View File
@@ -8,19 +8,67 @@ import (
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
)
type SubGraph struct {
type Organization struct {
eventsourced.BaseAggregate
Ref string
Service string
Url *string
WSUrl *string
Sdl string
Name string
Users []string
APIKeys []APIKey
CreatedBy string
CreatedAt time.Time
ChangedBy string
ChangedAt time.Time
}
func (o *Organization) Apply(event eventsourced.Event) error {
switch e := event.(type) {
case *OrganizationAdded:
e.UpdateOrganization(o)
case *APIKeyAdded:
o.APIKeys = append(o.APIKeys, APIKey{
Name: e.Name,
OrganizationId: o.ID.String(),
Key: e.Key,
Refs: e.Refs,
Read: e.Read,
Publish: e.Publish,
CreatedBy: e.Initiator,
CreatedAt: e.When(),
})
o.ChangedBy = e.Initiator
o.ChangedAt = e.When()
default:
return fmt.Errorf("unexpected event type: %+v", event)
}
return nil
}
var _ eventsourced.Aggregate = &Organization{}
type APIKey struct {
Name string
OrganizationId string
Key string
Refs []string
Read bool
Publish bool
CreatedBy string
CreatedAt time.Time
}
type SubGraph struct {
eventsourced.BaseAggregate
OrganizationId string
Ref string
Service string
Url *string
WSUrl *string
Sdl string
CreatedBy string
CreatedAt time.Time
ChangedBy string
ChangedAt time.Time
}
func (s *SubGraph) Apply(event eventsourced.Event) error {
switch e := event.(type) {
case *SubGraphUpdated:
@@ -28,6 +76,9 @@ func (s *SubGraph) Apply(event eventsourced.Event) error {
s.CreatedBy = e.Initiator
s.CreatedAt = e.When()
}
if s.OrganizationId == "" {
s.OrganizationId = e.OrganizationId
}
s.ChangedBy = e.Initiator
s.ChangedAt = e.When()
s.Ref = e.Ref
+74 -12
View File
@@ -6,17 +6,78 @@ import (
"strings"
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
"gitlab.com/unboundsoftware/schemas/hash"
)
type UpdateSubGraph struct {
Ref string
Service string
Url *string
WSUrl *string
Sdl string
type AddOrganization struct {
Name string
Initiator string
}
func (a AddOrganization) Validate(_ context.Context, aggregate eventsourced.Aggregate) error {
if aggregate.Identity() != nil {
return fmt.Errorf("organization already exists")
}
if len(a.Name) == 0 {
return fmt.Errorf("name is required")
}
return nil
}
func (a AddOrganization) Event(context.Context) eventsourced.Event {
return &OrganizationAdded{
Name: a.Name,
Initiator: a.Initiator,
}
}
var _ eventsourced.Command = AddOrganization{}
type AddAPIKey struct {
Name string
Key string
Refs []string
Read bool
Publish bool
Initiator string
}
func (a AddAPIKey) Validate(_ context.Context, aggregate eventsourced.Aggregate) error {
if aggregate.Identity() == nil {
return fmt.Errorf("organization does not exist")
}
for _, k := range aggregate.(*Organization).APIKeys {
if k.Name == a.Name {
return fmt.Errorf("a key named '%s' already exist", a.Name)
}
}
return nil
}
func (a AddAPIKey) Event(context.Context) eventsourced.Event {
return &APIKeyAdded{
Name: a.Name,
Key: hash.String(a.Key),
Refs: a.Refs,
Read: a.Read,
Publish: a.Publish,
Initiator: a.Initiator,
}
}
var _ eventsourced.Command = AddAPIKey{}
type UpdateSubGraph struct {
OrganizationId string
Ref string
Service string
Url *string
WSUrl *string
Sdl string
Initiator string
}
func (u UpdateSubGraph) Validate(_ context.Context, aggregate eventsourced.Aggregate) error {
switch a := aggregate.(type) {
case *SubGraph:
@@ -40,12 +101,13 @@ func (u UpdateSubGraph) Validate(_ context.Context, aggregate eventsourced.Aggre
func (u UpdateSubGraph) Event(context.Context) eventsourced.Event {
return &SubGraphUpdated{
Ref: u.Ref,
Service: u.Service,
Url: u.Url,
WSUrl: u.WSUrl,
Sdl: u.Sdl,
Initiator: u.Initiator,
OrganizationId: u.OrganizationId,
Ref: u.Ref,
Service: u.Service,
Url: u.Url,
WSUrl: u.WSUrl,
Sdl: u.Sdl,
Initiator: u.Initiator,
}
}
+63
View File
@@ -0,0 +1,63 @@
package domain
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"gitlab.com/unboundsoftware/eventsourced/eventsourced"
)
func TestAddAPIKey_Event(t *testing.T) {
type fields struct {
Name string
Key string
Refs []string
Read bool
Publish bool
Initiator string
}
type args struct {
in0 context.Context
}
tests := []struct {
name string
fields fields
args args
want eventsourced.Event
}{
{
name: "event",
fields: fields{
Name: "test",
Key: "us_ak_1234567890123456",
Refs: []string{"Example@dev"},
Read: true,
Publish: true,
Initiator: "jim@example.org",
},
args: args{},
want: &APIKeyAdded{
Name: "test",
Key: "dXNfYWtfMTIzNDU2Nzg5MDEyMzQ1NuOwxEKY/BwUmvv0yJlvuSQnrkHkZJuTTKSVmRt4UrhV",
Refs: []string{"Example@dev"},
Read: true,
Publish: true,
Initiator: "jim@example.org",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
a := AddAPIKey{
Name: tt.fields.Name,
Key: tt.fields.Key,
Refs: tt.fields.Refs,
Read: tt.fields.Read,
Publish: tt.fields.Publish,
Initiator: tt.fields.Initiator,
}
assert.Equalf(t, tt.want, a.Event(tt.args.in0), "Event(%v)", tt.args.in0)
})
}
}
+41 -6
View File
@@ -2,13 +2,48 @@ package domain
import "gitlab.com/unboundsoftware/eventsourced/eventsourced"
type OrganizationAdded struct {
eventsourced.EventAggregateId
eventsourced.EventTime
Name string `json:"name"`
Initiator string `json:"initiator"`
}
func (a *OrganizationAdded) UpdateOrganization(o *Organization) {
o.Name = a.Name
o.Users = []string{a.Initiator}
o.CreatedBy = a.Initiator
o.CreatedAt = a.When()
o.ChangedBy = a.Initiator
o.ChangedAt = a.When()
}
type APIKeyAdded struct {
eventsourced.EventAggregateId
eventsourced.EventTime
OrganizationId string `json:"organizationId"`
Name string `json:"name"`
Key string `json:"key"`
Refs []string `json:"refs"`
Read bool `json:"read"`
Publish bool `json:"publish"`
Initiator string `json:"initiator"`
}
func (a *APIKeyAdded) EnrichFromAggregate(aggregate eventsourced.Aggregate) {
a.OrganizationId = aggregate.Identity().String()
}
var _ eventsourced.EnrichableEvent = &APIKeyAdded{}
type SubGraphUpdated struct {
eventsourced.EventAggregateId
eventsourced.EventTime
Ref string
Service string
Url *string
WSUrl *string
Sdl string
Initiator string
OrganizationId string `json:"organizationId"`
Ref string `json:"ref"`
Service string `json:"service"`
Url *string `json:"url"`
WSUrl *string `json:"wsUrl"`
Sdl string `json:"sdl"`
Initiator string `json:"initiator"`
}