summaryrefslogtreecommitdiff
path: root/app/domain
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-04-25 11:00:53 -0600
committermo khan <mo@mokhan.ca>2025-04-25 11:00:53 -0600
commit0053db0d265af313dd281db5cf1e73236cde30c6 (patch)
tree2ec76a6d42fc903aaa1d0e135addd95d1fd945e4 /app/domain
parent33981e04bebe39c16d3bbb3af84c8772b00102fd (diff)
refactor: move domain package into app
Diffstat (limited to 'app/domain')
-rw-r--r--app/domain/entity.go7
-rw-r--r--app/domain/id.go7
-rw-r--r--app/domain/repository.go7
-rw-r--r--app/domain/sparkle.go60
-rw-r--r--app/domain/sparkle_test.go51
-rw-r--r--app/domain/user.go34
-rw-r--r--app/domain/user_test.go24
7 files changed, 190 insertions, 0 deletions
diff --git a/app/domain/entity.go b/app/domain/entity.go
new file mode 100644
index 0000000..fb1cab8
--- /dev/null
+++ b/app/domain/entity.go
@@ -0,0 +1,7 @@
+package domain
+
+type Entity interface {
+ GetID() ID
+ SetID(id ID) error
+ Validate() error
+}
diff --git a/app/domain/id.go b/app/domain/id.go
new file mode 100644
index 0000000..117a9ad
--- /dev/null
+++ b/app/domain/id.go
@@ -0,0 +1,7 @@
+package domain
+
+type ID string
+
+func (id ID) String() string {
+ return string(id)
+}
diff --git a/app/domain/repository.go b/app/domain/repository.go
new file mode 100644
index 0000000..fb7b6da
--- /dev/null
+++ b/app/domain/repository.go
@@ -0,0 +1,7 @@
+package domain
+
+type Repository[T Entity] interface {
+ All() []T
+ Find(ID) T
+ Save(T) error
+}
diff --git a/app/domain/sparkle.go b/app/domain/sparkle.go
new file mode 100644
index 0000000..68aed67
--- /dev/null
+++ b/app/domain/sparkle.go
@@ -0,0 +1,60 @@
+package domain
+
+import (
+ "errors"
+ "regexp"
+
+ "gitlab.com/gitlab-org/software-supply-chain-security/authorization/sparkled/pkg/pls"
+)
+
+type Sparkle struct {
+ ID ID `json:"id" jsonapi:"primary,sparkles"`
+ Sparklee string `json:"sparklee" jsonapi:"attr,sparklee"`
+ Author *User `json:"author" jsonapi:"attr,author"`
+ Reason string `json:"reason" jsonapi:"attr,reason"`
+}
+
+var SparkleRegex = regexp.MustCompile(`\A\s*(?P<sparklee>@\w+)\s+(?P<reason>.+)\z`)
+var SparkleeIndex = SparkleRegex.SubexpIndex("sparklee")
+var ReasonIndex = SparkleRegex.SubexpIndex("reason")
+
+var ReasonIsRequired = errors.New("Reason is required")
+var SparkleIsEmpty = errors.New("Sparkle is empty")
+var SparkleIsInvalid = errors.New("Sparkle is invalid")
+var SparkleeIsRequired = errors.New("Sparklee is required")
+
+func NewSparkle(text string) (*Sparkle, error) {
+ if len(text) == 0 {
+ return nil, SparkleIsEmpty
+ }
+
+ matches := SparkleRegex.FindStringSubmatch(text)
+ if len(matches) == 0 {
+ return nil, SparkleIsInvalid
+ }
+
+ return &Sparkle{
+ ID: ID(pls.GenerateULID()),
+ Sparklee: matches[SparkleeIndex],
+ Reason: matches[ReasonIndex],
+ }, nil
+}
+
+func (s *Sparkle) GetID() ID {
+ return s.ID
+}
+
+func (s *Sparkle) SetID(id ID) error {
+ s.ID = id
+ return nil
+}
+
+func (s *Sparkle) Validate() error {
+ if s.Sparklee == "" {
+ return SparkleeIsRequired
+ }
+ if s.Reason == "" {
+ return ReasonIsRequired
+ }
+ return nil
+}
diff --git a/app/domain/sparkle_test.go b/app/domain/sparkle_test.go
new file mode 100644
index 0000000..8d81afd
--- /dev/null
+++ b/app/domain/sparkle_test.go
@@ -0,0 +1,51 @@
+package domain
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSparkle(t *testing.T) {
+ t.Run("NewSparkle", func(t *testing.T) {
+ t.Run("with a valid body", func(t *testing.T) {
+ sparkle, err := NewSparkle("@tanuki for helping me with my homework!")
+
+ assert.Nil(t, err)
+ if err != nil {
+ assert.Equal(t, "@tanuki", sparkle.Sparklee)
+ assert.Equal(t, "for helping me with my homework!", sparkle.Reason)
+ }
+ })
+
+ t.Run("with an empty body", func(t *testing.T) {
+ sparkle, err := NewSparkle("")
+
+ assert.Nil(t, sparkle)
+ assert.NotNil(t, err)
+ if err != nil {
+ assert.Equal(t, "Sparkle is empty", err.Error())
+ }
+ })
+
+ t.Run("without a reason", func(t *testing.T) {
+ sparkle, err := NewSparkle("@tanuki")
+
+ assert.Nil(t, sparkle)
+ assert.NotNil(t, err)
+ if err != nil {
+ assert.Equal(t, "Sparkle is invalid", err.Error())
+ }
+ })
+
+ t.Run("without a username", func(t *testing.T) {
+ sparkle, err := NewSparkle("for helping me with my homework")
+
+ assert.Nil(t, sparkle)
+ assert.NotNil(t, err)
+ if err != nil {
+ assert.Equal(t, "Sparkle is invalid", err.Error())
+ }
+ })
+ })
+}
diff --git a/app/domain/user.go b/app/domain/user.go
new file mode 100644
index 0000000..aae17f6
--- /dev/null
+++ b/app/domain/user.go
@@ -0,0 +1,34 @@
+package domain
+
+type User struct {
+ ID ID `json:"id" jsonapi:"primary,users"`
+ Username string `json:"username" jsonapi:"attr,username"`
+ Email string `json:"email" jsonapi:"attr,email"`
+ ProfileURL string `json:"profile" jsonapi:"attr,profile"`
+ Picture string `json:"picture" jsonapi:"attr,picture"`
+}
+
+func NewUser() *User {
+ return &User{}
+}
+
+func (u *User) GetID() ID {
+ return u.ID
+}
+
+func (u *User) SetID(id ID) error {
+ u.ID = id
+ return nil
+}
+
+func (u *User) Validate() error {
+ return nil
+}
+
+func (self *User) Sparkle(sparklee string, reason string) *Sparkle {
+ return &Sparkle{
+ Sparklee: sparklee,
+ Author: self,
+ Reason: reason,
+ }
+}
diff --git a/app/domain/user_test.go b/app/domain/user_test.go
new file mode 100644
index 0000000..1576d6d
--- /dev/null
+++ b/app/domain/user_test.go
@@ -0,0 +1,24 @@
+package domain
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestUser(t *testing.T) {
+ t.Run("Sparkle", func(t *testing.T) {
+ t.Run("returns a new Sparkle", func(t *testing.T) {
+ tanuki := &User{Username: "tanuki"}
+ user := &User{}
+
+ sparkle := user.Sparkle(tanuki.Username, "for helping me with my homework")
+
+ require.NotNil(t, sparkle)
+ assert.Equal(t, tanuki.Username, sparkle.Sparklee)
+ assert.Equal(t, "for helping me with my homework", sparkle.Reason)
+ assert.Equal(t, user, sparkle.Author)
+ })
+ })
+}