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

Commit 26c3c0d

Browse files
committed
Impl CreateInvitation
1 parent 95dea46 commit 26c3c0d

File tree

9 files changed

+132
-57
lines changed

9 files changed

+132
-57
lines changed

api/entries.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.

api/invitations.pb.go

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

api/invitations.swagger.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,6 @@
121121
"type": "integer",
122122
"format": "int64"
123123
},
124-
"token": {
125-
"type": "string"
126-
},
127124
"email": {
128125
"type": "string"
129126
}

api/protos/invitations.proto

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ option go_package = "github.com/ProgrammingLab/prolab-accounts/api;api_pb";
88
import "google/api/annotations.proto";
99
import "google/protobuf/empty.proto";
1010

11+
import "users.proto";
12+
1113
service InvitationService {
1214
rpc ListInvitations (ListInvitationsRequest) returns (ListInvitationsResponse) {
1315
option (google.api.http) = {
@@ -34,8 +36,7 @@ service InvitationService {
3436

3537
message Invitation {
3638
uint32 invitation_id = 1;
37-
string token = 2;
38-
string email= 3;
39+
string email= 2;
3940
}
4041

4142
message ListInvitationsRequest {

app/di/store_component.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
entrystore "github.com/ProgrammingLab/prolab-accounts/infra/store/entry"
1616
feedstore "github.com/ProgrammingLab/prolab-accounts/infra/store/feed"
1717
heartbeatstore "github.com/ProgrammingLab/prolab-accounts/infra/store/heartbeat"
18+
invitationstore "github.com/ProgrammingLab/prolab-accounts/infra/store/invitation"
1819
profilestore "github.com/ProgrammingLab/prolab-accounts/infra/store/profile"
1920
rolestore "github.com/ProgrammingLab/prolab-accounts/infra/store/role"
2021
sessionstore "github.com/ProgrammingLab/prolab-accounts/infra/store/session"
@@ -33,6 +34,7 @@ type StoreComponent interface {
3334
RoleStore(ctx context.Context) store.RoleStore
3435
HeartbeatStore(ctx context.Context) store.HeartbeatStore
3536
DepartmentStore(ctx context.Context) store.DepartmentStore
37+
InvitationStore(ctx context.Context) store.InvitationStore
3638
}
3739

3840
// NewStoreComponent returns new store component
@@ -169,3 +171,7 @@ func (s *storeComponentImpl) DepartmentStore(ctx context.Context) store.Departme
169171
func (s *storeComponentImpl) HeartbeatStore(ctx context.Context) store.HeartbeatStore {
170172
return heartbeatstore.NewHeartbeatStore(ctx, s.client, s.cfg)
171173
}
174+
175+
func (s *storeComponentImpl) InvitationStore(ctx context.Context) store.InvitationStore {
176+
return invitationstore.NewInvitationStore(ctx, s.db)
177+
}

app/server/invitations_server.go

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@ package server
22

33
import (
44
"context"
5+
"database/sql"
56

67
"github.com/golang/protobuf/ptypes/empty"
78
"github.com/izumin5210/grapi/pkg/grapiserver"
9+
"github.com/pkg/errors"
810
"google.golang.org/grpc/codes"
911
"google.golang.org/grpc/status"
1012

1113
api_pb "github.com/ProgrammingLab/prolab-accounts/api"
1214
"github.com/ProgrammingLab/prolab-accounts/app/di"
15+
"github.com/ProgrammingLab/prolab-accounts/app/interceptor"
16+
"github.com/ProgrammingLab/prolab-accounts/app/util"
17+
"github.com/ProgrammingLab/prolab-accounts/infra/record"
18+
"github.com/ProgrammingLab/prolab-accounts/model"
1319
)
1420

1521
// InvitationServiceServer is a composite interface of api_pb.InvitationServiceServer and grapiserver.Server.
@@ -26,6 +32,11 @@ func NewInvitationServiceServer(store di.StoreComponent, cli di.ClientComponent)
2632
}
2733
}
2834

35+
var (
36+
// ErrEmailAlreadyInUse is returned when email is already in use
37+
ErrEmailAlreadyInUse = status.Error(codes.AlreadyExists, "email is already in use")
38+
)
39+
2940
type invitationServiceServerImpl struct {
3041
di.StoreComponent
3142
di.ClientComponent
@@ -42,11 +53,61 @@ func (s *invitationServiceServerImpl) GetInvitation(ctx context.Context, req *ap
4253
}
4354

4455
func (s *invitationServiceServerImpl) CreateInvitation(ctx context.Context, req *api_pb.CreateInvitationRequest) (*api_pb.Invitation, error) {
45-
// TODO: Not yet implemented.
46-
return nil, status.Error(codes.Unimplemented, "TODO: You should implement it!")
56+
admin, err := s.getAdmin(ctx)
57+
if err != nil {
58+
return nil, err
59+
}
60+
61+
us := s.UserStore(ctx)
62+
_, err = us.GetUserByEmail(req.GetEmail())
63+
if err == nil {
64+
return nil, ErrEmailAlreadyInUse
65+
}
66+
if errors.Cause(err) != sql.ErrNoRows {
67+
return nil, err
68+
}
69+
70+
is := s.InvitationStore(ctx)
71+
inv, err := is.CreateInvitation(model.UserID(admin.ID), req.GetEmail())
72+
if err != nil {
73+
return nil, err
74+
}
75+
76+
sender := s.EmailSender(ctx)
77+
err = sender.SendInvitationEmail(inv)
78+
if err != nil {
79+
return nil, err
80+
}
81+
82+
return invitationToResponse(inv), nil
4783
}
4884

4985
func (s *invitationServiceServerImpl) DeleteInvitation(ctx context.Context, req *api_pb.DeleteInvitationRequest) (*empty.Empty, error) {
5086
// TODO: Not yet implemented.
5187
return nil, status.Error(codes.Unimplemented, "TODO: You should implement it!")
5288
}
89+
90+
func (s *invitationServiceServerImpl) getAdmin(ctx context.Context) (*record.User, error) {
91+
userID, ok := interceptor.GetCurrentUserID(ctx)
92+
if !ok {
93+
return nil, util.ErrUnauthenticated
94+
}
95+
96+
us := s.UserStore(ctx)
97+
u, err := us.GetUserWithPrivate(userID)
98+
if err != nil {
99+
return nil, err
100+
}
101+
102+
if u.Authority != int(model.Admin) {
103+
return nil, util.ErrUnauthenticated
104+
}
105+
return u, nil
106+
}
107+
108+
func invitationToResponse(inv *record.Invitation) *api_pb.Invitation {
109+
return &api_pb.Invitation{
110+
InvitationId: uint32(inv.ID),
111+
Email: inv.Email,
112+
}
113+
}

infra/store/invitation/invitation_store.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ func (s *invitationStoreImpl) CreateInvitation(inviter model.UserID, email strin
4646
return nil, err
4747
}
4848

49+
_, err = record.Invitations(record.InvitationWhere.Email.EQ(email)).DeleteAll(s.ctx, s.db)
50+
if err != nil {
51+
return nil, errors.WithStack(err)
52+
}
53+
4954
inv := &record.Invitation{
5055
Code: code,
5156
Email: email,

infra/store/user/user_store.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ func (s *userStoreImpl) GetPublicUserByName(name string) (*record.User, error) {
6060
return u, nil
6161
}
6262

63+
func (s *userStoreImpl) GetUserByEmail(email string) (*record.User, error) {
64+
mods := []qm.QueryMod{
65+
record.UserWhere.Email.EQ(email),
66+
}
67+
u, err := record.Users(mods...).One(s.ctx, s.db)
68+
if err != nil {
69+
return nil, errors.WithStack(err)
70+
}
71+
72+
return u, nil
73+
}
74+
6375
func (s *userStoreImpl) GetUserWithPrivate(userID model.UserID) (*record.User, error) {
6476
mods := []qm.QueryMod{
6577
qm.Load("Profile.Role"),

infra/store/user_store.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
type UserStore interface {
1010
CreateUser(user *record.User) error
1111
GetPublicUserByName(name string) (*record.User, error)
12+
GetUserByEmail(email string) (*record.User, error)
1213
GetUserWithPrivate(userID model.UserID) (*record.User, error)
1314
ListPublicUsers(minUserID model.UserID, limit int) ([]*record.User, model.UserID, error)
1415
UpdateFullName(userID model.UserID, fullName string) (*record.User, error)

0 commit comments

Comments
 (0)