-
Notifications
You must be signed in to change notification settings - Fork 5.4k
/
account.py
233 lines (185 loc) · 7.23 KB
/
account.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
import graphene
from django.contrib.auth.tokens import default_token_generator
from django.core.exceptions import ValidationError
from ....account import emails, events as account_events, models, utils
from ....checkout import AddressType
from ....core.utils.url import validate_storefront_url
from ...account.enums import AddressTypeEnum
from ...account.types import Address, AddressInput, User
from ...core.mutations import BaseMutation, ModelDeleteMutation, ModelMutation
from .base import (
INVALID_TOKEN,
BaseAddressDelete,
BaseAddressUpdate,
BaseCustomerCreate,
)
class AccountRegisterInput(graphene.InputObjectType):
email = graphene.String(description="The email address of the user.", required=True)
password = graphene.String(description="Password", required=True)
class AccountRegister(ModelMutation):
class Arguments:
input = AccountRegisterInput(
description="Fields required to create a user.", required=True
)
class Meta:
description = "Register a new user."
exclude = ["password"]
model = models.User
@classmethod
def save(cls, info, user, cleaned_input):
password = cleaned_input["password"]
user.set_password(password)
user.save()
account_events.customer_account_created_event(user=user)
class AccountInput(graphene.InputObjectType):
first_name = graphene.String(description="Given name.")
last_name = graphene.String(description="Family name.")
default_billing_address = AddressInput(
description="Billing address of the customer."
)
default_shipping_address = AddressInput(
description="Shipping address of the customer."
)
class AccountUpdate(BaseCustomerCreate):
class Arguments:
input = AccountInput(
description="Fields required to update the account of the logged-in user.",
required=True,
)
class Meta:
description = "Updates the account of the logged-in user."
exclude = ["password"]
model = models.User
@classmethod
def check_permissions(cls, user):
return user.is_authenticated
@classmethod
def perform_mutation(cls, root, info, **data):
user = info.context.user
data["id"] = graphene.Node.to_global_id("User", user.id)
return super().perform_mutation(root, info, **data)
class AccountRequestDeletion(BaseMutation):
class Arguments:
redirect_url = graphene.String(
required=True,
description=(
"URL of a view where users should be redirected to "
"delete their account. URL in RFC 1808 format.",
),
)
class Meta:
description = (
"Sends an email with the account removal link for the logged-in user."
)
@classmethod
def check_permissions(cls, user):
return user.is_authenticated
@classmethod
def perform_mutation(cls, root, info, **data):
user = info.context.user
redirect_url = data["redirect_url"]
validate_storefront_url(redirect_url)
emails.send_account_delete_confirmation_email_with_url(redirect_url, user)
return AccountRequestDeletion()
class AccountDelete(ModelDeleteMutation):
class Arguments:
token = graphene.String(
description=(
"A one-time token required to remove account. "
"Sent by email using AccountRequestDeletion mutation."
),
required=True,
)
class Meta:
description = "Remove user account."
model = models.User
@classmethod
def check_permissions(cls, user):
return user.is_authenticated
@classmethod
def clean_instance(cls, info, instance):
super().clean_instance(info, instance)
if instance.is_staff:
raise ValidationError("Cannot delete a staff account.")
@classmethod
def perform_mutation(cls, _root, info, **data):
user = info.context.user
cls.clean_instance(info, user)
token = data.pop("token")
if not default_token_generator.check_token(user, token):
raise ValidationError({"token": INVALID_TOKEN})
db_id = user.id
user.delete()
# After the instance is deleted, set its ID to the original database's
# ID so that the success response contains ID of the deleted object.
user.id = db_id
return cls.success_response(user)
class AccountAddressCreate(ModelMutation):
user = graphene.Field(
User, description="A user instance for which the address was created."
)
class Arguments:
input = AddressInput(
description="Fields required to create address", required=True
)
type = AddressTypeEnum(
required=False,
description=(
"A type of address. If provided, the new address will be "
"automatically assigned as the customer's default address "
"of that type."
),
)
class Meta:
description = "Create a new address for the customer."
model = models.Address
@classmethod
def check_permissions(cls, user):
return user.is_authenticated
@classmethod
def perform_mutation(cls, root, info, **data):
success_response = super().perform_mutation(root, info, **data)
address_type = data.get("type", None)
user = info.context.user
success_response.user = user
if address_type:
instance = success_response.address
utils.change_user_default_address(user, instance, address_type)
return success_response
@classmethod
def save(cls, info, instance, cleaned_input):
super().save(info, instance, cleaned_input)
user = info.context.user
instance.user_addresses.add(user)
class AccountAddressUpdate(BaseAddressUpdate):
class Meta:
description = "Updates an address of the logged-in user."
model = models.Address
class AccountAddressDelete(BaseAddressDelete):
class Meta:
description = "Delete an address of the logged-in user."
model = models.Address
class AccountSetDefaultAddress(BaseMutation):
user = graphene.Field(User, description="An updated user instance.")
class Arguments:
id = graphene.ID(
required=True, description="ID of the address to set as default."
)
type = AddressTypeEnum(required=True, description="The type of address.")
class Meta:
description = "Sets a default address for the authenticated user."
@classmethod
def check_permissions(cls, user):
return user.is_authenticated
@classmethod
def perform_mutation(cls, _root, info, **data):
address = cls.get_node_or_error(info, data.get("id"), Address)
user = info.context.user
if not user.addresses.filter(pk=address.pk).exists():
raise ValidationError({"id": "The address doesn't belong to that user."})
if data.get("type") == AddressTypeEnum.BILLING.value:
address_type = AddressType.BILLING
else:
address_type = AddressType.SHIPPING
utils.change_user_default_address(user, address, address_type)
return cls(user=user)