class EmailForm(forms.Form): alt_email = AllowedEmailField( label=_("New Email"), required=False, help_text="Designate an alternative email for this account", ) password = forms.CharField( label=_("Current password"), widget=forms.PasswordInput(), help_text= _("You will need to enter your current account password to make changes." ), required=True, ) def __init__(self, user, *args, **kwargs): self.user = user super().__init__(*args, **kwargs) needs_password = user.has_usable_password() if not needs_password: del self.fields["password"] def clean_password(self): value = self.cleaned_data.get("password") if value and not self.user.check_password(value): raise forms.ValidationError( _("The password you entered is not correct.")) elif not value: raise forms.ValidationError( _("You must confirm your current password to make changes.")) return value
class AccountSettingsForm(forms.Form): name = forms.CharField(required=True, label=_("Name"), max_length=30) username = forms.CharField(label=_("Username"), max_length=128) email = AllowedEmailField(label=_("Email")) new_password = forms.CharField( label=_("New password"), widget=forms.PasswordInput(), required=False, # help_text=password_validation.password_validators_help_text_html(), ) verify_new_password = forms.CharField(label=_("Verify new password"), widget=forms.PasswordInput(), required=False) password = forms.CharField( label=_("Current password"), widget=forms.PasswordInput(), help_text= "You will need to enter your current account password to make changes.", required=False, ) def __init__(self, user, request, *args, **kwargs): self.user = user self.request = request super(AccountSettingsForm, self).__init__(*args, **kwargs) needs_password = user.has_usable_password() if self.user.is_managed: # username and password always managed, email and # name optionally managed for field in ("email", "name", "username"): if field == "username" or field in settings.SENTRY_MANAGED_USER_FIELDS: self.fields[field] = ReadOnlyTextField( label=self.fields[field].label) if field == "email": needs_password = False del self.fields["new_password"] del self.fields["verify_new_password"] # don't show username field if its the same as their email address if self.user.email == self.user.username: del self.fields["username"] if not needs_password: del self.fields["password"] def is_readonly(self): if self.user.is_managed: return set( ("email", "name")) == set(settings.SENTRY_MANAGED_USER_FIELDS) return False def _clean_managed_field(self, field): if self.user.is_managed and (field == "username" or field in settings.SENTRY_MANAGED_USER_FIELDS): return getattr(self.user, field) return self.cleaned_data[field] def clean_email(self): value = self._clean_managed_field("email").lower() if self.user.email.lower() == value: return value if (User.objects.filter( Q(email__iexact=value) | Q(username__iexact=value)).exclude( id=self.user.id).exists()): raise forms.ValidationError( _("There was an error adding %s: that email is already in use") % self.cleaned_data["email"]) return value def clean_name(self): return self._clean_managed_field("name") def clean_username(self): value = self._clean_managed_field("username") if User.objects.filter(username__iexact=value).exclude( id=self.user.id).exists(): raise forms.ValidationError(_("That username is already in use.")) return value def clean_password(self): value = self.cleaned_data.get("password") if value and not self.user.check_password(value): raise forms.ValidationError( "The password you entered is not correct.") elif not value and (self.cleaned_data.get( "email", self.user.email) != self.user.email or self.cleaned_data.get("new_password")): raise forms.ValidationError( "You must confirm your current password to make changes.") return value def clean_verify_new_password(self): new_password = self.cleaned_data.get("new_password") if new_password: verify_new_password = self.cleaned_data.get("verify_new_password") if verify_new_password is None: raise forms.ValidationError( "You must verify your new password.") if new_password != verify_new_password: raise forms.ValidationError( "Your new password and verify new password must match.") return verify_new_password def clean_new_password(self): new_password = self.cleaned_data.get("new_password") if new_password: password_validation.validate_password(new_password) return new_password def save(self, commit=True): if self.cleaned_data.get("new_password"): self.user.set_password(self.cleaned_data["new_password"]) self.user.refresh_session_nonce(self.request) capture_security_activity( account=self.user, type="password-changed", actor=self.request.user, ip_address=self.request.META["REMOTE_ADDR"], send_email=True, ) self.user.name = self.cleaned_data["name"] if self.cleaned_data["email"] != self.user.email: new_username = self.user.email == self.user.username else: new_username = False self.user.email = self.cleaned_data["email"] if self.cleaned_data.get("username"): self.user.username = self.cleaned_data["username"] elif new_username and not User.objects.filter( username__iexact=self.user.email).exists(): self.user.username = self.user.email if commit: self.user.save() return self.user
class PasswordlessRegistrationForm(forms.ModelForm): name = forms.CharField( label=_("Name"), max_length=30, widget=forms.TextInput(attrs={"placeholder": "Jane Bloggs"}), required=True, ) username = AllowedEmailField( label=_("Email"), max_length=128, widget=forms.TextInput(attrs={"placeholder": "*****@*****.**"}), required=True, ) subscribe = CustomTypedChoiceField( coerce=lambda x: str(x) == "1", label=_("Email updates"), choices=( (1, "Yes, I would like to receive updates via email"), (0, "No, I'd prefer not to receive these updates"), ), widget=forms.RadioSelect, required=True, initial=False, ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if not newsletter.is_enabled(): del self.fields["subscribe"] else: # NOTE: the text here is duplicated within the ``NewsletterConsent`` component # in the UI notice = ( "We'd love to keep you updated via email with product and feature " "announcements, promotions, educational materials, and events. " "Our updates focus on relevant information, and we'll never sell " "your data to third parties. See our " '<a href="{privacy_link}">Privacy Policy</a> for more details.' ) self.fields["subscribe"].help_text = mark_safe( notice.format(privacy_link=settings.PRIVACY_URL)) class Meta: fields = ("username", "name") model = User def clean_username(self): value = (self.cleaned_data.get("username") or "").strip() if not value: return if User.objects.filter(username__iexact=value).exists(): raise forms.ValidationError( _("An account is already registered with that email address.")) return value.lower() def save(self, commit=True): user = super().save(commit=False) user.email = user.username if commit: user.save() if self.cleaned_data.get("subscribe"): newsletter.create_or_update_subscriptions( user, list_ids=newsletter.get_default_list_ids()) return user
class NotificationSettingsForm(forms.Form): alert_email = AllowedEmailField( label=_("Email"), help_text=_("Designate an alternative email address to send email notifications to."), required=False, ) subscribe_by_default = forms.BooleanField( label=_("Automatically subscribe to alerts for new projects"), help_text=_( "When enabled, you'll automatically subscribe to alerts when you create or join a project." ), required=False, ) workflow_notifications = forms.ChoiceField( label=_("Preferred workflow subscription level for new projects"), choices=[ (UserOptionValue.all_conversations, "Receive workflow updates for all issues."), ( UserOptionValue.participating_only, "Receive workflow updates only for issues that I am participating in or have subscribed to.", ), (UserOptionValue.no_conversations, "Never receive workflow updates."), ], help_text=_( "This will be automatically set as your subscription preference when you create or join a project. It has no effect on existing projects." ), required=False, ) self_notifications = forms.BooleanField( label=_("Receive notifications about my own activity"), help_text=_( "Enable this if you wish to receive emails for your own actions, as well as others." ), required=False, ) self_assign_issue = forms.BooleanField( label=_("Claim unassigned issues when resolving them"), help_text=_( "When enabled, you'll automatically be assigned to unassigned issues when marking them as resolved." ), required=False, ) def __init__(self, user, *args, **kwargs): self.user = user super(NotificationSettingsForm, self).__init__(*args, **kwargs) self.fields["alert_email"].initial = UserOption.objects.get_value( user=self.user, key="alert_email", default=user.email ) self.fields["subscribe_by_default"].initial = ( UserOption.objects.get_value(user=self.user, key="subscribe_by_default", default="1") == "1" ) self.fields["workflow_notifications"].initial = UserOption.objects.get_value( user=self.user, key="workflow:notifications", default=UserOptionValue.participating_only, project=None, ) self.fields["self_notifications"].initial = ( UserOption.objects.get_value(user=self.user, key="self_notifications", default="0") == "1" ) self.fields["self_assign_issue"].initial = ( UserOption.objects.get_value(user=self.user, key="self_assign_issue", default="0") == "1" ) def get_title(self): return "General" def save(self): UserOption.objects.set_value( user=self.user, key="alert_email", value=self.cleaned_data["alert_email"] ) UserOption.objects.set_value( user=self.user, key="subscribe_by_default", value="1" if self.cleaned_data["subscribe_by_default"] else "0", ) UserOption.objects.set_value( user=self.user, key="self_notifications", value="1" if self.cleaned_data["self_notifications"] else "0", ) UserOption.objects.set_value( user=self.user, key="self_assign_issue", value="1" if self.cleaned_data["self_assign_issue"] else "0", ) workflow_notifications_value = self.cleaned_data.get("workflow_notifications") if not workflow_notifications_value: UserOption.objects.unset_value( user=self.user, key="workflow:notifications", project=None ) else: UserOption.objects.set_value( user=self.user, key="workflow:notifications", value=workflow_notifications_value, project=None, )