SMQ-2719 - Update list domain invitations endpoint (#2965)
Continuous Delivery / Build and Push (push) Has been cancelled
Check the consistency of generated files / check-generated-files (push) Has been cancelled
Check License Header / check-license (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled

Signed-off-by: Felix Gateru <felix.gateru@gmail.com>
This commit is contained in:
Felix Gateru
2025-07-01 20:03:33 +03:00
committed by GitHub
parent f6e8db4c09
commit 5d04de4ffa
15 changed files with 455 additions and 89 deletions
+1 -3
View File
@@ -234,9 +234,8 @@ func listDomainInvitationsEndpoint(svc domains.Service) endpoint.Endpoint {
if !ok {
return nil, svcerr.ErrAuthorization
}
req.InvitationPageMeta.DomainID = session.DomainID
page, err := svc.ListInvitations(ctx, session, req.InvitationPageMeta)
page, err := svc.ListDomainInvitations(ctx, session, req.InvitationPageMeta)
if err != nil {
return nil, err
}
@@ -258,7 +257,6 @@ func listUserInvitationsEndpoint(svc domains.Service) endpoint.Endpoint {
if !ok {
return nil, svcerr.ErrAuthorization
}
session.DomainID = req.DomainID
page, err := svc.ListInvitations(ctx, session, req.InvitationPageMeta)
if err != nil {
+163 -17
View File
@@ -1164,7 +1164,169 @@ func TestSendInvitation(t *testing.T) {
}
}
func TestListInvitation(t *testing.T) {
func TestListDomainInvitations(t *testing.T) {
is, svc, auth := newDomainsServer()
cases := []struct {
desc string
token string
session authn.Session
domainID string
query string
contentType string
status int
svcErr error
authnErr error
}{
{
desc: "list invitations with valid request",
token: validToken,
domainID: domainID,
status: http.StatusOK,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with invalid token",
token: "",
domainID: domainID,
status: http.StatusUnauthorized,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with offset",
token: validToken,
domainID: domainID,
query: "offset=1",
status: http.StatusOK,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with invalid offset",
token: validToken,
domainID: domainID,
query: "offset=invalid",
status: http.StatusBadRequest,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with limit",
token: validToken,
query: "limit=1",
domainID: domainID,
status: http.StatusOK,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with invalid limit",
token: validToken,
domainID: domainID,
query: "limit=invalid",
status: http.StatusBadRequest,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with invitee_user_id",
token: validToken,
domainID: domainID,
query: fmt.Sprintf("invitee_user_id=%s", validID),
status: http.StatusOK,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with duplicate invitee_user_id",
token: validToken,
domainID: domainID,
query: "invitee_user_id=1&invitee_user_id=2",
status: http.StatusBadRequest,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with invited_by",
token: validToken,
domainID: domainID,
query: fmt.Sprintf("invited_by=%s", validID),
status: http.StatusOK,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with duplicate invited_by",
token: validToken,
domainID: domainID,
query: "invited_by=1&invited_by=2",
status: http.StatusBadRequest,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with state",
token: validToken,
domainID: domainID,
query: "state=pending",
status: http.StatusOK,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with invalid state",
token: validToken,
domainID: domainID,
query: "state=invalid",
status: http.StatusBadRequest,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with duplicate state",
token: validToken,
domainID: domainID,
query: "state=all&state=all",
status: http.StatusBadRequest,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with service error",
token: validToken,
domainID: invalid,
status: http.StatusForbidden,
contentType: contentType,
svcErr: svcerr.ErrAuthorization,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
if tc.token == validToken {
tc.session = authn.Session{UserID: userID, DomainID: tc.domainID}
}
authnCall := auth.On("Authenticate", mock.Anything, tc.token).Return(tc.session, tc.authnErr)
repoCall := svc.On("ListDomainInvitations", mock.Anything, tc.session, mock.Anything).Return(domains.InvitationPage{}, tc.svcErr)
req := testRequest{
client: is.Client(),
method: http.MethodGet,
url: fmt.Sprintf("%s/domains/%s/invitations?", is.URL, tc.domainID) + tc.query,
token: tc.token,
contentType: tc.contentType,
}
res, err := req.make()
assert.Nil(t, err, tc.desc)
assert.Equal(t, tc.status, res.StatusCode, tc.desc)
repoCall.Unset()
authnCall.Unset()
})
}
}
func TestListUserInvitations(t *testing.T) {
is, svc, auth := newDomainsServer()
cases := []struct {
@@ -1223,22 +1385,6 @@ func TestListInvitation(t *testing.T) {
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with invitee_user_id",
token: validToken,
query: fmt.Sprintf("invitee_user_id=%s", validID),
status: http.StatusOK,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with duplicate invitee_user_id",
token: validToken,
query: "invitee_user_id=1&invitee_user_id=2",
status: http.StatusBadRequest,
contentType: contentType,
svcErr: nil,
},
{
desc: "list invitations with invited_by",
token: validToken,
+5 -2
View File
@@ -201,11 +201,14 @@ type Service interface {
ViewInvitation(ctx context.Context, session authn.Session, inviteeUserID, domainID string) (invitation Invitation, err error)
// ListInvitations returns a list of invitations.
// By default, it will list invitations the current user has received.
ListInvitations(ctx context.Context, session authn.Session, page InvitationPageMeta) (invitations InvitationPage, err error)
// ListDomainInvitations returns a list of invitations for the domain.
// People who can list invitations are:
// - platform administrators can list all invitations
// - domain administrators can list invitations for their domain
// By default, it will list invitations the current user has sent or received.
ListInvitations(ctx context.Context, session authn.Session, page InvitationPageMeta) (invitations InvitationPage, err error)
ListDomainInvitations(ctx context.Context, session authn.Session, page InvitationPageMeta) (invitations InvitationPage, err error)
// AcceptInvitation accepts an invitation by adding the user to the domain.
AcceptInvitation(ctx context.Context, session authn.Session, domainID string) (invitation Invitation, err error)
+54 -22
View File
@@ -13,21 +13,22 @@ import (
)
const (
domainPrefix = "domain."
domainCreate = domainPrefix + "create"
domainRetrieve = domainPrefix + "retrieve"
domainUpdate = domainPrefix + "update"
domainEnable = domainPrefix + "enable"
domainDisable = domainPrefix + "disable"
domainFreeze = domainPrefix + "freeze"
domainList = domainPrefix + "list"
invitationPrefix = "invitation."
invitationSend = invitationPrefix + "send"
invitationAccept = invitationPrefix + "accept"
invitationReject = invitationPrefix + "reject"
invitationList = invitationPrefix + "list"
invitationRetrieve = invitationPrefix + "retrieve"
invitationDelete = invitationPrefix + "delete"
domainPrefix = "domain."
domainCreate = domainPrefix + "create"
domainRetrieve = domainPrefix + "retrieve"
domainUpdate = domainPrefix + "update"
domainEnable = domainPrefix + "enable"
domainDisable = domainPrefix + "disable"
domainFreeze = domainPrefix + "freeze"
domainList = domainPrefix + "list"
invitationPrefix = "invitation."
invitationSend = invitationPrefix + "send"
invitationAccept = invitationPrefix + "accept"
invitationReject = invitationPrefix + "reject"
invitationList = invitationPrefix + "list"
invitationListDomain = invitationPrefix + "list_domain"
invitationRetrieve = invitationPrefix + "retrieve"
invitationDelete = invitationPrefix + "delete"
)
var (
@@ -42,6 +43,7 @@ var (
_ events.Event = (*sendInvitationEvent)(nil)
_ events.Event = (*viewInvitationEvent)(nil)
_ events.Event = (*listInvitationsEvent)(nil)
_ events.Event = (*listDomainInvitationsEvent)(nil)
_ events.Event = (*acceptInvitationEvent)(nil)
_ events.Event = (*rejectInvitationEvent)(nil)
_ events.Event = (*deleteInvitationEvent)(nil)
@@ -351,12 +353,11 @@ type listInvitationsEvent struct {
func (lie listInvitationsEvent) Encode() (map[string]interface{}, error) {
val := map[string]interface{}{
"operation": invitationList,
"offset": lie.Offset,
"limit": lie.Limit,
"user_id": lie.session.UserID,
"token_type": lie.session.Type.String(),
"super_admin": lie.session.SuperAdmin,
"operation": invitationList,
"offset": lie.Offset,
"limit": lie.Limit,
"user_id": lie.session.UserID,
"token_type": lie.session.Type.String(),
}
if lie.InvitedBy != "" {
@@ -371,7 +372,38 @@ func (lie listInvitationsEvent) Encode() (map[string]interface{}, error) {
if lie.RoleID != "" {
val["role_id"] = lie.RoleID
}
if lie.State.String() != "" {
if lie.State.String() != domains.UnknownState {
val["state"] = lie.State.String()
}
return val, nil
}
type listDomainInvitationsEvent struct {
domains.InvitationPageMeta
session authn.Session
}
func (lie listDomainInvitationsEvent) Encode() (map[string]interface{}, error) {
val := map[string]interface{}{
"operation": invitationListDomain,
"offset": lie.Offset,
"limit": lie.Limit,
"domain_id": lie.session.DomainID,
"token_type": lie.session.Type.String(),
"super_admin": lie.session.SuperAdmin,
}
if lie.InvitedBy != "" {
val["invited_by"] = lie.InvitedBy
}
if lie.InviteeUserID != "" {
val["invitee_user_id"] = lie.InviteeUserID
}
if lie.RoleID != "" {
val["role_id"] = lie.RoleID
}
if lie.State.String() != domains.UnknownState {
val["state"] = lie.State.String()
}
+33 -14
View File
@@ -16,20 +16,21 @@ import (
)
const (
supermqPrefix = "supermq."
createStream = supermqPrefix + domainCreate
retrieveStream = supermqPrefix + domainRetrieve
updateStream = supermqPrefix + domainUpdate
enableStream = supermqPrefix + domainEnable
disableStream = supermqPrefix + domainDisable
freezeStream = supermqPrefix + domainFreeze
listStream = supermqPrefix + domainList
sendInvitationStream = supermqPrefix + invitationSend
acceptInvitationStream = supermqPrefix + invitationAccept
rejectInvitationStream = supermqPrefix + invitationReject
listInvitationsStream = supermqPrefix + invitationList
retrieveInvitationStream = supermqPrefix + invitationRetrieve
deleteInvitationStream = supermqPrefix + invitationDelete
supermqPrefix = "supermq."
createStream = supermqPrefix + domainCreate
retrieveStream = supermqPrefix + domainRetrieve
updateStream = supermqPrefix + domainUpdate
enableStream = supermqPrefix + domainEnable
disableStream = supermqPrefix + domainDisable
freezeStream = supermqPrefix + domainFreeze
listStream = supermqPrefix + domainList
sendInvitationStream = supermqPrefix + invitationSend
acceptInvitationStream = supermqPrefix + invitationAccept
rejectInvitationStream = supermqPrefix + invitationReject
listInvitationsStream = supermqPrefix + invitationList
listDomainInvitationsStream = supermqPrefix + invitationListDomain
retrieveInvitationStream = supermqPrefix + invitationRetrieve
deleteInvitationStream = supermqPrefix + invitationDelete
)
var _ domains.Service = (*eventStore)(nil)
@@ -252,6 +253,24 @@ func (es *eventStore) ListInvitations(ctx context.Context, session authn.Session
return ip, nil
}
func (es *eventStore) ListDomainInvitations(ctx context.Context, session authn.Session, pm domains.InvitationPageMeta) (domains.InvitationPage, error) {
ip, err := es.svc.ListDomainInvitations(ctx, session, pm)
if err != nil {
return ip, err
}
event := listDomainInvitationsEvent{
InvitationPageMeta: pm,
session: session,
}
if err := es.Publish(ctx, listDomainInvitationsStream, event); err != nil {
return ip, err
}
return ip, nil
}
func (es *eventStore) AcceptInvitation(ctx context.Context, session authn.Session, domainID string) (domains.Invitation, error) {
inv, err := es.svc.AcceptInvitation(ctx, session, domainID)
if err != nil {
+15 -17
View File
@@ -226,23 +226,6 @@ func (am *authorizationMiddleware) ViewInvitation(ctx context.Context, session a
}
func (am *authorizationMiddleware) ListInvitations(ctx context.Context, session authn.Session, page domains.InvitationPageMeta) (invs domains.InvitationPage, err error) {
session.DomainUserID = auth.EncodeDomainUserID(session.DomainID, session.UserID)
if err := am.extAuthorize(ctx, session.UserID, policies.AdminPermission, policies.PlatformType, policies.SuperMQObject); err == nil {
session.SuperAdmin = true
page.DomainID = ""
}
if !session.SuperAdmin {
switch {
case page.DomainID != "":
if err := am.extAuthorize(ctx, session.DomainUserID, policies.AdminPermission, policies.DomainType, page.DomainID); err != nil {
return domains.InvitationPage{}, err
}
default:
page.InvitedByOrUserID = session.UserID
}
}
params := map[string]any{
"page": page,
}
@@ -253,6 +236,21 @@ func (am *authorizationMiddleware) ListInvitations(ctx context.Context, session
return am.svc.ListInvitations(ctx, session, page)
}
func (am *authorizationMiddleware) ListDomainInvitations(ctx context.Context, session authn.Session, page domains.InvitationPageMeta) (invs domains.InvitationPage, err error) {
if err := am.extAuthorize(ctx, session.DomainUserID, policies.AdminPermission, policies.DomainType, session.DomainID); err != nil {
return domains.InvitationPage{}, err
}
params := map[string]any{
"page": page,
}
if err := am.callOut(ctx, session, domains.OpListDomainInvitations.String(domains.OperationNames), params); err != nil {
return domains.InvitationPage{}, err
}
return am.svc.ListDomainInvitations(ctx, session, page)
}
func (am *authorizationMiddleware) AcceptInvitation(ctx context.Context, session authn.Session, domainID string) (inv domains.Invitation, err error) {
params := map[string]any{
"domain": domainID,
+20
View File
@@ -229,6 +229,26 @@ func (lm *loggingMiddleware) ListInvitations(ctx context.Context, session authn.
return lm.svc.ListInvitations(ctx, session, pm)
}
func (lm *loggingMiddleware) ListDomainInvitations(ctx context.Context, session authn.Session, pm domains.InvitationPageMeta) (invs domains.InvitationPage, err error) {
defer func(begin time.Time) {
args := []any{
slog.String("duration", time.Since(begin).String()),
slog.Group("page",
slog.Uint64("offset", pm.Offset),
slog.Uint64("limit", pm.Limit),
slog.Uint64("total", invs.Total),
),
}
if err != nil {
args = append(args, slog.Any("error", err))
lm.logger.Warn("List domain invitations failed", args...)
return
}
lm.logger.Info("List domain invitations completed successfully", args...)
}(time.Now())
return lm.svc.ListDomainInvitations(ctx, session, pm)
}
func (lm *loggingMiddleware) AcceptInvitation(ctx context.Context, session authn.Session, domainID string) (inv domains.Invitation, err error) {
defer func(begin time.Time) {
args := []any{
+8
View File
@@ -117,6 +117,14 @@ func (mm *metricsMiddleware) ListInvitations(ctx context.Context, session authn.
return mm.svc.ListInvitations(ctx, session, pm)
}
func (mm *metricsMiddleware) ListDomainInvitations(ctx context.Context, session authn.Session, pm domains.InvitationPageMeta) (invs domains.InvitationPage, err error) {
defer func(begin time.Time) {
mm.counter.With("method", "list_invitee_invitations").Add(1)
mm.latency.With("method", "list_invitee_invitations").Observe(time.Since(begin).Seconds())
}(time.Now())
return mm.svc.ListDomainInvitations(ctx, session, pm)
}
func (mm *metricsMiddleware) AcceptInvitation(ctx context.Context, session authn.Session, domainID string) (inv domains.Invitation, err error) {
defer func(begin time.Time) {
mm.counter.With("method", "accept_invitation").Add(1)
+56
View File
@@ -495,6 +495,62 @@ func (_c *Service_ListAvailableActions_Call) RunAndReturn(run func(ctx context.C
return _c
}
// ListDomainInvitations provides a mock function for the type Service
func (_mock *Service) ListDomainInvitations(ctx context.Context, session authn.Session, page domains.InvitationPageMeta) (domains.InvitationPage, error) {
ret := _mock.Called(ctx, session, page)
if len(ret) == 0 {
panic("no return value specified for ListDomainInvitations")
}
var r0 domains.InvitationPage
var r1 error
if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, domains.InvitationPageMeta) (domains.InvitationPage, error)); ok {
return returnFunc(ctx, session, page)
}
if returnFunc, ok := ret.Get(0).(func(context.Context, authn.Session, domains.InvitationPageMeta) domains.InvitationPage); ok {
r0 = returnFunc(ctx, session, page)
} else {
r0 = ret.Get(0).(domains.InvitationPage)
}
if returnFunc, ok := ret.Get(1).(func(context.Context, authn.Session, domains.InvitationPageMeta) error); ok {
r1 = returnFunc(ctx, session, page)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Service_ListDomainInvitations_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListDomainInvitations'
type Service_ListDomainInvitations_Call struct {
*mock.Call
}
// ListDomainInvitations is a helper method to define mock.On call
// - ctx
// - session
// - page
func (_e *Service_Expecter) ListDomainInvitations(ctx interface{}, session interface{}, page interface{}) *Service_ListDomainInvitations_Call {
return &Service_ListDomainInvitations_Call{Call: _e.mock.On("ListDomainInvitations", ctx, session, page)}
}
func (_c *Service_ListDomainInvitations_Call) Run(run func(ctx context.Context, session authn.Session, page domains.InvitationPageMeta)) *Service_ListDomainInvitations_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(authn.Session), args[2].(domains.InvitationPageMeta))
})
return _c
}
func (_c *Service_ListDomainInvitations_Call) Return(invitations domains.InvitationPage, err error) *Service_ListDomainInvitations_Call {
_c.Call.Return(invitations, err)
return _c
}
func (_c *Service_ListDomainInvitations_Call) RunAndReturn(run func(ctx context.Context, session authn.Session, page domains.InvitationPageMeta) (domains.InvitationPage, error)) *Service_ListDomainInvitations_Call {
_c.Call.Return(run)
return _c
}
// ListDomains provides a mock function for the type Service
func (_mock *Service) ListDomains(ctx context.Context, sesssion authn.Session, page domains.Page) (domains.DomainsPage, error) {
ret := _mock.Called(ctx, sesssion, page)
+5 -5
View File
@@ -157,7 +157,7 @@ func TestSaveInvitation(t *testing.T) {
}
}
func TestInvitationRetrieve(t *testing.T) {
func TestRetrieveInvitation(t *testing.T) {
t.Cleanup(func() {
_, err := db.Exec("DELETE FROM invitations")
require.Nil(t, err, fmt.Sprintf("clean invitations unexpected error: %s", err))
@@ -245,7 +245,7 @@ func TestInvitationRetrieve(t *testing.T) {
}
}
func TestInvitationRetrieveAll(t *testing.T) {
func TestRetrieveAllInvitations(t *testing.T) {
t.Cleanup(func() {
_, err := db.Exec("DELETE FROM invitations")
require.Nil(t, err, fmt.Sprintf("clean invitations unexpected error: %s", err))
@@ -633,7 +633,7 @@ func TestInvitationRetrieveAll(t *testing.T) {
}
}
func TestInvitationUpdateConfirmation(t *testing.T) {
func TestUpdateConfirmation(t *testing.T) {
t.Cleanup(func() {
_, err := db.Exec("DELETE FROM invitations")
require.Nil(t, err, fmt.Sprintf("clean invitations unexpected error: %s", err))
@@ -697,7 +697,7 @@ func TestInvitationUpdateConfirmation(t *testing.T) {
}
}
func TestInvitationUpdateRejection(t *testing.T) {
func TestUpdateRejection(t *testing.T) {
t.Cleanup(func() {
_, err := db.Exec("DELETE FROM invitations")
require.Nil(t, err, fmt.Sprintf("clean invitations unexpected error: %s", err))
@@ -761,7 +761,7 @@ func TestInvitationUpdateRejection(t *testing.T) {
}
}
func TestInvitationDelete(t *testing.T) {
func TestDeleteInvitation(t *testing.T) {
t.Cleanup(func() {
_, err := db.Exec("DELETE FROM invitations")
require.Nil(t, err, fmt.Sprintf("clean invitations unexpected error: %s", err))
+2
View File
@@ -20,6 +20,7 @@ const (
OpListDomains
OpViewInvitation
OpListInvitations
OpListDomainInvitations
OpRejectInvitation
OpDeleteInvitation
)
@@ -43,6 +44,7 @@ var OperationNames = []string{
"OpListDomains",
"OpViewInvitation",
"OpListInvitations",
"OpListDomainInvitations",
"OpRejectInvitation",
"OpDeleteInvitation",
}
+11 -1
View File
@@ -244,9 +244,19 @@ func (svc *service) ViewInvitation(ctx context.Context, session authn.Session, i
}
func (svc *service) ListInvitations(ctx context.Context, session authn.Session, page InvitationPageMeta) (invitations InvitationPage, err error) {
page.InviteeUserID = session.UserID
ip, err := svc.repo.RetrieveAllInvitations(ctx, page)
if err != nil {
return InvitationPage{}, err
return InvitationPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
}
return ip, nil
}
func (svc *service) ListDomainInvitations(ctx context.Context, session authn.Session, page InvitationPageMeta) (invitations InvitationPage, err error) {
page.DomainID = session.DomainID
ip, err := svc.repo.RetrieveAllInvitations(ctx, page)
if err != nil {
return InvitationPage{}, errors.Wrap(svcerr.ErrViewEntity, err)
}
return ip, nil
}
+65 -2
View File
@@ -829,7 +829,7 @@ func TestListInvitations(t *testing.T) {
desc: "list invitations unsuccessful",
session: validSession,
page: validPageMeta,
err: repoerr.ErrViewEntity,
err: svcerr.ErrViewEntity,
resp: domains.InvitationPage{},
repoErr: repoerr.ErrViewEntity,
},
@@ -839,7 +839,70 @@ func TestListInvitations(t *testing.T) {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("RetrieveAllInvitations", context.Background(), mock.Anything).Return(tc.resp, tc.repoErr)
resp, err := svc.ListInvitations(context.Background(), tc.session, tc.page)
assert.Equal(t, tc.err, err, tc.desc)
assert.True(t, errors.Contains(err, tc.err), tc.desc)
assert.Equal(t, tc.resp, resp, tc.desc)
repoCall.Unset()
})
}
}
func TestListDomainInvitations(t *testing.T) {
svc := newService()
validPageMeta := domains.InvitationPageMeta{
Offset: 0,
Limit: 10,
}
validResp := domains.InvitationPage{
Total: 1,
Offset: 0,
Limit: 10,
Invitations: []domains.Invitation{
{
InvitedBy: testsutil.GenerateUUID(t),
InviteeUserID: testsutil.GenerateUUID(t),
DomainID: testsutil.GenerateUUID(t),
RoleID: testsutil.GenerateUUID(t),
RoleName: "admin",
CreatedAt: time.Now().Add(-time.Hour),
UpdatedAt: time.Now().Add(-time.Hour),
ConfirmedAt: time.Now().Add(-time.Hour),
},
},
}
cases := []struct {
desc string
session authn.Session
page domains.InvitationPageMeta
resp domains.InvitationPage
repoErr error
err error
}{
{
desc: "list domain invitations successful",
session: validSession,
page: validPageMeta,
resp: validResp,
repoErr: nil,
err: nil,
},
{
desc: "list domain invitations unsuccessful",
session: validSession,
page: validPageMeta,
resp: domains.InvitationPage{},
repoErr: repoerr.ErrViewEntity,
err: svcerr.ErrViewEntity,
},
}
for _, tc := range cases {
t.Run(tc.desc, func(t *testing.T) {
repoCall := drepo.On("RetrieveAllInvitations", context.Background(), mock.Anything).Return(tc.resp, tc.repoErr)
resp, err := svc.ListDomainInvitations(context.Background(), tc.session, tc.page)
assert.True(t, errors.Contains(err, tc.err), tc.desc)
assert.Equal(t, tc.resp, resp, tc.desc)
repoCall.Unset()
})
+6 -6
View File
@@ -22,11 +22,11 @@ const (
// String representation of the possible state values.
const (
all = "all"
pending = "pending"
accepted = "accepted"
rejected = "rejected"
unknown = "unknown"
all = "all"
pending = "pending"
accepted = "accepted"
rejected = "rejected"
UnknownState = "unknown"
)
// String converts invitation state to string literal.
@@ -41,7 +41,7 @@ func (s State) String() string {
case Rejected:
return rejected
default:
return unknown
return UnknownState
}
}
+11
View File
@@ -116,6 +116,17 @@ func (tm *tracingMiddleware) ListInvitations(ctx context.Context, session authn.
return tm.svc.ListInvitations(ctx, session, pm)
}
func (tm *tracingMiddleware) ListDomainInvitations(ctx context.Context, session authn.Session, pm domains.InvitationPageMeta) (invs domains.InvitationPage, err error) {
ctx, span := tracing.StartSpan(ctx, tm.tracer, "list_domain_invitations", trace.WithAttributes(
attribute.Int("limit", int(pm.Limit)),
attribute.Int("offset", int(pm.Offset)),
attribute.String("domain_id", session.DomainID),
))
defer span.End()
return tm.svc.ListDomainInvitations(ctx, session, pm)
}
func (tm *tracingMiddleware) AcceptInvitation(ctx context.Context, session authn.Session, domainID string) (inv domains.Invitation, err error) {
ctx, span := tracing.StartSpan(ctx, tm.tracer, "accept_invitation", trace.WithAttributes(
attribute.String("domain_id", domainID),