[extensions-web/wip/visual-tag: 4/4] extensions: improved metadata's session_modes handling




commit 0a587a5684650540b0d64f85b5a431eb3c18a6d2
Author: Yuri Konotopov <ykonotopov gnome org>
Date:   Sun Apr 24 21:03:27 2022 +0400

    extensions: improved metadata's session_modes handling
    
    1. Save all session_modes with extension version
    2. Pre-populate session_modes property for existent extensions
    3. Added tests

 .../0010_extension_session_unlock_dialog.py        | 18 --------
 .../extensions/migrations/0010_session_modes.py    | 51 ++++++++++++++++++++++
 sweettooth/extensions/models.py                    | 38 ++++++++++++----
 .../extensions/templates/extensions/detail.html    |  4 +-
 sweettooth/extensions/tests.py                     | 50 ++++++++++++++++++++-
 5 files changed, 132 insertions(+), 29 deletions(-)
---
diff --git a/sweettooth/extensions/migrations/0010_session_modes.py 
b/sweettooth/extensions/migrations/0010_session_modes.py
new file mode 100644
index 0000000..3b47029
--- /dev/null
+++ b/sweettooth/extensions/migrations/0010_session_modes.py
@@ -0,0 +1,51 @@
+import json
+
+from django.db import migrations, models
+from django.apps.registry import Apps
+from sweettooth.extensions.models import (
+    ExtensionVersion as ExtensionVersionModel,
+    SessionMode as SessionModeModel,
+)
+
+def apply(apps: Apps, schema_editor):
+    ExtensionVersion: ExtensionVersionModel = apps.get_model("extensions", "ExtensionVersion")
+    SessionMode: SessionModeModel = apps.get_model("extensions", "SessionMode")
+
+    for version in ExtensionVersion.objects.all():
+        metadata = json.loads(version.extra_json_fields)
+        version.session_modes.set([
+            SessionMode.objects.get(pk=mode)
+            for mode in metadata.get('session_modes', [])
+        ])
+
+        if version.session_modes:
+            version.save()
+
+    for mode in SessionModeModel.SessionModes.values:
+        SessionMode.objects.create(mode=mode)
+
+
+def revert(apps: Apps, schema_editor):
+    pass
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('extensions', '0009_shell40_minor_version'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='SessionMode',
+            fields=[
+                ('mode', models.CharField(choices=[('user', 'User'), ('unlock-dialog', 'Unlock Dialog'), 
('gdm', 'Gdm')], max_length=16, primary_key=True, serialize=False)),
+            ],
+        ),
+        migrations.AddField(
+            model_name='extensionversion',
+            name='session_modes',
+            field=models.ManyToManyField(to='extensions.SessionMode'),
+        ),
+        migrations.RunPython(apply, revert),
+    ]
diff --git a/sweettooth/extensions/models.py b/sweettooth/extensions/models.py
index 1f11a30..c9b89ad 100644
--- a/sweettooth/extensions/models.py
+++ b/sweettooth/extensions/models.py
@@ -10,6 +10,7 @@
     (at your option) any later version.
 """
 
+from typing import Any
 import autoslug
 import json
 import os
@@ -104,6 +105,19 @@ def make_icon_filename(obj, filename=None):
     return "icons/icon_%d%s" % (obj.pk, ext)
 
 
+class SessionMode(models.Model):
+    class SessionModes(models.TextChoices):
+        USER = 'user'
+        UNLOCK_DIALOG = 'unlock-dialog'
+        GDM = 'gdm'
+
+    mode = models.CharField(
+        primary_key=True,
+        max_length=16,
+        choices=SessionModes.choices,
+    )
+
+
 class Extension(models.Model):
     name = models.CharField(max_length=200)
     uuid = models.CharField(max_length=200, unique=True, db_index=True)
@@ -111,7 +125,6 @@ class Extension(models.Model):
     creator = models.ForeignKey(settings.AUTH_USER_MODEL, db_index=True, on_delete=models.PROTECT)
     description = models.TextField(blank=True)
     url = HttpURLField(blank=True)
-    session_unlock_dialog = models.BooleanField(default=False)
     created = models.DateTimeField(auto_now_add=True)
     downloads = models.PositiveIntegerField(default=0)
     popularity = models.IntegerField(default=0)
@@ -134,12 +147,6 @@ class Extension(models.Model):
         self.description = metadata.pop('description', "")
         self.url = metadata.pop('url', "")
         self.uuid = metadata['uuid']
-        try:
-            session_info = metadata.pop('session-modes', "")
-            if "unlock-dialog" in session_info or session_info is "unlock-dialog":
-                self.session_unlock_dialog = True
-        except:
-            pass
 
     def clean(self):
         from django.core.exceptions import ValidationError
@@ -169,6 +176,14 @@ class Extension(models.Model):
             return True
         return False
 
+    def uses_session_mode(self, mode: str):
+        return any(
+            session_mode
+            for version in self.visible_versions.order_by('-pk')
+            for session_mode in version.session_modes.all()
+            if session_mode.mode == mode
+        )
+
     @property
     def first_line_of_description(self):
         if not self.description:
@@ -358,6 +373,7 @@ class ExtensionVersion(models.Model):
     extra_json_fields = models.TextField()
     status = models.PositiveIntegerField(choices=STATUSES.items())
     shell_versions = models.ManyToManyField(ShellVersion)
+    session_modes = models.ManyToManyField(SessionMode)
 
     class Meta:
         unique_together = ('extension', 'version'),
@@ -443,7 +459,7 @@ class ExtensionVersion(models.Model):
 
         super().save(*args, **kwargs)
 
-    def parse_metadata_json(self, metadata):
+    def parse_metadata_json(self, metadata: dict[str, Any]):
         """
         Given the contents of a metadata.json file, fill in the fields
         of the version and associated extension.
@@ -464,6 +480,12 @@ class ExtensionVersion(models.Model):
             else:
                 self.shell_versions.add(sv)
 
+        if 'session-modes' in metadata:
+            self.session_modes.set([
+                SessionMode.objects.get(mode=mode)
+                for mode in metadata['session-modes']
+            ])
+
     def get_absolute_url(self):
         return self.extension.get_absolute_url()
 
diff --git a/sweettooth/extensions/templates/extensions/detail.html 
b/sweettooth/extensions/templates/extensions/detail.html
index 65de4d2..c29bde3 100644
--- a/sweettooth/extensions/templates/extensions/detail.html
+++ b/sweettooth/extensions/templates/extensions/detail.html
@@ -54,12 +54,12 @@
               <dd><a href="{{ extension.url }}" id="extension_url">{{ extension.url }}</a></dd>
               {% endif %}
             </dl>
+            {% if extension.uses_session_mode('unlock-dialog') %}
             <dl>
-              {% if extension.session_unlock_dialog %}
               <dt>{% trans "Session Mode(s)" %}</dt>
               <dd><button type="disabled" class="btn btn-info btn-sm" title="{% trans "This extension will 
run while the screen is locked" %}">{% trans "Unlock Dialog" %}</button></dd>
-              {% endif %}
             </dl>
+            {% endif %}
             <dl>
               <dt>{% trans "Download" %}</dt>
               <dd class="extension-download">
diff --git a/sweettooth/extensions/tests.py b/sweettooth/extensions/tests.py
index 5bd3c46..309050f 100644
--- a/sweettooth/extensions/tests.py
+++ b/sweettooth/extensions/tests.py
@@ -2,7 +2,6 @@
 import os.path
 import json
 import tempfile
-import unittest
 from io import BytesIO
 from uuid import uuid4
 from zipfile import ZipFile
@@ -78,6 +77,55 @@ class ExtensionPropertiesTest(BasicUserTestCase, TestCase):
 
         self.assertEqual(version.shell_versions_json, '["3.2", "3.2.1"]')
 
+    def test_session_mode(self):
+        metadata = {"uuid": "something1 example com",
+                    "name": "Test Metadata",
+                    "shell-version": ["42"],
+                    "session-modes": [
+                        'forbidden'
+                    ]}
+
+        extension = models.Extension.objects.create_from_metadata(metadata, creator=self.user)
+        version = models.ExtensionVersion.objects.create(extension=extension,
+                                                         status=models.STATUS_UNREVIEWED)
+        with self.assertRaises(models.SessionMode.DoesNotExist):
+            version.parse_metadata_json(metadata)
+
+        metadata = {"uuid": "something2 example com",
+                    "name": "Test Metadata",
+                    "session-modes": [
+                        'unlock-dialog'
+                    ]}
+        extension = models.Extension.objects.create_from_metadata(metadata, creator=self.user)
+        version = models.ExtensionVersion.objects.create(extension=extension,
+                                                            status=models.STATUS_UNREVIEWED)
+        version.parse_metadata_json(metadata)
+        version.save()
+
+        self.assertEqual([mode.mode for mode in version.session_modes.all()], ['unlock-dialog'])
+        self.assertFalse(extension.uses_session_mode('unlock-dialog'))
+
+        version.status = models.STATUS_ACTIVE
+        version.save()
+        self.assertTrue(extension.uses_session_mode('unlock-dialog'))
+
+        metadata = {"uuid": "something3 example com",
+                    "name": "Test Metadata",
+                    "session-modes": [
+                        'gdm',
+                        'unlock-dialog'
+                    ]}
+        extension = models.Extension.objects.create_from_metadata(metadata, creator=self.user)
+        version = models.ExtensionVersion.objects.create(extension=extension,
+                                                            status=models.STATUS_ACTIVE)
+        version.parse_metadata_json(metadata)
+        version.save()
+
+        self.assertEqual([mode.mode for mode in version.session_modes.all()], ['gdm', 'unlock-dialog'])
+        self.assertTrue(extension.uses_session_mode('gdm'))
+        self.assertTrue(extension.uses_session_mode('unlock-dialog'))
+        self.assertFalse(extension.uses_session_mode('user'))
+
 class ParseZipfileTest(BasicUserTestCase, TestCase):
     def test_simple_metadata(self):
         metadata = {"uuid": "test-metadata mecheye net",


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]