Skip to content

Commit cb0861c

Browse files
author
Rocky Meza
committed
Merge branch 'new-save-flow'
2 parents a65f64e + 599bfe4 commit cb0861c

File tree

19 files changed

+902
-236
lines changed

19 files changed

+902
-236
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def read(fname):
1313

1414

1515
install_requires = [
16-
'mezzanine >= 1.3.0',
16+
'mezzanine >= 3.1.10',
1717
'django-treebeard',
1818
'django-filer>=0.9.6',
1919
'South',

tests/test_sqlite.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,15 @@
4747
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
4848
'compressor.finders.CompressorFinder',
4949
)
50+
51+
TEMPLATE_CONTEXT_PROCESSORS = (
52+
"django.contrib.auth.context_processors.auth",
53+
"django.contrib.messages.context_processors.messages",
54+
"django.core.context_processors.debug",
55+
"django.core.context_processors.i18n",
56+
"django.core.context_processors.static",
57+
"django.core.context_processors.media",
58+
"django.core.context_processors.request",
59+
"mezzanine.conf.context_processors.settings",
60+
"mezzanine.pages.context_processors.page",
61+
)

tests/urls.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from django.conf.urls import patterns, include, url
2+
from django.conf import settings
23

34
from django.contrib import admin
45
admin.autodiscover()
@@ -11,7 +12,12 @@ def dummy_view(*args, **kwargs):
1112
urlpatterns = patterns('',
1213
url('^core_tests/', include('modeltests.core_tests.urls')),
1314
url("^admin/", include(admin.site.urls)),
14-
url('^widgy-mezzanine/', include('widgy.contrib.widgy_mezzanine.urls')),
1515
# mezzanine.pages.views.page reverses the 'home' url.
1616
url('^$', dummy_view, name='home'),
1717
)
18+
19+
if 'widgy.contrib.widgy_mezzanine' in settings.INSTALLED_APPS:
20+
urlpatterns += [
21+
url('^widgy-mezzanine/', include('widgy.contrib.widgy_mezzanine.urls')),
22+
url('^mezzanine/', include('mezzanine.urls')),
23+
]

widgy/contrib/page_builder/templates/widgy/page_builder/widgypage_change_form.html

Lines changed: 0 additions & 12 deletions
This file was deleted.

widgy/contrib/review_queue/models.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ def unapproved(self):
2323
return self.filter(approved_at__isnull=True,
2424
approved_by__isnull=True)
2525

26+
def approved(self):
27+
return self.exclude(approved_at__isnull=True,
28+
approved_by__isnull=True)
29+
2630
objects = ReviewedVersionCommitQuerySet.as_manager()
2731

2832
@property
@@ -61,11 +65,8 @@ def published(self):
6165

6266
objects = ReviewedVersionTrackerQuerySet.as_manager()
6367

64-
def get_published_node(self, request):
65-
for commit in self.get_history():
66-
if commit.is_published and commit.reviewedversioncommit.is_approved:
67-
return commit.root_node
68-
return None
68+
def commit_is_ready(self, commit):
69+
return commit.is_published and commit.reviewedversioncommit.is_approved
6970

7071
@property
7172
def commits(self):

widgy/contrib/review_queue/views.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,5 @@ def get_context_data(self, **kwargs):
124124
interesting = True
125125
for commit in kwargs['commits']:
126126
commit.is_interesting_to_approve_or_unapprove = interesting
127-
if commit.reviewedversioncommit.is_approved:
128-
interesting = False
127+
interesting &= not self.object.commit_is_ready(commit)
129128
return kwargs

widgy/contrib/widgy_mezzanine/admin.py

Lines changed: 175 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
from django import forms
77
from django.core.urlresolvers import reverse
88
from django.contrib.admin.util import quote
9-
from django.utils.translation import ugettext_lazy as _, ugettext
9+
from django.utils.translation import ugettext_lazy as _, ugettext, ungettext
10+
from django.utils import timezone
11+
from django.contrib import messages
12+
from django.db.models.signals import post_save
13+
from django.db.models import Min, Q
1014

1115
from mezzanine.pages.admin import PageAdmin
1216
try:
@@ -17,18 +21,26 @@
1721
from mezzanine.core.models import (CONTENT_STATUS_PUBLISHED,
1822
CONTENT_STATUS_DRAFT)
1923

20-
from widgy.forms import WidgyFormMixin
24+
from widgy.forms import WidgyFormMixin, VersionedWidgyWidget
2125
from widgy.contrib.widgy_mezzanine import get_widgypage_model
22-
from widgy.contrib.widgy_mezzanine.views import ClonePageView
23-
from widgy.utils import fancy_import, format_html
26+
from widgy.contrib.widgy_mezzanine.views import ClonePageView, UnpublishView
27+
from widgy.utils import format_html
28+
from widgy.db.fields import get_site
2429

2530

2631
WidgyPage = get_widgypage_model()
2732

2833

34+
class PageVersionedWidgyWidget(VersionedWidgyWidget):
35+
template_name = 'widgy/widgy_mezzanine/versioned_widgy_field.html'
36+
37+
2938
class WidgyPageAdminForm(WidgyFormMixin, PageAdminForm):
3039
class Meta:
3140
model = WidgyPage
41+
widgets = {
42+
'root_node': PageVersionedWidgyWidget,
43+
}
3244

3345
def __init__(self, *args, **kwargs):
3446
super(WidgyPageAdminForm, self).__init__(*args, **kwargs)
@@ -38,26 +50,133 @@ def __init__(self, *args, **kwargs):
3850
self.fields['expiry_date'].help_text = _(
3951
"If you enter a date here, the page will not be viewable after this time"
4052
)
41-
self.fields['status'].initial = CONTENT_STATUS_DRAFT
53+
if self.instance.pk is not None:
54+
self.instance.status = CONTENT_STATUS_DRAFT
4255

43-
def clean_status(self):
44-
status = self.cleaned_data.get('status')
45-
if (status == CONTENT_STATUS_PUBLISHED and (not self.instance.root_node or
46-
not self.instance.root_node.head)):
47-
raise forms.ValidationError(_('You must commit before you can publish'))
48-
return status
4956

57+
# the status of a page before it's created, on the add page
58+
CONTENT_STATUS_EMBRYO = 0
5059

5160
class WidgyPageAdmin(PageAdmin):
52-
change_form_template = 'widgy/page_builder/widgypage_change_form.html'
61+
change_form_template = 'widgy/widgy_mezzanine/widgypage_change_form.html'
5362
form = WidgyPageAdminForm
63+
readonly_fields = ['status']
64+
65+
unreviewed_buttons = {
66+
CONTENT_STATUS_EMBRYO : [('_continue', _('Save'))],
67+
CONTENT_STATUS_DRAFT : [('_continue', _('Save as Draft')),
68+
('_save_and_commit', _('Publish'))],
69+
CONTENT_STATUS_PUBLISHED : [('_save_and_commit', _('Publish Changes'))],
70+
}
71+
reviewed_buttons = {
72+
(CONTENT_STATUS_EMBRYO, False) : [('_continue', _('Save'))],
73+
(CONTENT_STATUS_EMBRYO, True) : [('_continue', _('Save'))],
74+
(CONTENT_STATUS_DRAFT, False) : [('_continue', _('Save as Draft')),
75+
('_save_and_commit', _('Submit for Review'))],
76+
(CONTENT_STATUS_DRAFT, True) : [('_continue', _('Save as Draft')),
77+
('_save_and_commit', _('Submit for Review')),
78+
('_save_and_approve', _('Publish'))],
79+
(CONTENT_STATUS_PUBLISHED, False) : [('_save_and_commit', _('Submit for Review'))],
80+
(CONTENT_STATUS_PUBLISHED, True) : [('_save_and_commit', _('Submit for Review')),
81+
('_save_and_approve', _('Publish Changes'))],
82+
}
5483

5584
def get_urls(self):
5685
clone_view = ClonePageView.as_view(has_permission=self.has_add_permission)
86+
unpublish_view = UnpublishView.as_view(has_change_permission=self.has_change_permission)
5787
return [
5888
url('^(.+)/clone/$', self.admin_site.admin_view(clone_view)),
89+
url('^(.+)/unpublish/$', self.admin_site.admin_view(unpublish_view)),
5990
] + super(WidgyPageAdmin, self).get_urls()
6091

92+
def _save_and_commit(self, request, obj):
93+
site = self.get_site()
94+
commit_model = site.get_version_tracker_model().commit_model
95+
if not site.has_add_permission(request, commit_model):
96+
messages.error(request, _("You don't have permission to commit."))
97+
else:
98+
if obj.root_node.has_changes():
99+
obj.root_node.commit(user=request.user)
100+
elif self.has_review_queue:
101+
messages.warning(request, _("There was nothing to submit for review."))
102+
103+
if not self.has_review_queue:
104+
obj.status = CONTENT_STATUS_PUBLISHED
105+
# else:
106+
# If we are reviewed, we'll have to wait for approval.
107+
# Handled by the publish_page_on_approve signal.
108+
109+
def _save_and_approve(self, request, obj):
110+
site = self.get_site()
111+
commit_model = site.get_version_tracker_model().commit_model
112+
if not site.has_add_permission(request, commit_model) or \
113+
not site.has_change_permission(request, commit_model):
114+
messages.error(request, _("You don't have permission to approve commits."))
115+
else:
116+
if obj.root_node.has_changes():
117+
obj.root_node.commit(request.user)
118+
# If we had changes, `head` is the same commit we just created.
119+
# If we didn't need to create a commit, we want to publish the
120+
# most recent one instead.
121+
obj.root_node.head.reviewedversioncommit.approve(request.user)
122+
obj.root_node.head.reviewedversioncommit.save()
123+
obj.status = CONTENT_STATUS_PUBLISHED
124+
125+
def save_model(self, request, obj, form, change):
126+
if '_save_and_commit' in request.POST:
127+
self._save_and_commit(request, obj)
128+
elif '_save_and_approve' in request.POST and self.has_review_queue:
129+
self._save_and_approve(request, obj)
130+
request.POST['_continue'] = True
131+
super(WidgyPageAdmin, self).save_model(request, obj, form, change)
132+
133+
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None, *args, **kwargs):
134+
if not add:
135+
unapproved = 0
136+
future = 0
137+
for commit in obj.root_node.get_history_list():
138+
if obj.root_node.commit_is_ready(commit):
139+
# got to the currently-published commit
140+
break
141+
if self.has_review_queue and not commit.reviewedversioncommit.is_approved:
142+
unapproved += 1
143+
if not commit.is_published:
144+
future += 1
145+
if unapproved:
146+
messages.warning(request, ungettext(
147+
"There is one unreviewed commit for this page.",
148+
"There are {count} unreviewed commits for this page.",
149+
unapproved
150+
).format(count=unapproved))
151+
if future:
152+
messages.warning(request, ungettext(
153+
"There is one future-scheduled commit.",
154+
"There are {count} future-scheduled commits.",
155+
future
156+
).format(count=future))
157+
158+
site = self.get_site()
159+
if add:
160+
status = CONTENT_STATUS_EMBRYO
161+
else:
162+
status = obj.status
163+
if self.has_review_queue:
164+
commit_model = site.get_version_tracker_model().commit_model
165+
can_approve = site.has_change_permission(request, commit_model)
166+
context['save_buttons'] = self.reviewed_buttons[(status, can_approve)]
167+
else:
168+
context['save_buttons'] = self.unreviewed_buttons[status]
169+
if not add:
170+
context['history_url'] = site.reverse(site.history_view, kwargs={'pk': obj.pk})
171+
return super(WidgyPageAdmin, self).render_change_form(request, context, add, change, form_url, obj, *args, **kwargs)
172+
173+
@property
174+
def has_review_queue(self):
175+
return isinstance(self.get_site(), ReviewedWidgySite)
176+
177+
def get_site(self):
178+
return get_site(settings.WIDGY_MEZZANINE_SITE)
179+
61180

62181
class UndeleteField(forms.ModelChoiceField):
63182
widget = forms.RadioSelect
@@ -138,12 +257,55 @@ def __init__(self, *args, **kwargs):
138257
admin.site.register(WidgyPage, WidgyPageAdmin)
139258
admin.site.register(UndeletePage, UndeletePageAdmin)
140259

260+
261+
def publish_page_on_approve(sender, instance, created, **kwargs):
262+
site = get_site(settings.WIDGY_MEZZANINE_SITE)
263+
264+
pages = WidgyPage.objects.filter(
265+
root_node=instance.tracker,
266+
)
267+
if instance.is_approved:
268+
pages = pages.filter(
269+
Q(publish_date__gte=instance.publish_at) |
270+
Q(status=CONTENT_STATUS_DRAFT)
271+
).update(
272+
status=CONTENT_STATUS_PUBLISHED,
273+
publish_date=instance.publish_at,
274+
)
275+
elif not site.get_version_tracker_model().objects.filter(pk=instance.tracker.pk).published().exists():
276+
# unaproving a commit, and there are no other currently published commits
277+
CommitModel = site.get_version_tracker_model().commit_model
278+
beginning_of_validity = CommitModel.objects.approved().filter(
279+
tracker_id=instance.tracker.pk,
280+
publish_at__gt=timezone.now(),
281+
).aggregate(min=Min('publish_at'))['min']
282+
if beginning_of_validity is not None:
283+
# There's a scheduled commit, move publish_date of the page forward
284+
# up to the publish_at of the commit.
285+
pages.update(
286+
publish_date=beginning_of_validity,
287+
status=CONTENT_STATUS_PUBLISHED,
288+
)
289+
else:
290+
# no other published commits at all, page needs to be unpublished
291+
pages.update(
292+
status=CONTENT_STATUS_DRAFT,
293+
)
294+
141295
if 'widgy.contrib.review_queue' in settings.INSTALLED_APPS:
142296
from widgy.contrib.review_queue.admin import VersionCommitAdminBase
143297
from widgy.contrib.review_queue.models import ReviewedVersionCommit
298+
from widgy.contrib.review_queue.site import ReviewedWidgySite
144299

145300
class VersionCommitAdmin(VersionCommitAdminBase):
146301
def get_site(self):
147-
return fancy_import(settings.WIDGY_MEZZANINE_SITE)
302+
return get_site(settings.WIDGY_MEZZANINE_SITE)
148303

149304
admin.site.register(ReviewedVersionCommit, VersionCommitAdmin)
305+
306+
site = get_site(settings.WIDGY_MEZZANINE_SITE)
307+
308+
if isinstance(site, ReviewedWidgySite):
309+
# In the tests, review_queue is installed but a ReviewedWidgySite might
310+
# not be in use.
311+
post_save.connect(publish_page_on_approve, sender=site.get_version_tracker_model().commit_model)
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{% extends "widgy/popup_base.html" %}
2+
{% load i18n %}
3+
4+
{% block content %}
5+
<h1>{% blocktrans with page_title=object.title %}Unpublishing {{ page_title }}{% endblocktrans %}</h1>
6+
<p>
7+
{% blocktrans %}
8+
Unpublishing will cause this page to disappear from the live site. Users who
9+
go to this page will get a 404 (File Not Found) error page. Are you sure you
10+
want to unpublish this page?
11+
{% endblocktrans %}
12+
</p>
13+
<form method="post">
14+
{% csrf_token %}
15+
<div class="submit-row">
16+
<p class="cancellink-box"><a href="../" class="cancellink">{% trans "Cancel" %}</a></p>
17+
<input type="submit" value="{% trans "Yes, I'm sure" %}" class="default" />
18+
</div>
19+
</form>
20+
{% endblock %}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{% extends "widgy/versioned_widgy_field_base.html" %}
2+
{% load i18n %}
3+
{% load staticfiles %}
4+
5+
{% block widgy_tools %}
6+
<li><a class="widgy-fancybox commit" href="{{ commit_url }}">{% trans "Schedule changes" %}</a></li>
7+
<li><a class="widgy-fancybox reset" href="{{ reset_url }}">{% trans "Reset" %}</a></li>
8+
{% endblock %}

0 commit comments

Comments
 (0)