Skip to content
This repository was archived by the owner on Feb 4, 2021. It is now read-only.

Commit b7ce9a9

Browse files
committed
Impl ListEntries
1 parent 9e5ebd1 commit b7ce9a9

File tree

11 files changed

+171
-51
lines changed

11 files changed

+171
-51
lines changed

api/entries.pb.go

Lines changed: 51 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/entries.swagger.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@
4949
}
5050
},
5151
"definitions": {
52+
"prolab_accountsBlog": {
53+
"type": "object",
54+
"properties": {
55+
"blog_id": {
56+
"type": "integer",
57+
"format": "int64"
58+
},
59+
"url": {
60+
"type": "string"
61+
},
62+
"feed_url": {
63+
"type": "string"
64+
}
65+
}
66+
},
5267
"prolab_accountsEntry": {
5368
"type": "object",
5469
"properties": {
@@ -81,6 +96,9 @@
8196
"updated_at": {
8297
"type": "string",
8398
"format": "date-time"
99+
},
100+
"blog": {
101+
"$ref": "#/definitions/prolab_accountsBlog"
84102
}
85103
}
86104
},

api/entries.validator.pb.go

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/protos/entries.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import "google/api/annotations.proto";
1010
import "google/protobuf/empty.proto";
1111
import "google/protobuf/timestamp.proto";
1212

13+
import "user_blogs.proto";
1314
import "users.proto";
1415

1516
service EntryService {
@@ -30,6 +31,7 @@ message Entry {
3031
string image_url = 7;
3132
google.protobuf.Timestamp published_at = 8;
3233
google.protobuf.Timestamp updated_at = 9;
34+
Blog blog = 10;
3335
}
3436

3537
message ListEntriesRequest {

api/users.validator.pb.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/run.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ func Run() error {
5555
server.NewUserServiceServer(store, cfg),
5656
server.NewOAuthServiceServer(cli, store),
5757
server.NewUserBlogServiceServer(store),
58+
server.NewEntryServiceServer(store, cfg),
5859
server.NewPingServiceServer(store),
5960
),
6061
)

app/server/entries_server.go

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@ package server
22

33
import (
44
"context"
5+
"database/sql"
6+
"time"
57

8+
"github.com/golang/protobuf/ptypes/timestamp"
69
"github.com/izumin5210/grapi/pkg/grapiserver"
7-
"google.golang.org/grpc/codes"
8-
"google.golang.org/grpc/status"
10+
"github.com/pkg/errors"
911

1012
api_pb "github.com/ProgrammingLab/prolab-accounts/api"
13+
"github.com/ProgrammingLab/prolab-accounts/app/config"
14+
"github.com/ProgrammingLab/prolab-accounts/app/di"
15+
"github.com/ProgrammingLab/prolab-accounts/infra/record"
1116
)
1217

1318
// EntryServiceServer is a composite interface of api_pb.EntryServiceServer and grapiserver.Server.
@@ -17,14 +22,68 @@ type EntryServiceServer interface {
1722
}
1823

1924
// NewEntryServiceServer creates a new EntryServiceServer instance.
20-
func NewEntryServiceServer() EntryServiceServer {
21-
return &entryServiceServerImpl{}
25+
func NewEntryServiceServer(store di.StoreComponent, cfg *config.Config) EntryServiceServer {
26+
return &entryServiceServerImpl{
27+
StoreComponent: store,
28+
cfg: cfg,
29+
}
2230
}
2331

2432
type entryServiceServerImpl struct {
33+
di.StoreComponent
34+
cfg *config.Config
2535
}
2636

2737
func (s *entryServiceServerImpl) ListEntries(ctx context.Context, req *api_pb.ListEntriesRequest) (*api_pb.ListEntriesResponse, error) {
28-
// TODO: Not yet implemented.
29-
return nil, status.Error(codes.Unimplemented, "TODO: You should implement it!")
38+
es := s.EntryStore(ctx)
39+
entries, err := es.ListPublicEntries()
40+
if err != nil {
41+
if errors.Cause(err) == sql.ErrNoRows {
42+
return &api_pb.ListEntriesResponse{}, nil
43+
}
44+
return nil, err
45+
}
46+
47+
resp := entriesToResponse(entries, false, s.cfg)
48+
return &api_pb.ListEntriesResponse{
49+
Entries: resp,
50+
}, nil
51+
}
52+
53+
func entriesToResponse(entries []*record.Entry, includeEmail bool, cfg *config.Config) []*api_pb.Entry {
54+
res := make([]*api_pb.Entry, 0, len(entries))
55+
for _, e := range entries {
56+
res = append(res, entryToResponse(e, includeEmail, cfg))
57+
}
58+
59+
return res
60+
}
61+
62+
func entryToResponse(entry *record.Entry, includeEmail bool, cfg *config.Config) *api_pb.Entry {
63+
e := &api_pb.Entry{
64+
EntryId: uint32(entry.ID),
65+
Title: entry.Title,
66+
Description: entry.Description,
67+
Content: entry.Content,
68+
Link: entry.Link,
69+
ImageUrl: entry.ImageURL,
70+
UpdatedAt: timeToResponse(entry.UpdatedAt),
71+
}
72+
if t := entry.PublishedAt; t.Valid {
73+
e.PublishedAt = timeToResponse(t.Time)
74+
}
75+
if r := entry.R; r != nil {
76+
e.Author = userToResponse(r.Author, includeEmail, cfg)
77+
e.Blog = blogToResponse(r.Blog)
78+
}
79+
80+
return e
81+
}
82+
83+
func timeToResponse(t time.Time) *timestamp.Timestamp {
84+
t = t.UTC()
85+
return &timestamp.Timestamp{
86+
Seconds: t.Unix(),
87+
Nanos: int32(t.Nanosecond()),
88+
}
3089
}

app/server/user_blogs_server.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ func getFeedURL(ctx context.Context, s di.StoreComponent, req blogRequest) (stri
167167
}
168168

169169
func blogToResponse(blog *record.Blog) *api_pb.Blog {
170+
if blog == nil {
171+
return nil
172+
}
173+
170174
return &api_pb.Blog{
171175
BlogId: uint32(blog.ID),
172176
Url: blog.URL,

app/server/users_server.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,10 @@ func usersToResponse(users []*record.User, includeEmail bool, cfg *config.Config
186186
}
187187

188188
func userToResponse(user *record.User, includeEmail bool, cfg *config.Config) *api_pb.User {
189+
if user == nil {
190+
return nil
191+
}
192+
189193
var email string
190194
if includeEmail {
191195
email = user.Email

infra/store/entry/entry_store.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/ProgrammingLab/prolab-accounts/app/util"
1717
"github.com/ProgrammingLab/prolab-accounts/infra/record"
1818
"github.com/ProgrammingLab/prolab-accounts/infra/store"
19+
"github.com/ProgrammingLab/prolab-accounts/model"
1920
)
2021

2122
type entryStoreImpl struct {
@@ -31,6 +32,22 @@ func NewEntryStore(ctx context.Context, db *sql.DB) store.EntryStore {
3132
}
3233
}
3334

35+
func (s *entryStoreImpl) ListPublicEntries() ([]*record.Entry, error) {
36+
mods := []qm.QueryMod{
37+
qm.Load(record.EntryRels.Author),
38+
qm.Load(record.EntryRels.Blog),
39+
qm.InnerJoin("users on users.id = entries.author_id"),
40+
qm.InnerJoin("profiles on profiles.id = users.profile_id"),
41+
qm.Where("profiles.profile_scope = ?", model.Public),
42+
}
43+
44+
e, err := record.Entries(mods...).All(s.ctx, s.db)
45+
if err != nil {
46+
return nil, errors.WithStack(err)
47+
}
48+
return e, nil
49+
}
50+
3451
func (s *entryStoreImpl) CreateEntries(blog *record.Blog, feed *gofeed.Feed) (n int64, err error) {
3552
tx, err := s.db.Begin()
3653
if err != nil {

infra/store/entry_store.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ import (
77

88
// EntryStore accesses entry data
99
type EntryStore interface {
10+
ListPublicEntries() ([]*record.Entry, error)
1011
CreateEntries(blog *record.Blog, feed *gofeed.Feed) (int64, error)
1112
}

0 commit comments

Comments
 (0)