Repository: svthalia/concrexit

Issue:
Opt-out from alumni newsletter not possible without filling in many account details
### Describe the bug
To opt-out from alumni emails, you need to deselect a checkbox on your profile settings. In order to do this, you need to save all forms as a whole, which requires you to not leave certain fields empty. This causes unwanted behaviour for alumni, whose data has been minimalized: They only have a mail address and a name.


### How to reproduce
Steps to reproduce the behaviour:
- Start from 'empty account' 
- Add mail address and Name
- Forgot password button
- Reset password
- Login
- Try to opt-out from alumni mails. 

### Expected behaviour
We want alumni to easily deregister from the alumni newsletter. Currently, they cannot do that without filling in all sorts of irrelevant details.

### Additional context
This issue might be related to deeper concerns and also be relevant for other use cases, such as the regular newsletter and the Thabloid, but I'm not sure of that.



Discussion:
A simple option would be to just add a seperate form for email (and maybe some other) preferences, that validates independently of the rest of the profile fields. 
It would have to be easy to find with:
- Showing up in the user menu dropdown if(f) your data has been minimized.
- Perhaps a redirect from the normal edit profile view to the new one for dataminimized users.

This is somewhat related to #3292.

Resolving patch:
diff --git a/website/members/forms.py b/website/members/forms.py
--- a/website/members/forms.py
+++ b/website/members/forms.py
@@ -13,7 +13,12 @@
 
 
 class ProfileForm(forms.ModelForm):
-    """Form with all the user editable fields of a Profile model."""
+    """Form with all the user editable fields of a Profile model.
+
+    If the profile is minimized, no fields are required, unless the `require_address`
+    keyword argument is True, which is set if a user is filling a minimized profile
+    in order to be able to create a Renewal.
+    """
 
     birthday = forms.DateField()
 
@@ -43,8 +48,9 @@ class Meta:
         ]
         model = Profile
 
-    def __init__(self, *args, **kwargs):
+    def __init__(self, *args, require_address=False, **kwargs):
         super().__init__(*args, **kwargs)
+        user = Member.objects.get(pk=kwargs["instance"].user_id)
         for field in [
             "birthday",
             "address_street",
@@ -53,16 +59,17 @@ def __init__(self, *args, **kwargs):
             "address_city",
             "address_country",
         ]:
-            self.fields[field].required = True
+            if require_address or not user.profile.is_minimized:
+                self.fields[field].required = True
+            else:
+                self.fields[field].required = False
+
         if not kwargs["instance"].user.is_staff:
             self.fields["email_gsuite_only"].widget = self.fields[
                 "email_gsuite_only"
             ].hidden_widget()
 
-        if (
-            not Member.objects.get(pk=kwargs["instance"].user_id).has_been_member()
-            and not kwargs["instance"].receive_oldmembers
-        ):
+        if not user.has_been_member() and not kwargs["instance"].receive_oldmembers:
             self.fields["receive_oldmembers"].disabled = True
             self.fields["receive_oldmembers"].help_text = (
                 "If you are a past member, receive emails about Thalia events aimed at alumni. "
@@ -72,7 +79,7 @@ def __init__(self, *args, **kwargs):
             )
 
         self.fields["birthday"].widget.input_type = "date"
-        if not Member.objects.get(pk=kwargs["instance"].user_id).profile.is_minimized:
+        if not user.profile.is_minimized:
             self.fields["birthday"].disabled = True
 
         self.render_app_specific_profile_form_fields()
diff --git a/website/members/views.py b/website/members/views.py
--- a/website/members/views.py
+++ b/website/members/views.py
@@ -182,6 +182,11 @@ class UserProfileUpdateView(RedirectURLMixin, SuccessMessageMixin, UpdateView):
     def get_object(self, queryset=None) -> Profile:
         return get_object_or_404(models.Profile, user=self.request.user)
 
+    def get_form_kwargs(self):
+        kwargs = super().get_form_kwargs()
+        kwargs["require_address"] = bool(self.request.GET.get("require_address", False))
+        return kwargs
+
 
 @method_decorator(login_required, "dispatch")
 class StatisticsView(TemplateView):


Test patch: