Skip to content

Commit 7ced811

Browse files
authored
Merge pull request #399 from authorizerdev/feat/deativate-account
Add api to deactivate user account
2 parents ad41bcf + c1e1ee1 commit 7ced811

File tree

10 files changed

+183
-2
lines changed

10 files changed

+183
-2
lines changed

dashboard/src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ export const webhookEventNames = {
222222
'User deleted': 'user.deleted',
223223
'User access enabled': 'user.access_enabled',
224224
'User access revoked': 'user.access_revoked',
225+
'User deactivated': 'user.deactivated',
225226
};
226227

227228
export const emailTemplateEventNames = {

server/constants/webhook_event.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ const (
1515
UserAccessEnabledWebhookEvent = `user.access_enabled`
1616
// UserDeletedWebhookEvent name for user deleted event
1717
UserDeletedWebhookEvent = `user.deleted`
18+
// UserDeactivatedWebhookEvent name for user deactivated event
19+
UserDeactivatedWebhookEvent = `user.deactivated`
1820
)

server/graph/generated/generated.go

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

server/graph/schema.graphqls

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,7 @@ type Mutation {
587587
revoke(params: OAuthRevokeInput!): Response!
588588
verify_otp(params: VerifyOTPRequest!): AuthResponse!
589589
resend_otp(params: ResendOTPRequest!): Response!
590+
deactivate_account: Response!
590591
# admin only apis
591592
_delete_user(params: DeleteUserInput!): Response!
592593
_update_user(params: UpdateUserInput!): User!

server/graph/schema.resolvers.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package graph
55

66
import (
77
"context"
8+
"fmt"
89

910
"github.com/authorizerdev/authorizer/server/graph/generated"
1011
"github.com/authorizerdev/authorizer/server/graph/model"
@@ -81,6 +82,11 @@ func (r *mutationResolver) ResendOtp(ctx context.Context, params model.ResendOTP
8182
return resolvers.ResendOTPResolver(ctx, params)
8283
}
8384

85+
// DeactivateAccount is the resolver for the deactivate_account field.
86+
func (r *mutationResolver) DeactivateAccount(ctx context.Context) (*model.Response, error) {
87+
panic(fmt.Errorf("not implemented: DeactivateAccount - deactivate_account"))
88+
}
89+
8490
// DeleteUser is the resolver for the _delete_user field.
8591
func (r *mutationResolver) DeleteUser(ctx context.Context, params model.DeleteUserInput) (*model.Response, error) {
8692
return resolvers.DeleteUserResolver(ctx, params)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package resolvers
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/authorizerdev/authorizer/server/constants"
8+
"github.com/authorizerdev/authorizer/server/db"
9+
"github.com/authorizerdev/authorizer/server/graph/model"
10+
"github.com/authorizerdev/authorizer/server/memorystore"
11+
"github.com/authorizerdev/authorizer/server/token"
12+
"github.com/authorizerdev/authorizer/server/utils"
13+
log "github.com/sirupsen/logrus"
14+
)
15+
16+
// DeactivateAccountResolver is the resolver for the deactivate_account field.
17+
func DeactivateAccountResolver(ctx context.Context) (*model.Response, error) {
18+
var res *model.Response
19+
gc, err := utils.GinContextFromContext(ctx)
20+
if err != nil {
21+
log.Debug("Failed to get GinContext: ", err)
22+
return res, err
23+
}
24+
accessToken, err := token.GetAccessToken(gc)
25+
if err != nil {
26+
log.Debug("Failed to get access token: ", err)
27+
return res, err
28+
}
29+
claims, err := token.ValidateAccessToken(gc, accessToken)
30+
if err != nil {
31+
log.Debug("Failed to validate access token: ", err)
32+
return res, err
33+
}
34+
userID := claims["sub"].(string)
35+
log := log.WithFields(log.Fields{
36+
"user_id": userID,
37+
})
38+
user, err := db.Provider.GetUserByID(ctx, userID)
39+
if err != nil {
40+
log.Debug("Failed to get user by id: ", err)
41+
return res, err
42+
}
43+
now := time.Now().Unix()
44+
user.RevokedTimestamp = &now
45+
user, err = db.Provider.UpdateUser(ctx, user)
46+
if err != nil {
47+
log.Debug("Failed to update user: ", err)
48+
return res, err
49+
}
50+
go func() {
51+
memorystore.Provider.DeleteAllUserSessions(user.ID)
52+
utils.RegisterEvent(ctx, constants.UserDeactivatedWebhookEvent, "", user)
53+
}()
54+
res = &model.Response{
55+
Message: `user account deactivated successfully`,
56+
}
57+
return res, nil
58+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package test
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/authorizerdev/authorizer/server/constants"
8+
"github.com/authorizerdev/authorizer/server/db"
9+
"github.com/authorizerdev/authorizer/server/graph/model"
10+
"github.com/authorizerdev/authorizer/server/resolvers"
11+
"github.com/stretchr/testify/assert"
12+
)
13+
14+
func deactivateAccountTests(t *testing.T, s TestSetup) {
15+
t.Helper()
16+
t.Run(`should deactiavte the user account with access token only`, func(t *testing.T) {
17+
req, ctx := createContext(s)
18+
email := "deactiavte_account." + s.TestInfo.Email
19+
20+
resolvers.SignupResolver(ctx, model.SignUpInput{
21+
Email: email,
22+
Password: s.TestInfo.Password,
23+
ConfirmPassword: s.TestInfo.Password,
24+
})
25+
_, err := resolvers.DeactivateAccountResolver(ctx)
26+
assert.NotNil(t, err, "unauthorized")
27+
verificationRequest, err := db.Provider.GetVerificationRequestByEmail(ctx, email, constants.VerificationTypeBasicAuthSignup)
28+
assert.NoError(t, err)
29+
assert.NotNil(t, verificationRequest)
30+
verifyRes, err := resolvers.VerifyEmailResolver(ctx, model.VerifyEmailInput{
31+
Token: verificationRequest.Token,
32+
})
33+
assert.NoError(t, err)
34+
assert.NotNil(t, verifyRes)
35+
s.GinContext.Request.Header.Set("Authorization", "Bearer "+*verifyRes.AccessToken)
36+
ctx = context.WithValue(req.Context(), "GinContextKey", s.GinContext)
37+
_, err = resolvers.DeactivateAccountResolver(ctx)
38+
assert.NoError(t, err)
39+
s.GinContext.Request.Header.Set("Authorization", "")
40+
assert.Nil(t, err)
41+
_, err = resolvers.ProfileResolver(ctx)
42+
assert.NotNil(t, err, "unauthorized")
43+
cleanData(email)
44+
})
45+
}

server/test/integration_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ func TestResolvers(t *testing.T) {
143143
verifyOTPTest(t, s)
144144
resendOTPTest(t, s)
145145
validateSessionTests(t, s)
146+
deactivateAccountTests(t, s)
146147

147148
updateAllUsersTest(t, s)
148149
webhookLogsTest(t, s) // get logs after above resolver tests are done

server/test/test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func testSetup() TestSetup {
103103
Email: fmt.Sprintf("%[email protected]", time.Now().Unix()),
104104
Password: "Test@123",
105105
WebhookEndpoint: "https://62f93101e05644803533cf36.mockapi.io/authorizer/webhook",
106-
TestWebhookEventTypes: []string{constants.UserAccessEnabledWebhookEvent, constants.UserAccessRevokedWebhookEvent, constants.UserCreatedWebhookEvent, constants.UserDeletedWebhookEvent, constants.UserLoginWebhookEvent, constants.UserSignUpWebhookEvent},
106+
TestWebhookEventTypes: []string{constants.UserAccessEnabledWebhookEvent, constants.UserAccessRevokedWebhookEvent, constants.UserCreatedWebhookEvent, constants.UserDeletedWebhookEvent, constants.UserLoginWebhookEvent, constants.UserSignUpWebhookEvent, constants.UserDeactivatedWebhookEvent},
107107
TestEmailTemplateEventTypes: []string{constants.VerificationTypeBasicAuthSignup, constants.VerificationTypeForgotPassword, constants.VerificationTypeMagicLinkLogin, constants.VerificationTypeUpdateEmail},
108108
}
109109

server/validators/webhook.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import "github.com/authorizerdev/authorizer/server/constants"
44

55
// IsValidWebhookEventName to validate webhook event name
66
func IsValidWebhookEventName(eventName string) bool {
7-
if eventName != constants.UserCreatedWebhookEvent && eventName != constants.UserLoginWebhookEvent && eventName != constants.UserSignUpWebhookEvent && eventName != constants.UserDeletedWebhookEvent && eventName != constants.UserAccessEnabledWebhookEvent && eventName != constants.UserAccessRevokedWebhookEvent {
7+
if eventName != constants.UserCreatedWebhookEvent && eventName != constants.UserLoginWebhookEvent && eventName != constants.UserSignUpWebhookEvent && eventName != constants.UserDeletedWebhookEvent && eventName != constants.UserAccessEnabledWebhookEvent && eventName != constants.UserAccessRevokedWebhookEvent && eventName != constants.UserDeactivatedWebhookEvent {
88
return false
99
}
1010

0 commit comments

Comments
 (0)