From 66cb970bee72b77e3192a0882467f92b42dc37cb Mon Sep 17 00:00:00 2001 From: Dimas Ciputra Date: Fri, 23 Sep 2022 22:04:49 +0100 Subject: [PATCH 1/2] Fix navbar responsiveness issue --- qgis-app/static/style/new/basic.css | 18 +++++++++++ qgis-app/static/style/new/qgis-style.css | 40 +++++++++++++++++++++--- qgis-app/templates/base.html | 18 ++++++----- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/qgis-app/static/style/new/basic.css b/qgis-app/static/style/new/basic.css index d4965519..181d6e4c 100755 --- a/qgis-app/static/style/new/basic.css +++ b/qgis-app/static/style/new/basic.css @@ -384,3 +384,21 @@ div.sphinxsidebar, div.related, div.footer, #top-link { display: none; } } + +.navbar-search { + display: flex; + flex-direction: row; + align-items: center; +} + +.navbar-search #id_q { + border-radius: 12px 0 0 12px; + color: black; +} + +.btn-search { + width: fit-content !important; + margin-top: 0 !important; + border-radius: 0 12px 12px 0 !important; +} + diff --git a/qgis-app/static/style/new/qgis-style.css b/qgis-app/static/style/new/qgis-style.css index 2731ecf1..1888b420 100755 --- a/qgis-app/static/style/new/qgis-style.css +++ b/qgis-app/static/style/new/qgis-style.css @@ -171,12 +171,16 @@ pre, code { text-decoration:none !important; } +.signin-wrapper { + height: 60px; + float: right !important; + display: flex; + align-items: center; + padding: 0 20px 0 20px; +} + .icon-signin { color: #fff; - top: 100px !important; - float: right !important; - margin: 16px 0 0 20px !important; - text-decoration:none !important; } .navbar-inner > select body, .navbar-inner > select html { @@ -770,3 +774,31 @@ section.sponsors { height: 16px; display:block; } + + +@media (max-width: 500px) { + #page_bg { + width: 100%; + } + .navbar .brand { + background-size: 30px !important; + height: 30px; + width: 30px; + margin: 10px 0 0 0 !important; + } + + .navbar-search { + margin: 10px 0 0 0 !important; + } + + .signin-wrapper { + height: 100%; + margin-top: 3px; + } +} + +@media (max-width: 375px) { + .navbar .brand { + display: none; + } +} diff --git a/qgis-app/templates/base.html b/qgis-app/templates/base.html index 4e75ecc0..64861a98 100644 --- a/qgis-app/templates/base.html +++ b/qgis-app/templates/base.html @@ -46,17 +46,19 @@ - QGIS - {% if user.is_authenticated %} - - {% else %} - - {% endif %} + QGIS + {% if user.is_authenticated %} + + {% else %} +
+ +
+ {% endif %} {% get_namedmenu Navigation as menu %} From 8cb6c346b2ab538326d2c4ddb0911b0ab649547f Mon Sep 17 00:00:00 2001 From: Dimas Ciputra Date: Tue, 14 Mar 2023 17:35:37 +0700 Subject: [PATCH 2/2] Add support for renaming plugin package_name --- qgis-app/plugins/admin.py | 21 ++++++- qgis-app/plugins/api.py | 4 ++ .../migrations/0002_auto_20230314_0341.py | 28 +++++++++ qgis-app/plugins/models.py | 59 +++++++++++++++++-- qgis-app/plugins/urls.py | 4 +- qgis-app/plugins/views.py | 44 ++++++++++++-- 6 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 qgis-app/plugins/migrations/0002_auto_20230314_0341.py diff --git a/qgis-app/plugins/admin.py b/qgis-app/plugins/admin.py index 01649c9f..f5f1e89b 100644 --- a/qgis-app/plugins/admin.py +++ b/qgis-app/plugins/admin.py @@ -1,5 +1,8 @@ from django.contrib import admin -from plugins.models import Plugin, PluginVersion # , PluginCrashReport +from plugins.models import ( + Plugin, PluginVersion, + PluginLegacyName# , PluginCrashReport +) class PluginAdmin(admin.ModelAdmin): @@ -26,12 +29,28 @@ class PluginVersionAdmin(admin.ModelAdmin): "created_on", "downloads", ) + search_fields = ( + 'plugin__name', + ) # class PluginCrashReportAdmin(admin.ModelAdmin): # pass +class PluginLegacyNameAdmin(admin.ModelAdmin): + list_display = ( + 'plugin', + 'package_name', + 'created_on' + ) + readonly_fields = ( + 'created_on', + 'package_name' + ) + + admin.site.register(Plugin, PluginAdmin) admin.site.register(PluginVersion, PluginVersionAdmin) +admin.site.register(PluginLegacyName, PluginLegacyNameAdmin) # admin.site.register(PluginCrashReport, PluginCrashReportAdmin) diff --git a/qgis-app/plugins/api.py b/qgis-app/plugins/api.py index e2270fd4..4a5dc5b5 100644 --- a/qgis-app/plugins/api.py +++ b/qgis-app/plugins/api.py @@ -71,6 +71,10 @@ def plugin_upload(package, **kwargs): } # Gets existing plugin + if Plugin.objects.filter( + name__iexact=plugin_data['name'] + ).exclude(package_name__iexact=plugin_data['package_name']).count(): + raise Fault(1, 'Error: The package name for this plugin has changed.') try: plugin = Plugin.objects.get(package_name=plugin_data["package_name"]) # Apply new values diff --git a/qgis-app/plugins/migrations/0002_auto_20230314_0341.py b/qgis-app/plugins/migrations/0002_auto_20230314_0341.py new file mode 100644 index 00000000..8e73091a --- /dev/null +++ b/qgis-app/plugins/migrations/0002_auto_20230314_0341.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2.25 on 2023-03-14 03:41 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('plugins', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='plugin', + name='package_name', + field=models.CharField(help_text="This is the plugin's internal name, equals to the main folder name. Must start with an ASCII letter and can contain only ASCII letters, digits and the - and _ signs.", max_length=256, unique=True, verbose_name='Package Name'), + ), + migrations.CreateModel( + name='PluginLegacyName', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_on', models.DateTimeField(auto_now_add=True, verbose_name='Created on')), + ('package_name', models.CharField(blank=True, editable=False, help_text="This is the plugin's internal name, equals to the main folder name", max_length=256, null=True, verbose_name='Package Name')), + ('plugin', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='plugins.Plugin')), + ], + ), + ] diff --git a/qgis-app/plugins/models.py b/qgis-app/plugins/models.py index a37ea761..c9a9239d 100644 --- a/qgis-app/plugins/models.py +++ b/qgis-app/plugins/models.py @@ -7,6 +7,7 @@ from django.conf import settings from django.contrib.auth.models import User from django.db import models +from django.db.models import Q from django.urls import reverse from django.utils.translation import ugettext_lazy as _ from djangoratings.fields import AnonymousRatingField @@ -309,11 +310,12 @@ class Plugin(models.Model): package_name = models.CharField( _("Package Name"), help_text=_( - "This is the plugin's internal name, equals to the main folder name" + "This is the plugin's internal name, equals to the main folder name. " + "Must start with an ASCII letter and can contain only ASCII letters, digits and the - and _ signs." ), max_length=256, unique=True, - editable=False, + editable=True, ) name = models.CharField( _("Name"), help_text=_("Must be unique"), max_length=256, unique=True @@ -471,11 +473,16 @@ def clean(self): ) if self.pk: - qs = Plugin.objects.filter(package_name__iexact=self.package_name).exclude( + qs = Plugin.objects.filter( + Q(package_name__iexact=self.package_name) | + Q(pluginlegacyname__package_name__iexact=self.package_name) + ).exclude( pk=self.pk ) else: - qs = Plugin.objects.filter(package_name__iexact=self.package_name) + qs = Plugin.objects.filter( + Q(package_name__iexact=self.package_name) | + Q(pluginlegacyname__package_name__iexact=self.package_name)) if qs.count(): raise ValidationError( _( @@ -768,6 +775,30 @@ def __str__(self): return self.__unicode__() +class PluginLegacyName(models.Model): + plugin = models.ForeignKey( + Plugin, + on_delete=models.CASCADE) + + created_on = models.DateTimeField( + _("Created on"), + auto_now_add=True, + editable=False + ) + + # name, desc etc. + package_name = models.CharField( + _("Package Name"), + help_text=_( + "This is the plugin's internal name, equals to the main folder name" + ), + null=True, + blank=True, + max_length=256, + editable=False, + ) + + def delete_version_package(sender, instance, **kw): """ Removes the zip package @@ -788,5 +819,25 @@ def delete_plugin_icon(sender, instance, **kw): pass +def plugin_rename(sender, instance, **kwargs): + """ + Add old plugin name to plugin_legacy_name + """ + if not PluginVersion.objects.filter( + plugin=instance + ).exists(): + return None + try: + old_instance = Plugin.objects.get(id=instance.id) + if old_instance.package_name != instance.package_name: + PluginLegacyName.objects.get_or_create( + plugin=instance, + package_name=old_instance.package_name + ) + except Plugin.DoesNotExist: + return None + + models.signals.post_delete.connect(delete_version_package, sender=PluginVersion) models.signals.post_delete.connect(delete_plugin_icon, sender=Plugin) +models.signals.pre_save.connect(plugin_rename, sender=Plugin) diff --git a/qgis-app/plugins/urls.py b/qgis-app/plugins/urls.py index 50c6c05e..952450cd 100644 --- a/qgis-app/plugins/urls.py +++ b/qgis-app/plugins/urls.py @@ -279,9 +279,7 @@ urlpatterns += [ url( r"^(?P[A-Za-z][A-Za-z0-9-_]+)/$", - PluginDetailView.as_view( - slug_url_kwarg="package_name", slug_field="package_name" - ), + PluginDetailView.as_view(), name="plugin_detail", ), ] diff --git a/qgis-app/plugins/views.py b/qgis-app/plugins/views.py index 1c65043b..d851c255 100644 --- a/qgis-app/plugins/views.py +++ b/qgis-app/plugins/views.py @@ -43,6 +43,17 @@ from plugins.tasks.generate_plugins_xml import generate_plugins_xml +def get_plugin(package_name: str) -> Plugin: + """Get the plugin from package_name""" + try: + return Plugin.objects.get( + Q(package_name=package_name) | + Q(pluginlegacyname__package_name=package_name) + ) + except Plugin.DoesNotExist: + raise Http404() + + def send_mail_wrapper(subject, message, mail_from, recipients, fail_silently=True): if settings.DEBUG: logging.debug("Mail not sent (DEBUG=True)") @@ -297,6 +308,7 @@ def plugin_upload(request): """ if request.method == "POST": form = PackageUploadForm(request.POST, request.FILES) + plugin = None if form.is_valid(): try: plugin_data = { @@ -306,11 +318,20 @@ def plugin_upload(request): "created_by": request.user, "author": form.cleaned_data["author"], "email": form.cleaned_data["email"], - "created_by": request.user, "icon": form.cleaned_data["icon_file"], } # Gets existing plugin + if Plugin.objects.filter( + name__iexact=plugin_data['name'] + ).exclude( + package_name__iexact=plugin_data['package_name'] + ).count(): + raise ValidationError( + _( + 'Error: The package name for this plugin has changed.' + ) + ) try: plugin = Plugin.objects.get( package_name=plugin_data["package_name"] @@ -381,7 +402,7 @@ def plugin_upload(request): # Takes care of tags if form.cleaned_data.get("tags"): plugin.tags.set( - *[ + [ t.strip().lower() for t in form.cleaned_data.get("tags").split(",") ] @@ -434,7 +455,7 @@ def plugin_upload(request): except (IntegrityError, ValidationError, DjangoUnicodeDecodeError) as e: connection.close() messages.error(request, e, fail_silently=True) - if not plugin.pk: + if not plugin or not plugin.pk: return render(request, "plugins/plugin_upload.html", {"form": form}) return HttpResponseRedirect(plugin.get_absolute_url()) else: @@ -447,6 +468,19 @@ class PluginDetailView(DetailView): model = Plugin queryset = Plugin.objects.all() + def get_object(self, queryset=None): + if queryset is None: + queryset = self.get_queryset() + package_name = self.kwargs.get('package_name') + try: + return queryset.get( + Q(package_name__iexact=package_name) | + Q(pluginlegacyname__package_name__iexact=package_name) + ) + except Plugin.DoesNotExist: + raise Http404(_("No %(verbose_name)s found matching the query") % + {'verbose_name': queryset.model._meta.verbose_name}) + @method_decorator(ensure_csrf_cookie) def dispatch(self, *args, **kwargs): return super(PluginDetailView, self).dispatch(*args, **kwargs) @@ -1022,7 +1056,7 @@ def version_download(request, package_name, version): """ Update download counter(s) """ - plugin = get_object_or_404(Plugin, package_name=package_name) + plugin = get_plugin(package_name) version = get_object_or_404(PluginVersion, plugin=plugin, version=version) version.downloads = version.downloads + 1 version.save() @@ -1045,7 +1079,7 @@ def version_detail(request, package_name, version): """ Show version details """ - plugin = get_object_or_404(Plugin, package_name=package_name) + plugin = get_plugin(package_name) version = get_object_or_404(PluginVersion, plugin=plugin, version=version) return render(request, "plugins/version_detail.html", {"version": version})