2
2
from django .contrib .auth import login as django_login
3
3
import django .contrib .auth .views as authviews
4
4
from django .http import HttpResponseRedirect , Http404 , HttpResponse
5
+ from django .core .exceptions import PermissionDenied
5
6
from django .shortcuts import get_object_or_404
6
7
from pgweb .util .decorators import login_required , script_sources , frame_sources
7
8
from django .utils .encoding import force_bytes
23
24
24
25
from pgweb .util .contexts import render_pgweb
25
26
from pgweb .util .misc import send_template_mail , generate_random_token , get_client_ip
26
- from pgweb .util .helpers import HttpSimpleResponse
27
+ from pgweb .util .helpers import HttpSimpleResponse , simple_form
28
+ from pgweb .util .moderation import ModerationState
27
29
28
30
from pgweb .news .models import NewsArticle
29
31
from pgweb .events .models import Event
30
- from pgweb .core .models import Organisation , UserProfile
32
+ from pgweb .core .models import Organisation , UserProfile , ModerationNotification
31
33
from pgweb .contributors .models import Contributor
32
34
from pgweb .downloads .models import Product
33
35
from pgweb .profserv .models import ProfessionalService
34
36
35
37
from .models import CommunityAuthSite , CommunityAuthConsent , EmailChangeToken
36
- from .forms import PgwebAuthenticationForm
38
+ from .forms import PgwebAuthenticationForm , ConfirmSubmitForm
37
39
from .forms import CommunityAuthConsentForm
38
40
from .forms import SignupForm , SignupOauthForm
39
41
from .forms import UserForm , UserProfileForm , ContributorForm
40
42
from .forms import ChangeEmailForm , PgwebPasswordResetForm
41
43
42
44
import logging
45
+
46
+ from pgweb .util .moderation import get_moderation_model_from_suburl
47
+ from pgweb .mailqueue .util import send_simple_mail
48
+
43
49
log = logging .getLogger (__name__ )
44
50
45
51
# The value we store in user.password for oauth logins. This is
46
52
# a value that must not match any hashers.
47
53
OAUTH_PASSWORD_STORE = 'oauth_signin_account_no_password'
48
54
49
55
56
+ def _modobjs (qs ):
57
+ l = list (qs )
58
+ if l :
59
+ return {
60
+ 'title' : l [0 ]._meta .verbose_name_plural .capitalize (),
61
+ 'objects' : l ,
62
+ 'editurl' : l [0 ].account_edit_suburl ,
63
+ }
64
+ else :
65
+ return None
66
+
67
+
50
68
@login_required
51
69
def home (request ):
52
- myarticles = NewsArticle .objects .filter (org__managers = request .user , approved = False )
53
- myevents = Event .objects .filter (org__managers = request .user , approved = False )
54
- myorgs = Organisation .objects .filter (managers = request .user , approved = False )
55
- myproducts = Product .objects .filter (org__managers = request .user , approved = False )
56
- myprofservs = ProfessionalService .objects .filter (org__managers = request .user , approved = False )
57
70
return render_pgweb (request , 'account' , 'account/index.html' , {
58
- 'newsarticles' : myarticles ,
59
- 'events' : myevents ,
60
- 'organisations' : myorgs ,
61
- 'products' : myproducts ,
62
- 'profservs' : myprofservs ,
71
+ 'modobjects' : [
72
+ {
73
+ 'title' : 'not submitted yet' ,
74
+ 'objects' : [
75
+ _modobjs (NewsArticle .objects .filter (org__managers = request .user , modstate = ModerationState .CREATED )),
76
+ ],
77
+ },
78
+ {
79
+ 'title' : 'waiting for moderator approval' ,
80
+ 'objects' : [
81
+ _modobjs (NewsArticle .objects .filter (org__managers = request .user , modstate = ModerationState .PENDING )),
82
+ _modobjs (Event .objects .filter (org__managers = request .user , approved = False )),
83
+ _modobjs (Organisation .objects .filter (managers = request .user , approved = False )),
84
+ _modobjs (Product .objects .filter (org__managers = request .user , approved = False )),
85
+ _modobjs (ProfessionalService .objects .filter (org__managers = request .user , approved = False ))
86
+ ],
87
+ },
88
+ ],
63
89
})
64
90
65
91
66
92
objtypes = {
67
93
'news' : {
68
- 'title' : 'News Article ' ,
94
+ 'title' : 'news article ' ,
69
95
'objects' : lambda u : NewsArticle .objects .filter (org__managers = u ),
96
+ 'tristate' : True ,
97
+ 'editapproved' : False ,
70
98
},
71
99
'events' : {
72
- 'title' : 'Event ' ,
100
+ 'title' : 'event ' ,
73
101
'objects' : lambda u : Event .objects .filter (org__managers = u ),
102
+ 'editapproved' : True ,
74
103
},
75
104
'products' : {
76
- 'title' : 'Product ' ,
105
+ 'title' : 'product ' ,
77
106
'objects' : lambda u : Product .objects .filter (org__managers = u ),
107
+ 'editapproved' : True ,
78
108
},
79
109
'services' : {
80
- 'title' : 'Professional Service ' ,
110
+ 'title' : 'professional service ' ,
81
111
'objects' : lambda u : ProfessionalService .objects .filter (org__managers = u ),
112
+ 'editapproved' : True ,
82
113
},
83
114
'organisations' : {
84
- 'title' : 'Organisation ' ,
115
+ 'title' : 'organisation ' ,
85
116
'objects' : lambda u : Organisation .objects .filter (managers = u ),
86
117
'submit_header' : 'Before submitting a new Organisation, please verify on the list of <a href="/account/orglist/">current organisations</a> if the organisation already exists. If it does, please contact the manager of the organisation to gain permissions.' ,
118
+ 'editapproved' : True ,
87
119
},
88
120
}
89
121
@@ -208,14 +240,25 @@ def listobjects(request, objtype):
208
240
raise Http404 ("Object type not found" )
209
241
o = objtypes [objtype ]
210
242
211
- return render_pgweb (request , 'account' , 'account/objectlist.html' , {
212
- 'objects' : {
243
+ if o .get ('tristate' , False ):
244
+ objects = {
245
+ 'approved' : o ['objects' ](request .user ).filter (modstate = ModerationState .APPROVED ),
246
+ 'unapproved' : o ['objects' ](request .user ).filter (modstate = ModerationState .PENDING ),
247
+ 'inprogress' : o ['objects' ](request .user ).filter (modstate = ModerationState .CREATED ),
248
+ }
249
+ else :
250
+ objects = {
213
251
'approved' : o ['objects' ](request .user ).filter (approved = True ),
214
252
'unapproved' : o ['objects' ](request .user ).filter (approved = False ),
215
- },
253
+ }
254
+
255
+ return render_pgweb (request , 'account' , 'account/objectlist.html' , {
256
+ 'objects' : objects ,
216
257
'title' : o ['title' ],
258
+ 'editapproved' : o ['editapproved' ],
217
259
'submit_header' : o .get ('submit_header' , None ),
218
260
'suburl' : objtype ,
261
+ 'tristate' : o .get ('tristate' , False ),
219
262
})
220
263
221
264
@@ -228,6 +271,100 @@ def orglist(request):
228
271
})
229
272
230
273
274
+ @login_required
275
+ def submitted_item_form (request , objtype , item ):
276
+ model = get_moderation_model_from_suburl (objtype )
277
+
278
+ if item == 'new' :
279
+ extracontext = {}
280
+ else :
281
+ extracontext = {
282
+ 'notices' : ModerationNotification .objects .filter (
283
+ objecttype = model .__name__ ,
284
+ objectid = item ,
285
+ ).order_by ('-date' )
286
+ }
287
+
288
+ return simple_form (model , item , request , model .get_formclass (),
289
+ redirect = '/account/edit/{}/' .format (objtype ),
290
+ formtemplate = 'account/submit_form.html' ,
291
+ extracontext = extracontext )
292
+
293
+
294
+ def _submitted_item_submit (request , objtype , model , obj ):
295
+ if obj .modstate != ModerationState .CREATED :
296
+ # Can only submit if state is created
297
+ return HttpResponseRedirect ("/account/edit/{}/" .format (objtype ))
298
+
299
+ if request .method == 'POST' :
300
+ form = ConfirmSubmitForm (obj ._meta .verbose_name , data = request .POST )
301
+ if form .is_valid ():
302
+ with transaction .atomic ():
303
+ obj .modstate = ModerationState .PENDING
304
+ obj .send_notification = False
305
+ obj .save ()
306
+
307
+ send_simple_mail (settings .NOTIFICATION_FROM ,
308
+ settings .NOTIFICATION_EMAIL ,
309
+ "{} {} submitted" .format (obj ._meta .verbose_name .capitalize (), obj .id ),
310
+ "{} {} with title {} submitted for moderation by {}" .format (
311
+ obj ._meta .verbose_name .capitalize (),
312
+ obj .id ,
313
+ obj .title ,
314
+ request .user .username
315
+ ),
316
+ )
317
+ return HttpResponseRedirect ("/account/edit/{}/" .format (objtype ))
318
+ else :
319
+ form = ConfirmSubmitForm (obj ._meta .verbose_name )
320
+
321
+ return render_pgweb (request , 'account' , 'account/submit_preview.html' , {
322
+ 'obj' : obj ,
323
+ 'form' : form ,
324
+ 'objtype' : obj ._meta .verbose_name ,
325
+ 'preview' : obj .get_preview_fields (),
326
+ })
327
+
328
+
329
+ def _submitted_item_withdraw (request , objtype , model , obj ):
330
+ # XXX: should we do a confirmation step? But it's easy enough to resubmit.
331
+ if obj .modstate != ModerationState .PENDING :
332
+ # Can only withdraw if it's in pending state
333
+ return HttpResponseRedirect ("/account/edit/{}/" .format (objtype ))
334
+
335
+ obj .modstate = ModerationState .CREATED
336
+ obj .send_notification = False
337
+ obj .save ()
338
+
339
+ send_simple_mail (
340
+ settings .NOTIFICATION_FROM ,
341
+ settings .NOTIFICATION_EMAIL ,
342
+ "{} {} withdrawn from moderation" .format (model ._meta .verbose_name .capitalize (), obj .id ),
343
+ "{} {} with title {} withdrawn from moderation by {}" .format (
344
+ model ._meta .verbose_name .capitalize (),
345
+ obj .id ,
346
+ obj .title ,
347
+ request .user .username
348
+ ),
349
+ )
350
+ return HttpResponseRedirect ("/account/edit/{}/" .format (objtype ))
351
+
352
+
353
+ @login_required
354
+ @transaction .atomic
355
+ def submitted_item_submitwithdraw (request , objtype , item , what ):
356
+ model = get_moderation_model_from_suburl (objtype )
357
+
358
+ obj = get_object_or_404 (model , pk = item )
359
+ if not obj .verify_submitter (request .user ):
360
+ raise PermissionDenied ("You are not the owner of this item!" )
361
+
362
+ if what == 'submit' :
363
+ return _submitted_item_submit (request , objtype , model , obj )
364
+ else :
365
+ return _submitted_item_withdraw (request , objtype , model , obj )
366
+
367
+
231
368
def login (request ):
232
369
return authviews .LoginView .as_view (template_name = 'account/login.html' ,
233
370
authentication_form = PgwebAuthenticationForm ,
0 commit comments