satellite/console/.../consoleql: add project invite expiration status
Each project member invitation returned from our GraphQL API now contains a field indicating whether the invitation has expired. This is required for us to enable functionality in the satellite frontend that is dependent on this information. References #5752 Change-Id: I4b71738e7a7373c690de188614f8c95009bc3989
This commit is contained in:
parent
d18f4f7d99
commit
28b2384970
@ -166,9 +166,18 @@ func graphqlProject(service *console.Service, types *TypeCreator) *graphql.Objec
|
||||
})
|
||||
}
|
||||
|
||||
var invites []projectInvitation
|
||||
for _, invite := range page.ProjectInvitations {
|
||||
invites = append(invites, projectInvitation{
|
||||
Email: invite.Email,
|
||||
CreatedAt: invite.CreatedAt,
|
||||
Expired: service.IsProjectInvitationExpired(&invite),
|
||||
})
|
||||
}
|
||||
|
||||
projectMembersPage := projectMembersPage{
|
||||
ProjectMembers: users,
|
||||
ProjectInvitations: page.ProjectInvitations,
|
||||
ProjectInvitations: invites,
|
||||
TotalCount: page.TotalCount,
|
||||
Offset: page.Offset,
|
||||
Limit: page.Limit,
|
||||
|
@ -18,6 +18,8 @@ const (
|
||||
ProjectInvitationType = "projectInvitation"
|
||||
// FieldJoinedAt is a field name for joined at timestamp.
|
||||
FieldJoinedAt = "joinedAt"
|
||||
// FieldExpired is a field name for expiration status.
|
||||
FieldExpired = "expired"
|
||||
)
|
||||
|
||||
// graphqlProjectMember creates projectMember type.
|
||||
@ -51,6 +53,9 @@ func graphqlProjectInvitation() *graphql.Object {
|
||||
FieldCreatedAt: &graphql.Field{
|
||||
Type: graphql.DateTime,
|
||||
},
|
||||
FieldExpired: &graphql.Field{
|
||||
Type: graphql.Boolean,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@ -122,9 +127,16 @@ type projectMember struct {
|
||||
JoinedAt time.Time
|
||||
}
|
||||
|
||||
// projectInvitation encapsulates a console.ProjectInvitation and its expiration status.
|
||||
type projectInvitation struct {
|
||||
Email string
|
||||
CreatedAt time.Time
|
||||
Expired bool
|
||||
}
|
||||
|
||||
type projectMembersPage struct {
|
||||
ProjectMembers []projectMember
|
||||
ProjectInvitations []console.ProjectInvitation
|
||||
ProjectInvitations []projectInvitation
|
||||
|
||||
Search string
|
||||
Limit uint
|
||||
|
@ -3471,7 +3471,7 @@ func (s *Service) GetUserProjectInvitations(ctx context.Context) (_ []ProjectInv
|
||||
|
||||
var active []ProjectInvitation
|
||||
for _, invite := range invites {
|
||||
if !time.Now().After(invite.CreatedAt.Add(s.config.ProjectInvitationExpiration)) {
|
||||
if !s.IsProjectInvitationExpired(&invite) {
|
||||
active = append(active, invite)
|
||||
}
|
||||
}
|
||||
@ -3544,7 +3544,7 @@ func (s *Service) RespondToProjectInvitation(ctx context.Context, projectID uuid
|
||||
return ErrProjectInviteInvalid.New(projInviteInvalidErrMsg)
|
||||
}
|
||||
|
||||
if time.Now().After(invite.CreatedAt.Add(s.config.ProjectInvitationExpiration)) {
|
||||
if s.IsProjectInvitationExpired(invite) {
|
||||
deleteWithLog()
|
||||
return ErrProjectInviteInvalid.New(projInviteInvalidErrMsg)
|
||||
}
|
||||
@ -3596,7 +3596,7 @@ func (s *Service) InviteProjectMembers(ctx context.Context, projectID uuid.UUID,
|
||||
if err != nil && !errs.Is(err, sql.ErrNoRows) {
|
||||
return nil, Error.Wrap(err)
|
||||
}
|
||||
if invite != nil && !time.Now().After(invite.CreatedAt.Add(s.config.ProjectInvitationExpiration)) {
|
||||
if invite != nil && !s.IsProjectInvitationExpired(invite) {
|
||||
return nil, ErrProjectInviteActive.New(projInviteActiveErrMsg, invitedUser.Email)
|
||||
}
|
||||
users = append(users, invitedUser)
|
||||
@ -3662,6 +3662,11 @@ func (s *Service) InviteProjectMembers(ctx context.Context, projectID uuid.UUID,
|
||||
return invites, nil
|
||||
}
|
||||
|
||||
// IsProjectInvitationExpired returns whether the project member invitation has expired.
|
||||
func (s *Service) IsProjectInvitationExpired(invite *ProjectInvitation) bool {
|
||||
return time.Now().After(invite.CreatedAt.Add(s.config.ProjectInvitationExpiration))
|
||||
}
|
||||
|
||||
// GetInviteByToken returns a project invite given an invite token.
|
||||
func (s *Service) GetInviteByToken(ctx context.Context, token string) (invite *ProjectInvitation, err error) {
|
||||
defer mon.Task()(&ctx)(&err)
|
||||
@ -3686,7 +3691,7 @@ func (s *Service) GetInviteByToken(ctx context.Context, token string) (invite *P
|
||||
}
|
||||
return nil, ErrProjectInviteInvalid.New(projInviteInvalidErrMsg)
|
||||
}
|
||||
if time.Now().After(invite.CreatedAt.Add(s.config.ProjectInvitationExpiration)) {
|
||||
if s.IsProjectInvitationExpired(invite) {
|
||||
return nil, ErrProjectInviteInvalid.New(projInviteInvalidErrMsg)
|
||||
}
|
||||
|
||||
|
@ -1987,10 +1987,11 @@ func TestProjectInvitations(t *testing.T) {
|
||||
|
||||
expireInvite := func(t *testing.T, ctx context.Context, invite *console.ProjectInvitation) {
|
||||
createdAt := time.Now().Add(-sat.Config.Console.ProjectInvitationExpiration)
|
||||
_, err := sat.DB.Console().ProjectInvitations().Update(ctx, invite.ProjectID, invite.Email, console.UpdateProjectInvitationRequest{
|
||||
newInvite, err := sat.DB.Console().ProjectInvitations().Update(ctx, invite.ProjectID, invite.Email, console.UpdateProjectInvitationRequest{
|
||||
CreatedAt: &createdAt,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
*invite = *newInvite
|
||||
}
|
||||
|
||||
t.Run("invite users", func(t *testing.T) {
|
||||
@ -2031,13 +2032,18 @@ func TestProjectInvitations(t *testing.T) {
|
||||
require.True(t, console.ErrProjectInviteActive.Has(err))
|
||||
require.Empty(t, invites)
|
||||
|
||||
// resending an expired invitation should succeed.
|
||||
// expire the invitation.
|
||||
require.False(t, service.IsProjectInvitationExpired(&user3Invite))
|
||||
oldCreatedAt := user3Invite.CreatedAt
|
||||
expireInvite(t, ctx, &user3Invite)
|
||||
require.True(t, service.IsProjectInvitationExpired(&user3Invite))
|
||||
|
||||
// resending an expired invitation should succeed.
|
||||
invites, err = service.InviteProjectMembers(ctx2, project.ID, []string{user3.Email})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, invites, 1)
|
||||
require.Equal(t, user2.ID, *invites[0].InviterID)
|
||||
require.True(t, invites[0].CreatedAt.After(user3Invite.CreatedAt))
|
||||
require.True(t, invites[0].CreatedAt.After(oldCreatedAt))
|
||||
|
||||
// inviting a project member should fail.
|
||||
_, err = service.InviteProjectMembers(ctx, project.ID, []string{user2.Email})
|
||||
|
@ -64,7 +64,8 @@ export class ProjectMembersApiGql extends BaseGql implements ProjectMembersApi {
|
||||
},
|
||||
projectInvitations {
|
||||
email,
|
||||
createdAt
|
||||
createdAt,
|
||||
expired
|
||||
},
|
||||
search,
|
||||
limit,
|
||||
@ -127,6 +128,7 @@ export class ProjectMembersApiGql extends BaseGql implements ProjectMembersApi {
|
||||
projectMembersPage.projectInvitations = projectMembers.projectInvitations.map(key => new ProjectInvitationItemModel(
|
||||
key.email,
|
||||
new Date(key.createdAt),
|
||||
key.expired,
|
||||
));
|
||||
|
||||
projectMembersPage.search = projectMembers.search;
|
||||
|
@ -231,6 +231,7 @@ export class ProjectInvitationItemModel implements ProjectMemberItemModel {
|
||||
public constructor(
|
||||
public email: string,
|
||||
public createdAt: Date,
|
||||
public expired: boolean,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user