diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6288aa3..b8fba58 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,7 @@ Unreleased ========== * Introduced Django 4.2 support. * Dropped Support for Django<3.1 +* Dropped the dependency of `aldryn-translation-tools` 1.0.2 (2023-02-24) ================== diff --git a/MANIFEST.in b/MANIFEST.in index a5e100c..02e5cce 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,6 +3,7 @@ include README.rst include CHANGELOG.rst recursive-include aldryn_redirects/locale * recursive-include aldryn_redirects/migrations * +recursive-include aldryn_redirects/static * recursive-include aldryn_redirects/templates * recursive-exclude * *.pyc diff --git a/aldryn_redirects/admin.py b/aldryn_redirects/admin.py index 71d11ee..6ec4b41 100644 --- a/aldryn_redirects/admin.py +++ b/aldryn_redirects/admin.py @@ -1,12 +1,16 @@ from django.conf import settings from django.contrib import admin, messages +from django.forms import widgets from django.http import HttpResponse from django.shortcuts import redirect, render from django.urls import reverse from django.utils import timezone +from django.utils.encoding import force_str from django.utils.translation import gettext, gettext_lazy as _ -from aldryn_translation_tools.admin import AllTranslationsMixin +from cms.utils.i18n import get_current_language +from cms.utils.urlutils import admin_reverse + from parler.admin import TranslatableAdmin from tablib import Dataset @@ -46,6 +50,67 @@ def delete_selected(self, request, queryset): self.message_user(request, msg) +class AllTranslationsMixin(object): + + @property + def media(self): + return super().media + widgets.Media( + css={'all': ('css/admin/all-translations-mixin.css', ), } + ) + + @admin.display( + description='Translations' + ) + def all_translations(self, obj): + """ + Adds a property to the list_display that lists all translations with + links directly to their change forms. Includes CSS to style the links + to looks like tags with color indicating current language, active and + inactive translations. + + A similar capability is in HVAD, and now there is this for + Parler-based projects. + """ + available = list(obj.get_available_languages()) + current = get_current_language() + langs = [] + for code, lang_name in settings.LANGUAGES: + classes = ["lang-code", ] + title = force_str(lang_name) + if code == current: + classes += ["current", ] + if code in available: + classes += ["active", ] + title += " (translated)" + else: + title += " (untranslated)" + change_form_url = admin_reverse( + '{app_label}_{model_name}_change'.format( + app_label=obj._meta.app_label.lower(), + model_name=obj.__class__.__name__.lower(), + ), args=(obj.id, ) + ) + link = '{code}'.format( + classes=' '.join(classes), + url=change_form_url, + code=code, + title=title, + ) + langs.append(link) + return ''.join(langs) + + def get_list_display(self, request): + """ + Unless the the developer has already placed "all_translations" in the + list_display list (presumably specifically where she wants it), append + the list of translations to the end. + """ + list_display = super().get_list_display(request) + if 'all_translations' not in list_display: + list_display = list(list_display) + ['all_translations', ] + return list_display + + @admin.register(Redirect) class RedirectAdmin(DeletionMixin, AllTranslationsMixin, TranslatableAdmin): list_display = ('old_path',) diff --git a/aldryn_redirects/south_migrations/0001_initial.py b/aldryn_redirects/south_migrations/0001_initial.py deleted file mode 100644 index 33e4bc9..0000000 --- a/aldryn_redirects/south_migrations/0001_initial.py +++ /dev/null @@ -1,81 +0,0 @@ -from south.db import db -from south.v2 import SchemaMigration - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding model 'RedirectTranslation' - db.create_table(u'aldryn_redirects_redirect_translation', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('new_path', self.gf('django.db.models.fields.CharField')(max_length=200, blank=True)), - ('language_code', self.gf('django.db.models.fields.CharField')(max_length=15, db_index=True)), - ( - 'master', - self.gf('django.db.models.fields.related.ForeignKey') - (related_name='translations', null=True, to=orm['aldryn_redirects.Redirect'])), - )) - db.send_create_signal(u'aldryn_redirects', ['RedirectTranslation']) - - # Adding unique constraint on 'RedirectTranslation', fields ['language_code', 'master'] - db.create_unique(u'aldryn_redirects_redirect_translation', ['language_code', 'master_id']) - - # Adding model 'Redirect' - db.create_table(u'aldryn_redirects_redirect', ( - (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ( - 'site', - self.gf('django.db.models.fields.related.ForeignKey') - (related_name='redirects_hvad_set', to=orm['sites.Site']) - ), - ('old_path', self.gf('django.db.models.fields.CharField')(max_length=200, db_index=True)), - )) - db.send_create_signal(u'aldryn_redirects', ['Redirect']) - - # Adding unique constraint on 'Redirect', fields ['site', 'old_path'] - db.create_unique(u'aldryn_redirects_redirect', ['site_id', 'old_path']) - - def backwards(self, orm): - # Removing unique constraint on 'Redirect', fields ['site', 'old_path'] - db.delete_unique(u'aldryn_redirects_redirect', ['site_id', 'old_path']) - - # Removing unique constraint on 'RedirectTranslation', fields ['language_code', 'master'] - db.delete_unique(u'aldryn_redirects_redirect_translation', ['language_code', 'master_id']) - - # Deleting model 'RedirectTranslation' - db.delete_table(u'aldryn_redirects_redirect_translation') - - # Deleting model 'Redirect' - db.delete_table(u'aldryn_redirects_redirect') - - models = { - u'aldryn_redirects.redirect': { - 'Meta': - {'ordering': "('old_path',)", 'unique_together': "(('site', 'old_path'),)", 'object_name': 'Redirect'}, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'old_path': ('django.db.models.fields.CharField', [], {'max_length': '200', 'db_index': 'True'}), - 'site': ('django.db.models.fields.related.ForeignKey', [], - {'related_name': "'redirects_hvad_set'", 'to': u"orm['sites.Site']"}) - }, - u'aldryn_redirects.redirecttranslation': { - 'Meta': - {'unique_together': "[('language_code', 'master')]", - 'object_name': 'RedirectTranslation', - 'db_table': "u'aldryn_redirects_redirect_translation'" - }, - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'language_code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'db_index': 'True'}), - 'master': ( - 'django.db.models.fields.related.ForeignKey', [], - {'related_name': "'translations'", 'null': 'True', 'to': u"orm['aldryn_redirects.Redirect']"}), - 'new_path': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}) - }, - u'sites.site': { - 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, - 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['aldryn_redirects'] diff --git a/aldryn_redirects/south_migrations/__init__.py b/aldryn_redirects/south_migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/aldryn_redirects/static/css/admin/all-translations-mixin.css b/aldryn_redirects/static/css/admin/all-translations-mixin.css new file mode 100644 index 0000000..37eb7b0 --- /dev/null +++ b/aldryn_redirects/static/css/admin/all-translations-mixin.css @@ -0,0 +1,23 @@ +a.lang-code { + background-color: #BFBFBF; /* hsl(0, 0%, 75%); */ + border-radius: 3px; + color: #fff !important; + display: inline-block; + font-size: 0.75em; + letter-spacing: 0.05em; + line-height: 1em; + margin-right: 0.25em; + padding: 3px; + text-decoration: none; + text-transform: uppercase; +} +a.lang-code.active { + background-color: #3B99FC; /* hsl(211, 97%, 61%) */ +} +a.lang-code.current { + background-color: #999999; /* hsl(0, 0%, 60%); */ + font-weight: bold; +} +a.lang-code.current.active { + background-color: #3178BE; /* hsl(211, 59%, 48%) */ +} diff --git a/setup.py b/setup.py index f3a1a72..8658a7e 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,6 @@ REQUIREMENTS = [ 'tablib', 'django-parler', - 'aldryn-translation-tools', ] CLASSIFIERS = [ diff --git a/tests/requirements/requirements_base.txt b/tests/requirements/requirements_base.txt index f50129a..4f2eb3b 100644 --- a/tests/requirements/requirements_base.txt +++ b/tests/requirements/requirements_base.txt @@ -1,4 +1,3 @@ -aldryn-translation-tools asgiref beautifulsoup4 coverage>=4.4.2 diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 5a0699a..ac17da5 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -1,6 +1,7 @@ from __future__ import division, print_function from django.contrib.sites.models import Site +from django.http.response import HttpResponse from django.test import TestCase from django.test.client import RequestFactory @@ -8,6 +9,10 @@ from aldryn_redirects.models import StaticRedirect +def get_response(): + return HttpResponse() + + class RedirectFallbackMiddlewareTestCase(TestCase): def setUp(self, *args, **kwargs): super(RedirectFallbackMiddlewareTestCase, self).setUp(*args, **kwargs) @@ -20,7 +25,7 @@ def test_redirect_found(self): redirect.sites.add(self.site) redirect.query_params.create(key='query1', value='param1') - response = RedirectFallbackMiddleware().process_request(self.request) + response = RedirectFallbackMiddleware(get_response).process_request(self.request) self.assertEquals(response.status_code, 301) self.assertEquals(response.url, 'http://example.com/dest?keep=this') @@ -31,10 +36,10 @@ def test_redirect_found_from_root(self): redirect.query_params.create(key='query1', value='param1') request_from_root = RequestFactory().get('http://example.com/?query1=param1') - response = RedirectFallbackMiddleware().process_request(request_from_root) + response = RedirectFallbackMiddleware(get_response).process_request(request_from_root) self.assertEquals(response.status_code, 301) self.assertEquals(response.url, 'http://example.com/dest?keep=this') def test_redirect_not_found(self): - self.assertIsNone(RedirectFallbackMiddleware().process_request(self.request)) + self.assertIsNone(RedirectFallbackMiddleware(get_response).process_request(self.request))