Fixes #6533
Showing 3 of 5 files from the diff.
wagtail/core/models.py
changed.
wagtail/locales/tests.py
changed.
wagtail/locales/views.py
changed.
Other files ignored by Codecov
CHANGELOG.txt
has changed.
docs/releases/2.11.2.rst
has changed.
@@ -373,6 +373,26 @@
Loading
373 | 373 | except (cls.DoesNotExist, LookupError): |
|
374 | 374 | return cls.get_default() |
|
375 | 375 | ||
376 | + | @transaction.atomic |
|
377 | + | def delete(self, *args, **kwargs): |
|
378 | + | # if we're deleting the locale used on the root page node, reassign that to a new locale first |
|
379 | + | root_page_with_this_locale = Page.objects.filter(depth=1, locale=self) |
|
380 | + | if root_page_with_this_locale.exists(): |
|
381 | + | # Select the default locale, if one exists and isn't the one being deleted |
|
382 | + | try: |
|
383 | + | new_locale = Locale.get_default() |
|
384 | + | default_locale_is_ok = (new_locale != self) |
|
385 | + | except (Locale.DoesNotExist, LookupError): |
|
386 | + | default_locale_is_ok = False |
|
387 | + | ||
388 | + | if not default_locale_is_ok: |
|
389 | + | # fall back on any remaining locale |
|
390 | + | new_locale = Locale.all_objects.exclude(pk=self.pk).first() |
|
391 | + | ||
392 | + | root_page_with_this_locale.update(locale=new_locale) |
|
393 | + | ||
394 | + | return super().delete(*args, **kwargs) |
|
395 | + | ||
376 | 396 | def language_code_is_valid(self): |
|
377 | 397 | return self.language_code in get_content_languages() |
|
378 | 398 |
@@ -1,8 +1,8 @@
Loading
1 | 1 | from django.contrib.messages import get_messages |
|
2 | - | from django.test import TestCase |
|
2 | + | from django.test import TestCase, override_settings |
|
3 | 3 | from django.urls import reverse |
|
4 | 4 | ||
5 | - | from wagtail.core.models import Locale |
|
5 | + | from wagtail.core.models import Locale, Page |
|
6 | 6 | from wagtail.tests.utils import WagtailTestUtils |
|
7 | 7 | ||
8 | 8 |
@@ -175,6 +175,10 @@
Loading
175 | 175 | self.assertFalse(Locale.objects.filter(language_code='fr').exists()) |
|
176 | 176 | ||
177 | 177 | def test_cannot_delete_locales_with_pages(self): |
|
178 | + | # create a French locale so that the deletion is not rejected on grounds of being the only |
|
179 | + | # existing locale |
|
180 | + | Locale.objects.create(language_code='fr') |
|
181 | + | ||
178 | 182 | response = self.post() |
|
179 | 183 | ||
180 | 184 | self.assertEqual(response.status_code, 200) |
@@ -186,3 +190,76 @@
Loading
186 | 190 | ||
187 | 191 | # Check that the locale was not deleted |
|
188 | 192 | self.assertTrue(Locale.objects.filter(language_code='en').exists()) |
|
193 | + | ||
194 | + | @override_settings( |
|
195 | + | LANGUAGE_CODE='de-at', |
|
196 | + | WAGTAIL_CONTENT_LANGUAGES=[ |
|
197 | + | ('en', 'English'), |
|
198 | + | ('fr', 'French'), |
|
199 | + | ('de', 'German'), |
|
200 | + | ('pl', 'Polish'), |
|
201 | + | ('ja', 'Japanese') |
|
202 | + | ] |
|
203 | + | ) |
|
204 | + | def test_can_delete_default_locale(self): |
|
205 | + | # The presence of the locale on the root page node (if that's the only thing using the |
|
206 | + | # locale) should not prevent deleting it |
|
207 | + | ||
208 | + | for lang in ('fr', 'de', 'pl', 'ja'): |
|
209 | + | Locale.objects.create(language_code=lang) |
|
210 | + | ||
211 | + | self.assertTrue(Page.get_first_root_node().locale.language_code, 'en') |
|
212 | + | Page.objects.filter(depth__gt=1).delete() |
|
213 | + | response = self.post() |
|
214 | + | ||
215 | + | # Should redirect back to index |
|
216 | + | self.assertRedirects(response, reverse('wagtaillocales:index')) |
|
217 | + | ||
218 | + | # Check that the locale was deleted |
|
219 | + | self.assertFalse(Locale.objects.filter(language_code='en').exists()) |
|
220 | + | ||
221 | + | # root node's locale should now have been reassigned to the one matching the current |
|
222 | + | # LANGUAGE_CODE |
|
223 | + | self.assertTrue(Page.get_first_root_node().locale.language_code, 'de') |
|
224 | + | ||
225 | + | @override_settings( |
|
226 | + | LANGUAGE_CODE='de-at', |
|
227 | + | WAGTAIL_CONTENT_LANGUAGES=[ |
|
228 | + | ('en', 'English'), |
|
229 | + | ('fr', 'French'), |
|
230 | + | ('de', 'German'), |
|
231 | + | ('pl', 'Polish'), |
|
232 | + | ('ja', 'Japanese') |
|
233 | + | ] |
|
234 | + | ) |
|
235 | + | def test_can_delete_default_locale_when_language_code_has_no_locale(self): |
|
236 | + | Locale.objects.create(language_code='fr') |
|
237 | + | ||
238 | + | self.assertTrue(Page.get_first_root_node().locale.language_code, 'en') |
|
239 | + | Page.objects.filter(depth__gt=1).delete() |
|
240 | + | response = self.post() |
|
241 | + | ||
242 | + | # Should redirect back to index |
|
243 | + | self.assertRedirects(response, reverse('wagtaillocales:index')) |
|
244 | + | ||
245 | + | # Check that the locale was deleted |
|
246 | + | self.assertFalse(Locale.objects.filter(language_code='en').exists()) |
|
247 | + | ||
248 | + | # root node's locale should now have been reassigned to 'fr' despite that not matching |
|
249 | + | # LANGUAGE_CODE (because it's the only remaining Locale record) |
|
250 | + | self.assertTrue(Page.get_first_root_node().locale.language_code, 'fr') |
|
251 | + | ||
252 | + | def test_cannot_delete_last_remaining_locale(self): |
|
253 | + | Page.objects.filter(depth__gt=1).delete() |
|
254 | + | ||
255 | + | response = self.post() |
|
256 | + | ||
257 | + | self.assertEqual(response.status_code, 200) |
|
258 | + | ||
259 | + | # Check error message |
|
260 | + | messages = list(get_messages(response.wsgi_request)) |
|
261 | + | self.assertEqual(messages[0].level_tag, 'error') |
|
262 | + | self.assertEqual(messages[0].message, "This locale cannot be deleted because there are no other locales.\n\n\n\n\n") |
|
263 | + | ||
264 | + | # Check that the locale was not deleted |
|
265 | + | self.assertTrue(Locale.objects.filter(language_code='en').exists()) |
@@ -43,14 +43,25 @@
Loading
43 | 43 | ||
44 | 44 | class DeleteView(generic.DeleteView): |
|
45 | 45 | success_message = gettext_lazy("Locale '{0}' deleted.") |
|
46 | - | cannot_delete_message = gettext_lazy("This locale cannot be deleted because there are pages and/or other objects using it.") |
|
47 | 46 | page_title = gettext_lazy("Delete locale") |
|
48 | 47 | confirmation_message = gettext_lazy("Are you sure you want to delete this locale?") |
|
49 | 48 | template_name = 'wagtaillocales/confirm_delete.html' |
|
50 | 49 | queryset = Locale.all_objects.all() |
|
51 | 50 | ||
52 | 51 | def can_delete(self, locale): |
|
53 | - | return get_locale_usage(locale) == (0, 0) |
|
52 | + | if not self.queryset.exclude(pk=locale.pk).exists(): |
|
53 | + | self.cannot_delete_message = gettext_lazy( |
|
54 | + | "This locale cannot be deleted because there are no other locales." |
|
55 | + | ) |
|
56 | + | return False |
|
57 | + | ||
58 | + | if get_locale_usage(locale) != (0, 0): |
|
59 | + | self.cannot_delete_message = gettext_lazy( |
|
60 | + | "This locale cannot be deleted because there are pages and/or other objects using it." |
|
61 | + | ) |
|
62 | + | return False |
|
63 | + | ||
64 | + | return True |
|
54 | 65 | ||
55 | 66 | def get_context_data(self, object=None): |
|
56 | 67 | context = context = super().get_context_data() |
Files | Coverage |
---|---|
client/src | 90.67% |
wagtail | 44.34% |
Project Totals (438 files) | 46.23% |
15868.1
TRAVIS_PYTHON_VERSION=3.6 TRAVIS_OS_NAME=linux TOXENV=py36-dj22-sqlite-elasticsearch2
backend
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file.
The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files.
The size and color of each slice is representing the number of statements and the coverage, respectively.