1 # -*- coding: utf-8 -*-
2 # Copyright (C) 1998-2021 by the Free Software Foundation, Inc.
4 # This file is part of Postorius.
6 # Postorius is free software: you can redistribute it and/or modify it under
7 # the terms of the GNU General Public License as published by the Free
8 # Software Foundation, either version 3 of the License, or (at your option)
11 # Postorius is distributed in the hope that it will be useful, but WITHOUT
12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 # You should have received a copy of the GNU General Public License along with
17 # Postorius. If not, see <http://www.gnu.org/licenses/>.
21 from urllib
.error
import HTTPError
23 from django
.contrib
import messages
24 from django
.contrib
.auth
.decorators
import login_required
25 from django
.forms
import formset_factory
26 from django
.http
import Http404
27 from django
.shortcuts
import render
28 from django
.urls
import reverse
, reverse_lazy
29 from django
.utils
.decorators
import method_decorator
30 from django
.utils
.translation
import gettext
as _
31 from django
.views
.generic
import FormView
33 from allauth
.account
.models
import EmailAddress
34 from django_mailman3
.lib
.mailman
import get_mailman_client
, get_mailman_user
36 from postorius
.forms
import (
37 ChangeSubscriptionForm
, UserPreferences
, UserPreferencesFormset
)
38 from postorius
.models
import List
, MailmanUser
, SubscriptionMode
39 from postorius
.utils
import set_preferred
40 from postorius
.views
.generic
import MailmanClientMixin
43 logger
= logging
.getLogger(__name__
)
46 class UserPreferencesView(FormView
, MailmanClientMixin
):
47 """Generic view for the logged-in user's various preferences."""
49 form_class
= UserPreferences
51 def get_context_data(self
, **kwargs
):
52 data
= super(UserPreferencesView
, self
).get_context_data(**kwargs
)
53 data
['mm_user'] = self
.mm_user
56 def get_form_kwargs(self
):
57 kwargs
= super(UserPreferencesView
, self
).get_form_kwargs()
58 kwargs
['preferences'] = self
._get
_preferences
()
61 def _set_view_attributes(self
, request
, *args
, **kwargs
):
62 self
.mm_user
= MailmanUser
.objects
.get_or_create_from_django(
65 @method_decorator(login_required
)
66 def dispatch(self
, request
, *args
, **kwargs
):
67 self
._set
_view
_attributes
(request
, *args
, **kwargs
)
68 return super(UserPreferencesView
, self
).dispatch(
69 request
, *args
, **kwargs
)
71 def form_valid(self
, form
):
74 except HTTPError
as e
:
75 messages
.error(self
.request
, e
.msg
)
76 if form
.has_changed():
78 self
.request
, _('Your preferences have been updated.'))
80 messages
.info(self
.request
, _('Your preferences did not change.'))
81 return super(UserPreferencesView
, self
).form_valid(form
)
84 class UserMailmanSettingsView(UserPreferencesView
):
85 """The logged-in user's global Mailman preferences."""
87 form_class
= UserPreferences
88 template_name
= 'postorius/user/mailman_settings.html'
89 success_url
= reverse_lazy('user_mailmansettings')
91 def _get_preferences(self
):
92 # Get the defaults and pre-populate so view shows them
93 combinedpreferences
= self
._get
_combined
_preferences
()
94 for key
in combinedpreferences
:
95 if key
!= "self_link":
96 self
.mm_user
.preferences
[key
] = combinedpreferences
[key
]
98 # This is a bit of a hack so preferences behave as users expect
99 # We probably don't want to save, only display here
100 # but this means that whatever preferences the users see first are
101 # the ones they have unless they explicitly change them
102 self
.mm_user
.preferences
.save()
104 return self
.mm_user
.preferences
106 def _get_combined_preferences(self
):
107 # Get layers of default preferences to match how they are applied
108 # We ignore self_link as we don't want to over-write it
109 defaultpreferences
= get_mailman_client().preferences
110 combinedpreferences
= {}
111 for key
in defaultpreferences
:
112 if key
!= "self_link":
113 combinedpreferences
[key
] = defaultpreferences
[key
]
115 # Clobber defaults with any preferences already set
116 for key
in self
.mm_user
.preferences
:
117 if key
!= "self_link":
118 combinedpreferences
[key
] = self
.mm_user
.preferences
[key
]
120 return(combinedpreferences
)
123 class UserAddressPreferencesView(UserPreferencesView
):
124 """The logged-in user's address-based Mailman Preferences."""
126 template_name
= 'postorius/user/address_preferences.html'
127 success_url
= reverse_lazy('user_address_preferences')
129 def get_form_class(self
):
130 return formset_factory(
131 UserPreferences
, formset
=UserPreferencesFormset
, extra
=0)
133 def _get_preferences(self
):
134 return [address
.preferences
for address
in self
.mm_user
.addresses
]
136 def _get_combined_preferences(self
):
137 # grab the default preferences
138 defaultpreferences
= get_mailman_client().preferences
140 # grab your global preferences
141 globalpreferences
= self
.mm_user
.preferences
143 # start a new combined preferences object
144 combinedpreferences
= []
146 for address
in self
.mm_user
.addresses
:
147 # make a per-address prefs object
150 # initialize with default preferences
151 for key
in defaultpreferences
:
152 if key
!= "self_link":
153 prefs
[key
] = defaultpreferences
[key
]
155 # overwrite with user's global preferences
156 for key
in globalpreferences
:
157 if key
!= "self_link":
158 prefs
[key
] = globalpreferences
[key
]
160 # overwrite with address-specific preferences
161 for key
in address
.preferences
:
162 if key
!= "self_link":
163 prefs
[key
] = address
.preferences
[key
]
164 combinedpreferences
.append(prefs
)
166 # put the combined preferences back on the original object
168 if key
!= "self_link":
169 address
.preferences
[key
] = prefs
[key
]
171 return combinedpreferences
173 def get_context_data(self
, **kwargs
):
174 data
= super(UserAddressPreferencesView
, self
).get_context_data(
176 data
['formset'] = data
.pop('form')
177 for form
, address
in list(zip(
178 data
['formset'].forms
, self
.mm_user
.addresses
)):
179 form
.address
= address
183 class UserListOptionsView(UserPreferencesView
):
184 """The logged-in user's subscription preferences."""
186 form_class
= UserPreferences
187 template_name
= 'postorius/user/list_options.html'
189 def _get_subscription(self
):
191 for s
in self
.mm_user
.subscriptions
:
192 if s
.role
== 'member' and s
.list_id
== self
.mlist
.list_id
:
196 raise Http404(_('Subscription does not exist'))
199 def _set_view_attributes(self
, request
, *args
, **kwargs
):
200 super(UserListOptionsView
, self
)._set
_view
_attributes
(
201 request
, *args
, **kwargs
)
202 self
.mlist
= List
.objects
.get_or_404(fqdn_listname
=kwargs
['list_id'])
203 self
.subscription
= self
._get
_subscription
()
204 if (self
.subscription
.subscription_mode
==
205 SubscriptionMode
.as_user
.name
):
206 self
.subscriber
= self
.subscription
.user
.user_id
208 self
.subscriber
= self
.subscription
.email
210 def _get_preferences(self
):
211 return self
.subscription
.preferences
213 def get_context_data(self
, **kwargs
):
214 data
= super(UserListOptionsView
, self
).get_context_data(**kwargs
)
215 data
['mlist'] = self
.mlist
216 user_emails
= EmailAddress
.objects
.filter(
217 user
=self
.request
.user
, verified
=True).order_by(
218 "email").values_list("email", flat
=True)
219 mm_user
= get_mailman_user(self
.request
.user
)
221 if mm_user
.preferred_address
is None:
222 primary_email
= set_preferred(self
.request
.user
, mm_user
)
224 primary_email
= mm_user
.preferred_address
.email
225 data
['change_subscription_form'] = ChangeSubscriptionForm(
226 user_emails
, mm_user
.user_id
, primary_email
,
227 initial
={'subscriber': self
.subscriber
})
230 def get_success_url(self
):
232 'user_list_options', kwargs
=dict(list_id
=self
.mlist
.list_id
))
235 class UserSubscriptionPreferencesView(UserPreferencesView
):
236 """The logged-in user's subscription-based Mailman Preferences."""
238 template_name
= 'postorius/user/subscription_preferences.html'
239 success_url
= reverse_lazy('user_subscription_preferences')
241 def _get_subscriptions(self
):
243 for s
in self
.mm_user
.subscriptions
:
244 if s
.role
!= 'member':
246 subscriptions
.append(s
)
249 def _set_view_attributes(self
, request
, *args
, **kwargs
):
250 super(UserSubscriptionPreferencesView
, self
)._set
_view
_attributes
(
251 request
, *args
, **kwargs
)
252 self
.subscriptions
= self
._get
_subscriptions
()
254 def get_form_class(self
):
255 return formset_factory(
256 UserPreferences
, formset
=UserPreferencesFormset
, extra
=0)
258 def _get_preferences(self
):
259 return [sub
.preferences
for sub
in self
.subscriptions
]
261 def _get_combined_preferences(self
):
262 # grab the default preferences
263 defaultpreferences
= get_mailman_client().preferences
265 # grab your global preferences
266 globalpreferences
= self
.mm_user
.preferences
268 # start a new combined preferences object
269 combinedpreferences
= []
271 for sub
in self
.subscriptions
:
272 # make a per-address prefs object
275 # initialize with default preferences
276 for key
in defaultpreferences
:
277 if key
!= "self_link":
278 prefs
[key
] = defaultpreferences
[key
]
280 # overwrite with user's global preferences
281 for key
in globalpreferences
:
282 if key
!= "self_link":
283 prefs
[key
] = globalpreferences
[key
]
285 # overwrite with address-based preferences
286 # There is currently no better way to do this,
287 # we may consider revisiting.
288 addresspreferences
= {}
289 for address
in self
.mm_user
.addresses
:
290 if sub
.email
== address
.email
:
291 addresspreferences
= address
.preferences
293 for key
in addresspreferences
:
294 if key
!= "self_link":
295 prefs
[key
] = addresspreferences
[key
]
297 # overwrite with subscription-specific preferences
298 for key
in sub
.preferences
:
299 if key
!= "self_link":
300 prefs
[key
] = sub
.preferences
[key
]
302 combinedpreferences
.append(prefs
)
304 return combinedpreferences
305 # return [sub.preferences for sub in self.subscriptions]
307 def get_context_data(self
, **kwargs
):
308 data
= super(UserSubscriptionPreferencesView
, self
).get_context_data(
310 data
['formset'] = data
.pop('form')
311 for form
, subscription
in list(zip(
312 data
['formset'].forms
, self
.subscriptions
)):
313 form
.list_id
= subscription
.list_id
318 def user_subscriptions(request
):
319 """Shows the subscriptions of a user."""
320 mm_user
= MailmanUser
.objects
.get_or_create_from_django(request
.user
)
321 memberships
= [m
for m
in mm_user
.subscriptions
]
322 return render(request
, 'postorius/user/subscriptions.html',
323 {'memberships': memberships
})