Skip to content

Commit 5950fbe

Browse files
committed
More sketching
1 parent d164485 commit 5950fbe

7 files changed

Lines changed: 387 additions & 3 deletions

File tree

backend/ddd/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
1. Admin only
1818
10. Delete Post
1919
1. Admin only
20+
11. Create Post
21+
12. Update Post
22+
1. Title
23+
2. Content
24+
3. PublishedAt
25+
13. Delete Expired Sessions
2026

2127
## Queries
2228

@@ -37,7 +43,6 @@
3743
1. Session
3844
2. Blog
3945
1. Post ?
40-
3. Post ?
4146
3. Tag
4247

4348
## Entities

backend/ddd/account.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package ddd
2+
3+
import (
4+
"fmt"
5+
"slices"
6+
"time"
7+
8+
"github.com/google/uuid"
9+
10+
"github.com/theandrew168/bloggulus/backend/timeutil"
11+
)
12+
13+
type Session struct {
14+
id uuid.UUID
15+
accountID uuid.UUID
16+
hash string
17+
expiresAt time.Time
18+
19+
createdAt time.Time
20+
updatedAt time.Time
21+
}
22+
23+
type Account struct {
24+
id uuid.UUID
25+
username string
26+
isAdmin bool
27+
28+
followedBlogIDs []uuid.UUID
29+
sessions []Session
30+
31+
createdAt time.Time
32+
updatedAt time.Time
33+
}
34+
35+
func NewAccount(username string) (*Account, error) {
36+
if username == "" {
37+
return nil, fmt.Errorf("account: invalid username")
38+
}
39+
40+
now := timeutil.Now()
41+
account := Account{
42+
id: uuid.New(),
43+
username: username,
44+
isAdmin: false,
45+
46+
createdAt: now,
47+
updatedAt: now,
48+
}
49+
return &account, nil
50+
}
51+
52+
func LoadAccount(id uuid.UUID, username string, isAdmin bool, createdAt, updatedAt time.Time) *Account {
53+
account := Account{
54+
id: id,
55+
username: username,
56+
isAdmin: isAdmin,
57+
58+
createdAt: createdAt,
59+
updatedAt: updatedAt,
60+
}
61+
return &account
62+
}
63+
64+
func (a *Account) ID() uuid.UUID {
65+
return a.id
66+
}
67+
68+
func (a *Account) Username() string {
69+
return a.username
70+
}
71+
72+
func (a *Account) IsAdmin() bool {
73+
return a.isAdmin
74+
}
75+
76+
func (a *Account) CreatedAt() time.Time {
77+
return a.createdAt
78+
}
79+
80+
func (a *Account) UpdatedAt() time.Time {
81+
return a.updatedAt
82+
}
83+
84+
func (a *Account) CheckDelete() error {
85+
return nil
86+
}
87+
88+
func (a *Account) FollowBlog(blogID uuid.UUID) error {
89+
if slices.Contains(a.followedBlogIDs, blogID) {
90+
return fmt.Errorf("account: already following blog")
91+
}
92+
93+
a.followedBlogIDs = append(a.followedBlogIDs, blogID)
94+
return nil
95+
}
96+
97+
func (a *Account) UnfollowBlog(blogID uuid.UUID) error {
98+
for i, id := range a.followedBlogIDs {
99+
if id == blogID {
100+
a.followedBlogIDs = slices.Delete(a.followedBlogIDs, i, i+1)
101+
return nil
102+
}
103+
}
104+
105+
return fmt.Errorf("account: not following blog")
106+
}
107+
108+
func (a *Account) Sessions() []Session {
109+
return a.sessions
110+
}

backend/ddd/blog.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
package ddd
2+
3+
import (
4+
"time"
5+
6+
"github.com/google/uuid"
7+
8+
"github.com/theandrew168/bloggulus/backend/timeutil"
9+
)
10+
11+
const (
12+
// Ensure that a post doesn't get synced more than once every SyncCooldown.
13+
SyncCooldown = 2 * time.Hour
14+
)
15+
16+
type Blog struct {
17+
id uuid.UUID
18+
feedURL string
19+
siteURL string
20+
title string
21+
etag string
22+
lastModified string
23+
syncedAt time.Time
24+
25+
createdAt time.Time
26+
updatedAt time.Time
27+
}
28+
29+
func NewBlog(feedURL, siteURL, title string) (*Blog, error) {
30+
now := timeutil.Now()
31+
blog := Blog{
32+
id: uuid.New(),
33+
feedURL: feedURL,
34+
siteURL: siteURL,
35+
title: title,
36+
37+
createdAt: now,
38+
updatedAt: now,
39+
}
40+
return &blog, nil
41+
}
42+
43+
func LoadBlog(id uuid.UUID, feedURL, siteURL, title, etag, lastModified string, syncedAt, createdAt, updatedAt time.Time) *Blog {
44+
blog := Blog{
45+
id: id,
46+
feedURL: feedURL,
47+
siteURL: siteURL,
48+
title: title,
49+
etag: etag,
50+
lastModified: lastModified,
51+
syncedAt: syncedAt,
52+
53+
createdAt: createdAt,
54+
updatedAt: updatedAt,
55+
}
56+
return &blog
57+
}
58+
59+
func (b *Blog) ID() uuid.UUID {
60+
return b.id
61+
}
62+
63+
func (b *Blog) FeedURL() string {
64+
return b.feedURL
65+
}
66+
67+
func (b *Blog) SiteURL() string {
68+
return b.siteURL
69+
}
70+
71+
func (b *Blog) Title() string {
72+
return b.title
73+
}
74+
75+
func (b *Blog) ETag() string {
76+
return b.etag
77+
}
78+
79+
func (b *Blog) SetETag(etag string) error {
80+
b.etag = etag
81+
return nil
82+
}
83+
84+
func (b *Blog) LastModified() string {
85+
return b.lastModified
86+
}
87+
88+
func (b *Blog) SetLastModified(lastModified string) error {
89+
b.lastModified = lastModified
90+
return nil
91+
}
92+
93+
func (b *Blog) SyncedAt() time.Time {
94+
return b.syncedAt
95+
}
96+
97+
func (b *Blog) SetSyncedAt(syncedAt time.Time) error {
98+
b.syncedAt = syncedAt
99+
return nil
100+
}
101+
102+
func (b *Blog) CanBeSynced(now time.Time) bool {
103+
return b.syncedAt.Add(SyncCooldown).Before(now)
104+
}
105+
106+
func (b *Blog) CreatedAt() time.Time {
107+
return b.createdAt
108+
}
109+
110+
func (b *Blog) UpdatedAt() time.Time {
111+
return b.updatedAt
112+
}
113+
114+
func (b *Blog) SetUpdatedAt(updatedAt time.Time) error {
115+
b.updatedAt = updatedAt
116+
return nil
117+
}
118+
119+
func (b *Blog) CheckDelete() error {
120+
return nil
121+
}

backend/ddd/command/command.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package command
2+
3+
import "github.com/google/uuid"
4+
5+
type Command interface {
6+
Kind() string
7+
}
8+
9+
type AddBlog struct {
10+
URL string
11+
}
12+
13+
func (c AddBlog) Kind() string {
14+
return "AddBlog"
15+
}
16+
17+
type FollowBlog struct {
18+
AccountID uuid.UUID
19+
BlogID uuid.UUID
20+
}
21+
22+
func (c FollowBlog) Kind() string {
23+
return "FollowBlog"
24+
}
25+
26+
type UnfollowBlog struct {
27+
AccountID uuid.UUID
28+
BlogID uuid.UUID
29+
}
30+
31+
func (c UnfollowBlog) Kind() string {
32+
return "UnfollowBlog"
33+
}

backend/ddd/post.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package ddd
2+
3+
import (
4+
"time"
5+
6+
"github.com/google/uuid"
7+
8+
"github.com/theandrew168/bloggulus/backend/timeutil"
9+
)
10+
11+
type Post struct {
12+
id uuid.UUID
13+
blogID uuid.UUID
14+
url string
15+
title string
16+
content string
17+
publishedAt time.Time
18+
19+
createdAt time.Time
20+
updatedAt time.Time
21+
}
22+
23+
func NewPost(blog *Blog, url, title, content string, publishedAt time.Time) (*Post, error) {
24+
now := timeutil.Now()
25+
post := Post{
26+
id: uuid.New(),
27+
blogID: blog.ID(),
28+
url: url,
29+
title: title,
30+
content: content,
31+
publishedAt: publishedAt,
32+
33+
createdAt: now,
34+
updatedAt: now,
35+
}
36+
return &post, nil
37+
}
38+
39+
func LoadPost(id, blogID uuid.UUID, url, title, content string, publishedAt, createdAt, updatedAt time.Time) *Post {
40+
post := Post{
41+
id: id,
42+
blogID: blogID,
43+
url: url,
44+
title: title,
45+
content: content,
46+
publishedAt: publishedAt,
47+
48+
createdAt: createdAt,
49+
updatedAt: updatedAt,
50+
}
51+
return &post
52+
}
53+
54+
func (p *Post) ID() uuid.UUID {
55+
return p.id
56+
}
57+
58+
func (p *Post) BlogID() uuid.UUID {
59+
return p.blogID
60+
}
61+
62+
func (p *Post) URL() string {
63+
return p.url
64+
}
65+
66+
func (p *Post) Title() string {
67+
return p.title
68+
}
69+
70+
func (p *Post) SetTitle(title string) error {
71+
p.title = title
72+
return nil
73+
}
74+
75+
func (p *Post) Content() string {
76+
return p.content
77+
}
78+
79+
func (p *Post) SetContent(content string) error {
80+
p.content = content
81+
return nil
82+
}
83+
84+
func (p *Post) PublishedAt() time.Time {
85+
return p.publishedAt
86+
}
87+
88+
func (p *Post) SetPublishedAt(publishedAt time.Time) error {
89+
p.publishedAt = publishedAt
90+
return nil
91+
}
92+
93+
func (p *Post) CreatedAt() time.Time {
94+
return p.createdAt
95+
}
96+
97+
func (p *Post) UpdatedAt() time.Time {
98+
return p.updatedAt
99+
}
100+
101+
func (p *Post) SetUpdatedAt(updatedAt time.Time) error {
102+
p.updatedAt = updatedAt
103+
return nil
104+
}
105+
106+
func (p *Post) CheckDelete() error {
107+
return nil
108+
}

0 commit comments

Comments
 (0)