satellite/console: delete project invitations with project members

The console service method responsible for removing members from a
project has been extended to remove project member invitations as well.
This will allow invitations to be deleted through the satellite
frontend.

References #5855

Change-Id: I90ca042cc6fb9a75fcd9b391e317caabb1c828f2
This commit is contained in:
Jeremy Wharton 2023-06-08 01:34:55 -05:00 committed by Storj Robot
parent 2ab6e00966
commit 0cbb0ee12e
4 changed files with 161 additions and 114 deletions

View File

@ -241,7 +241,7 @@ func rootMutation(log *zap.Logger, service *console.Service, mailService *mailse
return nil, err
}
err = service.DeleteProjectMembers(p.Context, project.ID, userEmails)
err = service.DeleteProjectMembersAndInvitations(p.Context, project.ID, userEmails)
if err != nil {
return nil, err
}

View File

@ -67,15 +67,14 @@ const (
projectOwnerDeletionForbiddenErrMsg = "%s is a project owner and can not be deleted"
apiKeyWithNameExistsErrMsg = "An API Key with this name already exists in this project, please use a different name"
apiKeyWithNameDoesntExistErrMsg = "An API Key with this name doesn't exist in this project."
teamMemberDoesNotExistErrMsg = `There is no account on this Satellite for the user(s) you have entered.
Please add team members with active accounts`
activationTokenExpiredErrMsg = "This activation token has expired, please request another one"
usedRegTokenErrMsg = "This registration token has already been used"
projLimitErrMsg = "Sorry, project creation is limited for your account. Please contact support!"
projNameErrMsg = "The new project must have a name you haven't used before!"
projInviteInvalidErrMsg = "The invitation has expired or is invalid"
projInviteAlreadyMemberErrMsg = "You are already a member of the project"
projInviteResponseInvalidErrMsg = "Invalid project member invitation response"
teamMemberDoesNotExistErrMsg = "There are no team members with the email '%s'. Please try again."
activationTokenExpiredErrMsg = "This activation token has expired, please request another one"
usedRegTokenErrMsg = "This registration token has already been used"
projLimitErrMsg = "Sorry, project creation is limited for your account. Please contact support!"
projNameErrMsg = "The new project must have a name you haven't used before!"
projInviteInvalidErrMsg = "The invitation has expired or is invalid"
projInviteAlreadyMemberErrMsg = "You are already a member of the project"
projInviteResponseInvalidErrMsg = "Invalid project member invitation response"
)
var (
@ -2042,9 +2041,9 @@ func (s *Service) AddProjectMembers(ctx context.Context, projectID uuid.UUID, em
return users, nil
}
// DeleteProjectMembers removes users by email from given project.
// DeleteProjectMembersAndInvitations removes users and invitations by email from given project.
// projectID here may be project.PublicID or project.ID.
func (s *Service) DeleteProjectMembers(ctx context.Context, projectID uuid.UUID, emails []string) (err error) {
func (s *Service) DeleteProjectMembersAndInvitations(ctx context.Context, projectID uuid.UUID, emails []string) (err error) {
defer mon.Task()(&ctx)(&err)
user, err := s.getUserAndAuditLog(ctx, "delete project members", zap.String("projectID", projectID.String()), zap.Strings("emails", emails))
if err != nil {
@ -2059,13 +2058,24 @@ func (s *Service) DeleteProjectMembers(ctx context.Context, projectID uuid.UUID,
projectID = isMember.project.ID
var userIDs []uuid.UUID
var userErr errs.Group
var invitedEmails []string
// collect user querying errors
for _, email := range emails {
invite, err := s.store.ProjectInvitations().Get(ctx, projectID, email)
if err == nil {
invitedEmails = append(invitedEmails, email)
continue
}
if !errs.Is(err, sql.ErrNoRows) {
return Error.Wrap(err)
}
user, err := s.store.Users().GetByEmail(ctx, email)
if err != nil {
userErr.Add(err)
if invite == nil {
return ErrValidation.New(teamMemberDoesNotExistErrMsg, email)
}
invitedEmails = append(invitedEmails, email)
continue
}
@ -2080,18 +2090,20 @@ func (s *Service) DeleteProjectMembers(ctx context.Context, projectID uuid.UUID,
userIDs = append(userIDs, user.ID)
}
if err = userErr.Err(); err != nil {
return ErrValidation.New(teamMemberDoesNotExistErrMsg)
}
// delete project members in transaction scope
err = s.store.WithTx(ctx, func(ctx context.Context, tx DBTx) error {
err = s.store.WithTx(ctx, func(ctx context.Context, tx DBTx) (err error) {
for _, uID := range userIDs {
err = tx.ProjectMembers().Delete(ctx, uID, projectID)
if err != nil {
return err
}
}
for _, email := range invitedEmails {
err = tx.ProjectInvitations().Delete(ctx, projectID, email)
if err != nil {
return err
}
}
return nil
})

View File

@ -53,43 +53,48 @@ func TestService(t *testing.T) {
sat := planet.Satellites[0]
service := sat.API.Console.Service
up1Pro1, err := sat.API.DB.Console().Projects().Get(ctx, planet.Uplinks[0].Projects[0].ID)
up1Proj, err := sat.API.DB.Console().Projects().Get(ctx, planet.Uplinks[0].Projects[0].ID)
require.NoError(t, err)
up2Pro1, err := sat.API.DB.Console().Projects().Get(ctx, planet.Uplinks[1].Projects[0].ID)
up2Proj, err := sat.API.DB.Console().Projects().Get(ctx, planet.Uplinks[1].Projects[0].ID)
require.NoError(t, err)
up2User, err := sat.API.DB.Console().Users().Get(ctx, up2Pro1.OwnerID)
require.NotEqual(t, up1Proj.ID, up2Proj.ID)
require.NotEqual(t, up1Proj.OwnerID, up2Proj.OwnerID)
userCtx1, err := sat.UserContext(ctx, up1Proj.OwnerID)
require.NoError(t, err)
require.NotEqual(t, up1Pro1.ID, up2Pro1.ID)
require.NotEqual(t, up1Pro1.OwnerID, up2Pro1.OwnerID)
userCtx1, err := sat.UserContext(ctx, up1Pro1.OwnerID)
userCtx2, err := sat.UserContext(ctx, up2Proj.OwnerID)
require.NoError(t, err)
userCtx2, err := sat.UserContext(ctx, up2Pro1.OwnerID)
require.NoError(t, err)
getOwnerAndCtx := func(ctx context.Context, proj *console.Project) (user *console.User, userCtx context.Context) {
user, err := sat.API.DB.Console().Users().Get(ctx, proj.OwnerID)
require.NoError(t, err)
userCtx, err = sat.UserContext(ctx, user.ID)
require.NoError(t, err)
return
}
t.Run("GetProject", func(t *testing.T) {
// Getting own project details should work
project, err := service.GetProject(userCtx1, up1Pro1.ID)
project, err := service.GetProject(userCtx1, up1Proj.ID)
require.NoError(t, err)
require.Equal(t, up1Pro1.ID, project.ID)
require.Equal(t, up1Proj.ID, project.ID)
// Getting someone else project details should not work
project, err = service.GetProject(userCtx1, up2Pro1.ID)
project, err = service.GetProject(userCtx1, up2Proj.ID)
require.Error(t, err)
require.Nil(t, project)
})
t.Run("GetSalt", func(t *testing.T) {
// Getting project salt as a member should work
salt, err := service.GetSalt(userCtx1, up1Pro1.ID)
salt, err := service.GetSalt(userCtx1, up1Proj.ID)
require.NoError(t, err)
require.NotNil(t, salt)
// Getting project salt with publicID should work
salt1, err := service.GetSalt(userCtx1, up1Pro1.PublicID)
salt1, err := service.GetSalt(userCtx1, up1Proj.PublicID)
require.NoError(t, err)
require.NotNil(t, salt1)
@ -97,19 +102,15 @@ func TestService(t *testing.T) {
require.Equal(t, salt, salt1)
// Getting project salt as a non-member should not work
salt, err = service.GetSalt(userCtx1, up2Pro1.ID)
salt, err = service.GetSalt(userCtx1, up2Proj.ID)
require.Error(t, err)
require.Nil(t, salt)
})
t.Run("AddCreditCard fails when payments.CreditCards.Add returns error", func(t *testing.T) {
// user should be in free tier
user, err := service.GetUser(ctx, up1Pro1.OwnerID)
require.NoError(t, err)
user, userCtx1 := getOwnerAndCtx(ctx, up1Proj)
require.False(t, user.PaidTier)
// get context
userCtx1, err := sat.UserContext(ctx, user.ID)
require.NoError(t, err)
// stripecoinpayments.TestPaymentMethodsAttachFailure triggers the underlying mock stripe client to return an error
// when attaching a payment method to a customer.
@ -117,7 +118,7 @@ func TestService(t *testing.T) {
require.Error(t, err)
// user still in free tier
user, err = service.GetUser(ctx, up1Pro1.OwnerID)
user, err = service.GetUser(ctx, up1Proj.OwnerID)
require.NoError(t, err)
require.False(t, user.PaidTier)
@ -128,18 +129,15 @@ func TestService(t *testing.T) {
t.Run("AddCreditCard", func(t *testing.T) {
// user should be in free tier
user, err := service.GetUser(ctx, up1Pro1.OwnerID)
require.NoError(t, err)
user, userCtx1 := getOwnerAndCtx(ctx, up1Proj)
require.False(t, user.PaidTier)
// get context
userCtx1, err := sat.UserContext(ctx, user.ID)
require.NoError(t, err)
// add a credit card to put the user in the paid tier
card, err := service.Payments().AddCreditCard(userCtx1, "test-cc-token")
require.NoError(t, err)
require.NotEmpty(t, card)
// user should be in paid tier
user, err = service.GetUser(ctx, up1Pro1.OwnerID)
user, err = service.GetUser(ctx, up1Proj.OwnerID)
require.NoError(t, err)
require.True(t, user.PaidTier)
@ -151,7 +149,7 @@ func TestService(t *testing.T) {
t.Run("CreateProject", func(t *testing.T) {
// Creating a project with a previously used name should fail
createdProject, err := service.CreateProject(userCtx1, console.ProjectInfo{
Name: up1Pro1.Name,
Name: up1Proj.Name,
})
require.Error(t, err)
require.Nil(t, createdProject)
@ -186,33 +184,29 @@ func TestService(t *testing.T) {
updatedStorageLimit := memory.Size(100)
updatedBandwidthLimit := memory.Size(100)
user, err := service.GetUser(ctx, up1Pro1.OwnerID)
require.NoError(t, err)
userCtx1, err := sat.UserContext(ctx, user.ID)
require.NoError(t, err)
_, userCtx1 := getOwnerAndCtx(ctx, up1Proj)
// Updating own project should work
updatedProject, err := service.UpdateProject(userCtx1, up1Pro1.ID, console.ProjectInfo{
updatedProject, err := service.UpdateProject(userCtx1, up1Proj.ID, console.ProjectInfo{
Name: updatedName,
Description: updatedDescription,
StorageLimit: updatedStorageLimit,
BandwidthLimit: updatedBandwidthLimit,
})
require.NoError(t, err)
require.NotEqual(t, up1Pro1.Name, updatedProject.Name)
require.NotEqual(t, up1Proj.Name, updatedProject.Name)
require.Equal(t, updatedName, updatedProject.Name)
require.NotEqual(t, up1Pro1.Description, updatedProject.Description)
require.NotEqual(t, up1Proj.Description, updatedProject.Description)
require.Equal(t, updatedDescription, updatedProject.Description)
require.NotEqual(t, *up1Pro1.StorageLimit, *updatedProject.StorageLimit)
require.NotEqual(t, *up1Proj.StorageLimit, *updatedProject.StorageLimit)
require.Equal(t, updatedStorageLimit, *updatedProject.StorageLimit)
require.NotEqual(t, *up1Pro1.BandwidthLimit, *updatedProject.BandwidthLimit)
require.NotEqual(t, *up1Proj.BandwidthLimit, *updatedProject.BandwidthLimit)
require.Equal(t, updatedBandwidthLimit, *updatedProject.BandwidthLimit)
require.Equal(t, updatedStorageLimit, *updatedProject.UserSpecifiedStorageLimit)
require.Equal(t, updatedBandwidthLimit, *updatedProject.UserSpecifiedBandwidthLimit)
// Updating someone else project details should not work
updatedProject, err = service.UpdateProject(userCtx1, up2Pro1.ID, console.ProjectInfo{
updatedProject, err = service.UpdateProject(userCtx1, up2Proj.ID, console.ProjectInfo{
Name: "newName",
Description: "TestUpdate",
StorageLimit: memory.Size(100),
@ -227,8 +221,8 @@ func TestService(t *testing.T) {
size100 := new(memory.Size)
*size100 = memory.Size(100)
up1Pro1.StorageLimit = size0
err = sat.DB.Console().Projects().Update(ctx, up1Pro1)
up1Proj.StorageLimit = size0
err = sat.DB.Console().Projects().Update(ctx, up1Proj)
require.NoError(t, err)
updateInfo := console.ProjectInfo{
@ -237,26 +231,26 @@ func TestService(t *testing.T) {
StorageLimit: memory.Size(123),
BandwidthLimit: memory.Size(123),
}
updatedProject, err = service.UpdateProject(userCtx1, up1Pro1.ID, updateInfo)
updatedProject, err = service.UpdateProject(userCtx1, up1Proj.ID, updateInfo)
require.Error(t, err)
require.Nil(t, updatedProject)
up1Pro1.StorageLimit = size100
up1Pro1.BandwidthLimit = size0
up1Proj.StorageLimit = size100
up1Proj.BandwidthLimit = size0
err = sat.DB.Console().Projects().Update(ctx, up1Pro1)
err = sat.DB.Console().Projects().Update(ctx, up1Proj)
require.NoError(t, err)
updatedProject, err = service.UpdateProject(userCtx1, up1Pro1.ID, updateInfo)
updatedProject, err = service.UpdateProject(userCtx1, up1Proj.ID, updateInfo)
require.Error(t, err)
require.Nil(t, updatedProject)
up1Pro1.StorageLimit = size100
up1Pro1.BandwidthLimit = size100
err = sat.DB.Console().Projects().Update(ctx, up1Pro1)
up1Proj.StorageLimit = size100
up1Proj.BandwidthLimit = size100
err = sat.DB.Console().Projects().Update(ctx, up1Proj)
require.NoError(t, err)
updatedProject, err = service.UpdateProject(userCtx1, up1Pro1.ID, updateInfo)
updatedProject, err = service.UpdateProject(userCtx1, up1Proj.ID, updateInfo)
require.NoError(t, err)
require.Equal(t, updateInfo.Name, updatedProject.Name)
require.Equal(t, updateInfo.Description, updatedProject.Description)
@ -265,65 +259,102 @@ func TestService(t *testing.T) {
require.Equal(t, updateInfo.StorageLimit, *updatedProject.StorageLimit)
require.Equal(t, updateInfo.BandwidthLimit, *updatedProject.BandwidthLimit)
project, err := service.GetProject(userCtx1, up1Pro1.ID)
project, err := service.GetProject(userCtx1, up1Proj.ID)
require.NoError(t, err)
require.Equal(t, updateInfo.StorageLimit, *project.StorageLimit)
require.Equal(t, updateInfo.BandwidthLimit, *project.BandwidthLimit)
// attempting to update a project with a previously used name should fail
updatedProject, err = service.UpdateProject(userCtx1, up2Pro1.ID, console.ProjectInfo{
Name: up1Pro1.Name,
updatedProject, err = service.UpdateProject(userCtx1, up2Proj.ID, console.ProjectInfo{
Name: up1Proj.Name,
})
require.Error(t, err)
require.Nil(t, updatedProject)
})
t.Run("AddProjectMembers", func(t *testing.T) {
up2User, _ := getOwnerAndCtx(ctx, up2Proj)
// Adding members to own project should work
addedUsers, err := service.AddProjectMembers(userCtx1, up1Pro1.ID, []string{up2User.Email})
addedUsers, err := service.AddProjectMembers(userCtx1, up1Proj.ID, []string{up2User.Email})
require.NoError(t, err)
require.Len(t, addedUsers, 1)
require.Contains(t, addedUsers, up2User)
// Adding members to someone else project should not work
addedUsers, err = service.AddProjectMembers(userCtx1, up2Pro1.ID, []string{up2User.Email})
addedUsers, err = service.AddProjectMembers(userCtx1, up2Proj.ID, []string{up2User.Email})
require.Error(t, err)
require.Nil(t, addedUsers)
})
t.Run("GetProjectMembers", func(t *testing.T) {
// Getting the project members of an own project that one is a part of should work
userPage, err := service.GetProjectMembers(userCtx1, up1Pro1.ID, console.ProjectMembersCursor{Page: 1, Limit: 10})
userPage, err := service.GetProjectMembers(userCtx1, up1Proj.ID, console.ProjectMembersCursor{Page: 1, Limit: 10})
require.NoError(t, err)
require.Len(t, userPage.ProjectMembers, 2)
// Getting the project members of a foreign project that one is a part of should work
userPage, err = service.GetProjectMembers(userCtx2, up1Pro1.ID, console.ProjectMembersCursor{Page: 1, Limit: 10})
userPage, err = service.GetProjectMembers(userCtx2, up1Proj.ID, console.ProjectMembersCursor{Page: 1, Limit: 10})
require.NoError(t, err)
require.Len(t, userPage.ProjectMembers, 2)
// Getting the project members of a foreign project that one is not a part of should not work
userPage, err = service.GetProjectMembers(userCtx1, up2Pro1.ID, console.ProjectMembersCursor{Page: 1, Limit: 10})
userPage, err = service.GetProjectMembers(userCtx1, up2Proj.ID, console.ProjectMembersCursor{Page: 1, Limit: 10})
require.Error(t, err)
require.Nil(t, userPage)
})
t.Run("DeleteProjectMembers", func(t *testing.T) {
// Deleting project members of an own project should work
err := service.DeleteProjectMembers(userCtx1, up1Pro1.ID, []string{up2User.Email})
t.Run("DeleteProjectMembersAndInvitations", func(t *testing.T) {
user1, user1Ctx := getOwnerAndCtx(ctx, up1Proj)
_, user2Ctx := getOwnerAndCtx(ctx, up2Proj)
invitedUser, err := sat.AddUser(ctx, console.CreateUser{
FullName: "Test User",
Email: "test@mail.test",
}, 1)
require.NoError(t, err)
// Deleting Project members of someone else project should not work
err = service.DeleteProjectMembers(userCtx1, up2Pro1.ID, []string{up2User.Email})
for _, id := range []uuid.UUID{up1Proj.ID, up2Proj.ID} {
_, err = sat.DB.Console().ProjectInvitations().Insert(ctx, &console.ProjectInvitation{
ProjectID: id,
Email: invitedUser.Email,
})
require.NoError(t, err)
}
// You should not be able to remove someone from a project that you aren't a member of.
err = service.DeleteProjectMembersAndInvitations(user1Ctx, up2Proj.ID, []string{invitedUser.Email})
require.Error(t, err)
// Project owners should not be able to be removed.
err = service.DeleteProjectMembersAndInvitations(user2Ctx, up1Proj.ID, []string{user1.Email})
require.Error(t, err)
// An invalid email should cause the operation to fail.
err = service.DeleteProjectMembersAndInvitations(user2Ctx, up2Proj.ID, []string{invitedUser.Email, "nobody@mail.test"})
require.Error(t, err)
_, err = sat.DB.Console().ProjectInvitations().Get(ctx, up2Proj.ID, invitedUser.Email)
require.NoError(t, err)
// Members and invitations should be removed.
err = service.DeleteProjectMembersAndInvitations(user2Ctx, up2Proj.ID, []string{invitedUser.Email, user1.Email})
require.NoError(t, err)
_, err = sat.DB.Console().ProjectInvitations().Get(ctx, up2Proj.ID, invitedUser.Email)
require.ErrorIs(t, err, sql.ErrNoRows)
memberships, err := sat.DB.Console().ProjectMembers().GetByMemberID(ctx, user1.ID)
require.NoError(t, err)
require.Len(t, memberships, 1)
require.NotEqual(t, up2Proj.ID, memberships[0].ProjectID)
})
t.Run("DeleteProject", func(t *testing.T) {
// Deleting the own project should not work before deleting the API-Key
err := service.DeleteProject(userCtx1, up1Pro1.ID)
err := service.DeleteProject(userCtx1, up1Proj.ID)
require.Error(t, err)
keys, err := service.GetAPIKeys(userCtx1, up1Pro1.ID, console.APIKeyCursor{Page: 1, Limit: 10})
keys, err := service.GetAPIKeys(userCtx1, up1Proj.ID, console.APIKeyCursor{Page: 1, Limit: 10})
require.NoError(t, err)
require.Len(t, keys.APIKeys, 1)
@ -331,18 +362,18 @@ func TestService(t *testing.T) {
require.NoError(t, err)
// Deleting the own project should now work
err = service.DeleteProject(userCtx1, up1Pro1.ID)
err = service.DeleteProject(userCtx1, up1Proj.ID)
require.NoError(t, err)
// Deleting someone else project should not work
err = service.DeleteProject(userCtx1, up2Pro1.ID)
err = service.DeleteProject(userCtx1, up2Proj.ID)
require.Error(t, err)
err = planet.Uplinks[1].CreateBucket(ctx, sat, "testbucket")
require.NoError(t, err)
// deleting a project with a bucket should fail
err = service.DeleteProject(userCtx2, up2Pro1.ID)
err = service.DeleteProject(userCtx2, up2Proj.ID)
require.Error(t, err)
require.Equal(t, "console service: project usage: some buckets still exist", err.Error())
})
@ -351,12 +382,12 @@ func TestService(t *testing.T) {
bandwidthLimit := sat.Config.Console.UsageLimits.Bandwidth.Free
storageLimit := sat.Config.Console.UsageLimits.Storage.Free
limits1, err := service.GetProjectUsageLimits(userCtx2, up2Pro1.ID)
limits1, err := service.GetProjectUsageLimits(userCtx2, up2Proj.ID)
require.NoError(t, err)
require.NotNil(t, limits1)
// Get usage limits with publicID
limits2, err := service.GetProjectUsageLimits(userCtx2, up2Pro1.PublicID)
limits2, err := service.GetProjectUsageLimits(userCtx2, up2Proj.PublicID)
require.NoError(t, err)
require.NotNil(t, limits2)
@ -369,19 +400,19 @@ func TestService(t *testing.T) {
// update project's limits
updatedStorageLimit := memory.Size(100) + memory.TB
updatedBandwidthLimit := memory.Size(100) + memory.TB
up2Pro1.StorageLimit = new(memory.Size)
*up2Pro1.StorageLimit = updatedStorageLimit
up2Pro1.BandwidthLimit = new(memory.Size)
*up2Pro1.BandwidthLimit = updatedBandwidthLimit
err = sat.DB.Console().Projects().Update(ctx, up2Pro1)
up2Proj.StorageLimit = new(memory.Size)
*up2Proj.StorageLimit = updatedStorageLimit
up2Proj.BandwidthLimit = new(memory.Size)
*up2Proj.BandwidthLimit = updatedBandwidthLimit
err = sat.DB.Console().Projects().Update(ctx, up2Proj)
require.NoError(t, err)
limits1, err = service.GetProjectUsageLimits(userCtx2, up2Pro1.ID)
limits1, err = service.GetProjectUsageLimits(userCtx2, up2Proj.ID)
require.NoError(t, err)
require.NotNil(t, limits1)
// Get usage limits with publicID
limits2, err = service.GetProjectUsageLimits(userCtx2, up2Pro1.PublicID)
limits2, err = service.GetProjectUsageLimits(userCtx2, up2Proj.PublicID)
require.NoError(t, err)
require.NotNil(t, limits2)
@ -410,13 +441,13 @@ func TestService(t *testing.T) {
bucket1 := buckets.Bucket{
ID: testrand.UUID(),
Name: "testBucket1",
ProjectID: up2Pro1.ID,
ProjectID: up2Proj.ID,
}
bucket2 := buckets.Bucket{
ID: testrand.UUID(),
Name: "testBucket2",
ProjectID: up2Pro1.ID,
ProjectID: up2Proj.ID,
}
_, err := sat.API.Buckets.Service.CreateBucket(userCtx2, bucket1)
@ -425,18 +456,18 @@ func TestService(t *testing.T) {
_, err = sat.API.Buckets.Service.CreateBucket(userCtx2, bucket2)
require.NoError(t, err)
bucketNames, err := service.GetAllBucketNames(userCtx2, up2Pro1.ID)
bucketNames, err := service.GetAllBucketNames(userCtx2, up2Proj.ID)
require.NoError(t, err)
require.Equal(t, bucket1.Name, bucketNames[0])
require.Equal(t, bucket2.Name, bucketNames[1])
bucketNames, err = service.GetAllBucketNames(userCtx2, up2Pro1.PublicID)
bucketNames, err = service.GetAllBucketNames(userCtx2, up2Proj.PublicID)
require.NoError(t, err)
require.Equal(t, bucket1.Name, bucketNames[0])
require.Equal(t, bucket2.Name, bucketNames[1])
// Getting someone else buckets should not work
bucketsForUnauthorizedUser, err := service.GetAllBucketNames(userCtx1, up2Pro1.ID)
bucketsForUnauthorizedUser, err := service.GetAllBucketNames(userCtx1, up2Proj.ID)
require.Error(t, err)
require.Nil(t, bucketsForUnauthorizedUser)
})
@ -450,7 +481,7 @@ func TestService(t *testing.T) {
apikey := console.APIKeyInfo{
Name: "test",
ProjectID: up2Pro1.ID,
ProjectID: up2Proj.ID,
Secret: secret,
}
@ -462,10 +493,10 @@ func TestService(t *testing.T) {
require.NotNil(t, info)
// Deleting someone else api keys should not work
err = service.DeleteAPIKeyByNameAndProjectID(userCtx1, apikey.Name, up2Pro1.ID)
err = service.DeleteAPIKeyByNameAndProjectID(userCtx1, apikey.Name, up2Proj.ID)
require.Error(t, err)
err = service.DeleteAPIKeyByNameAndProjectID(userCtx2, apikey.Name, up2Pro1.ID)
err = service.DeleteAPIKeyByNameAndProjectID(userCtx2, apikey.Name, up2Proj.ID)
require.NoError(t, err)
info, err = sat.DB.Console().APIKeys().Get(ctx, createdKey.ID)
@ -481,7 +512,7 @@ func TestService(t *testing.T) {
require.NotNil(t, info)
// deleting by project.publicID
err = service.DeleteAPIKeyByNameAndProjectID(userCtx2, apikey.Name, up2Pro1.PublicID)
err = service.DeleteAPIKeyByNameAndProjectID(userCtx2, apikey.Name, up2Proj.PublicID)
require.NoError(t, err)
info, err = sat.DB.Console().APIKeys().Get(ctx, createdKey.ID)
@ -502,7 +533,7 @@ func TestService(t *testing.T) {
require.NotNil(t, coupon)
require.Equal(t, freeTier, coupon.ID)
coupon, err = sat.API.Payments.Accounts.Coupons().GetByUserID(ctx, up1Pro1.OwnerID)
coupon, err = sat.API.Payments.Accounts.Coupons().GetByUserID(ctx, up1Proj.OwnerID)
require.NoError(t, err)
require.Equal(t, freeTier, coupon.ID)
@ -519,7 +550,7 @@ func TestService(t *testing.T) {
require.NotNil(t, coupon)
require.Equal(t, id, coupon.ID)
coupon, err = sat.API.Payments.Accounts.Coupons().GetByUserID(ctx, up2Pro1.OwnerID)
coupon, err = sat.API.Payments.Accounts.Coupons().GetByUserID(ctx, up2Proj.OwnerID)
require.NoError(t, err)
require.Equal(t, id, coupon.ID)
})
@ -539,7 +570,7 @@ func TestService(t *testing.T) {
purchaseTime := time.Now()
check := func() {
dbPackagePlan, dbPurchaseTime, err := sat.DB.StripeCoinPayments().Customers().GetPackageInfo(ctx, up1Pro1.OwnerID)
dbPackagePlan, dbPurchaseTime, err := sat.DB.StripeCoinPayments().Customers().GetPackageInfo(ctx, up1Proj.OwnerID)
require.NoError(t, err)
require.NotNil(t, dbPackagePlan)
require.NotNil(t, dbPurchaseTime)
@ -559,7 +590,7 @@ func TestService(t *testing.T) {
})
t.Run("ApplyCredit fails when payments.Balances.ApplyCredit returns an error", func(t *testing.T) {
require.Error(t, service.Payments().ApplyCredit(userCtx1, 1000, stripe.MockCBTXsNewFailure))
btxs, err := sat.API.Payments.Accounts.Balances().ListTransactions(ctx, up1Pro1.OwnerID)
btxs, err := sat.API.Payments.Accounts.Balances().ListTransactions(ctx, up1Proj.OwnerID)
require.NoError(t, err)
require.Zero(t, len(btxs))
})
@ -567,7 +598,7 @@ func TestService(t *testing.T) {
amount := int64(1000)
desc := "test"
require.NoError(t, service.Payments().ApplyCredit(userCtx1, 1000, desc))
btxs, err := sat.API.Payments.Accounts.Balances().ListTransactions(ctx, up1Pro1.OwnerID)
btxs, err := sat.API.Payments.Accounts.Balances().ListTransactions(ctx, up1Proj.OwnerID)
require.NoError(t, err)
require.Len(t, btxs, 1)
require.Equal(t, amount, btxs[0].Amount)
@ -575,13 +606,13 @@ func TestService(t *testing.T) {
// test same description results in no new credit
require.NoError(t, service.Payments().ApplyCredit(userCtx1, 1000, desc))
btxs, err = sat.API.Payments.Accounts.Balances().ListTransactions(ctx, up1Pro1.OwnerID)
btxs, err = sat.API.Payments.Accounts.Balances().ListTransactions(ctx, up1Proj.OwnerID)
require.NoError(t, err)
require.Len(t, btxs, 1)
// test different description results in new credit
require.NoError(t, service.Payments().ApplyCredit(userCtx1, 1000, "new desc"))
btxs, err = sat.API.Payments.Accounts.Balances().ListTransactions(ctx, up1Pro1.OwnerID)
btxs, err = sat.API.Payments.Accounts.Balances().ListTransactions(ctx, up1Proj.OwnerID)
require.NoError(t, err)
require.Len(t, btxs, 2)
})

View File

@ -81,7 +81,11 @@ func TestProjectInvitations(t *testing.T) {
t.Run("get invitation", func(t *testing.T) {
ctx := testcontext.New(t)
other, err := invitesDB.Get(ctx, projID, email)
other, err := invitesDB.Get(ctx, projID, "nobody@mail.test")
require.ErrorIs(t, err, sql.ErrNoRows)
require.Nil(t, other)
other, err = invitesDB.Get(ctx, projID, email)
require.NoError(t, err)
require.Equal(t, invite, other)
})