diff --git a/docs/conf.py b/docs/conf.py index 8ade9a1e..b29c95cb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -17,9 +17,9 @@ # -- Project information ----------------------------------------------------- -project = 'Jandig ARte Help' -copyright = '2019, pablodiegoss, rodrigocam, vjpixel, hvalois' -author = 'pablodiegoss, rodrigocam, vjpixel, hvalois' +project = "Jandig ARte Help" +copyright = "2019, pablodiegoss, rodrigocam, vjpixel, hvalois" +author = "pablodiegoss, rodrigocam, vjpixel, hvalois" # -- General configuration --------------------------------------------------- @@ -27,18 +27,17 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ -] +extensions = [] # Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +templates_path = ["_templates"] # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = 'pt_BR' +language = "pt_BR" # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. @@ -51,28 +50,29 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # -html_theme = 'alabaster' +html_theme = "alabaster" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ["_static"] html_theme_options = { - 'logo': 'logo.png', - 'github_user': 'memeLab', - 'github_repo': 'Jandig', - 'html_sidebars': { - '**': [ - 'search.html', - 'navigation.html', - ] + "logo": "logo.png", + "github_user": "memeLab", + "github_repo": "Jandig", + "html_sidebars": { + "**": [ + "search.html", + "navigation.html", + ] }, - 'extra_nav_links': { - 'Official Site': 'https://jandig.app', - 'Github': 'https://github.com/memelab/Jandig' + "extra_nav_links": { + "Official Site": "https://jandig.app", + "Github": "https://github.com/memelab/Jandig", }, } + def setup(app): - app.add_css_file('reset.css') \ No newline at end of file + app.add_css_file("reset.css") diff --git a/etc/scripts/compilemessages.py b/etc/scripts/compilemessages.py index 2af14779..0521787e 100644 --- a/etc/scripts/compilemessages.py +++ b/etc/scripts/compilemessages.py @@ -2,10 +2,10 @@ import glob import os -from subprocess import Popen, PIPE +from subprocess import PIPE, Popen -program = 'msgfmt' -program_options = ['--check-format', '-f'] +program = "msgfmt" +program_options = ["--check-format", "-f"] def main(): @@ -14,26 +14,26 @@ def main(): django.core.management.commands.compilemessages """ # Walk entire tree, looking for locale directories - basedirs = ['locale'] - for dirpath, dirnames, filenames in os.walk('.', topdown=True): + basedirs = ["locale"] + for dirpath, dirnames, filenames in os.walk(".", topdown=True): for dirname in dirnames: - if dirname == 'locale': + if dirname == "locale": basedirs.append(os.path.join(dirpath, dirname)) basedirs = set(map(os.path.abspath, filter(os.path.isdir, basedirs))) # Build locale list all_locales = [] for basedir in basedirs: - locale_dirs = filter(os.path.isdir, glob.glob(f'{basedir}/*')) + locale_dirs = filter(os.path.isdir, glob.glob(f"{basedir}/*")) all_locales.extend(map(os.path.basename, locale_dirs)) locales = set(all_locales) for basedir in basedirs: - dirs = [os.path.join(basedir, locale, 'LC_MESSAGES') for locale in locales] + dirs = [os.path.join(basedir, locale, "LC_MESSAGES") for locale in locales] locations = [] for ldir in dirs: for dirpath, dirnames, filenames in os.walk(ldir): - locations.extend((dirpath, f) for f in filenames if f.endswith('.po')) + locations.extend((dirpath, f) for f in filenames if f.endswith(".po")) compile_messages(locations) @@ -42,21 +42,21 @@ def compile_messages(locations): Locations is a list of tuples: [(directory, file), ...] """ for _, (dirpath, f) in enumerate(locations): - print(f'processing file {f} in {dirpath}\n') + print(f"processing file {f} in {dirpath}\n") # Program args po_path = os.path.join(dirpath, f) base_path = os.path.splitext(po_path)[0] - extra_args = ['-o', base_path + '.mo', base_path + '.po'] + extra_args = ["-o", base_path + ".mo", base_path + ".po"] args = [program] + program_options + extra_args # Execute command __, errors, status = popen_wrapper(args) if status: if errors: - msg = f'Execution of {program} failed: {errors}' + msg = f"Execution of {program} failed: {errors}" else: - msg = f'Execution of {program} failed' + msg = f"Execution of {program} failed" raise RuntimeError(msg) @@ -68,8 +68,8 @@ def popen_wrapper(args, os_err_exc_type=RuntimeError): with Popen(args, shell=False, stdout=PIPE, stderr=PIPE, close_fds=True) as p: output, errors = p.communicate() return output, errors, p.returncode - raise os_err_exc_type('Error executing') + raise os_err_exc_type("Error executing") -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/src/core/admin.py b/src/core/admin.py index 2211979b..e5af7e08 100644 --- a/src/core/admin.py +++ b/src/core/admin.py @@ -1,6 +1,5 @@ -from django.contrib import admin - from core.models import Artwork, Exhibit, Marker, Object +from django.contrib import admin admin.site.register(Exhibit) admin.site.register(Object) diff --git a/src/core/models.py b/src/core/models.py index 8f301cb3..4197da51 100644 --- a/src/core/models.py +++ b/src/core/models.py @@ -1,24 +1,22 @@ +import logging import re +from config.storage_backends import PublicMediaStorage from django.core.files.base import ContentFile from django.db import models from django.db.models.signals import post_delete from django.dispatch import receiver from PIL import Image from pymarker.core import generate_marker_from_image, generate_patt_from_image - -from config.storage_backends import PublicMediaStorage from users.models import Profile -import logging log = logging.getLogger() + def create_patt(filename, original_filename): filestorage = PublicMediaStorage() with Image.open(filestorage.open(filename)) as image: patt_str = generate_patt_from_image(image) - # string_file = StringIO(patt_str.encode('UTF-8')) - # string_file.name = original_filename patt_file = filestorage.save( "patts/" + original_filename + ".patt", ContentFile(patt_str.encode("utf-8")), @@ -32,12 +30,13 @@ def create_marker(filename, original_filename): marker_image = generate_marker_from_image(image) marker_image.name = original_filename marker_image.__commited = False - # marker = filestorage.save("markers/" + original_filename, marker_image) return marker_image class Marker(models.Model): - owner = models.ForeignKey(Profile, on_delete=models.DO_NOTHING, related_name="markers") + owner = models.ForeignKey( + Profile, on_delete=models.DO_NOTHING, related_name="markers" + ) source = models.ImageField(upload_to="markers/") uploaded_at = models.DateTimeField(auto_now=True) author = models.CharField(max_length=60, blank=False) @@ -45,23 +44,6 @@ class Marker(models.Model): patt = models.FileField(upload_to="patts/") def save(self, *args, **kwargs): - # filestorage = PublicMediaStorage() - # # Image Filename - # original_filename = self.source.name - # filename = filestorage.save(f"original_{original_filename}", self.source) - # # Complete Image URL on storage - # print("aaaaa"*30) - # with Image.open(self.source) as image: - # print(image) - # print("aaaaa"*30) - # # fileurl = filestorage.url(filename) - # print(filename) - # self.source = create_marker(filename, original_filename) - # self.patt = create_patt(filename, original_filename) - print("B" * 30) - print(self.source) - print(self.patt) - print("B" * 30) super().save(*args, **kwargs) def __str__(self): @@ -91,7 +73,9 @@ def in_use(self): class Object(models.Model): - owner = models.ForeignKey(Profile, on_delete=models.DO_NOTHING, related_name="ar_objects") + owner = models.ForeignKey( + Profile, on_delete=models.DO_NOTHING, related_name="ar_objects" + ) source = models.FileField(upload_to="objects/") uploaded_at = models.DateTimeField(auto_now=True) author = models.CharField(max_length=60, blank=False) @@ -209,7 +193,9 @@ def yposition(self): class Artwork(models.Model): - author = models.ForeignKey(Profile, on_delete=models.DO_NOTHING, related_name="artworks") + author = models.ForeignKey( + Profile, on_delete=models.DO_NOTHING, related_name="artworks" + ) marker = models.ForeignKey(Marker, on_delete=models.DO_NOTHING) augmented = models.ForeignKey(Object, on_delete=models.DO_NOTHING) title = models.CharField(max_length=50, blank=False) @@ -239,7 +225,9 @@ def remove_source_file(sender, instance, **kwargs): class Exhibit(models.Model): - owner = models.ForeignKey(Profile, on_delete=models.DO_NOTHING, related_name="exhibits") + owner = models.ForeignKey( + Profile, on_delete=models.DO_NOTHING, related_name="exhibits" + ) name = models.CharField(unique=True, max_length=50) slug = models.CharField(unique=True, max_length=50) artworks = models.ManyToManyField(Artwork, related_name="exhibits") diff --git a/src/core/serializers/artworks.py b/src/core/serializers/artworks.py index 04751a7d..30e3627d 100644 --- a/src/core/serializers/artworks.py +++ b/src/core/serializers/artworks.py @@ -1,6 +1,5 @@ -from rest_framework.serializers import ModelSerializer - from core.models import Artwork +from rest_framework.serializers import ModelSerializer class ArtworkSerializer(ModelSerializer): diff --git a/src/core/serializers/exhibits.py b/src/core/serializers/exhibits.py index 502e7272..5981d01c 100644 --- a/src/core/serializers/exhibits.py +++ b/src/core/serializers/exhibits.py @@ -1,6 +1,5 @@ -from rest_framework.serializers import ModelSerializer - from core.models import Exhibit +from rest_framework.serializers import ModelSerializer class ExhibitSerializer(ModelSerializer): diff --git a/src/core/serializers/markers.py b/src/core/serializers/markers.py index 9b0ac3ae..7dd53f8a 100644 --- a/src/core/serializers/markers.py +++ b/src/core/serializers/markers.py @@ -1,6 +1,5 @@ -from rest_framework.serializers import ModelSerializer - from core.models import Marker +from rest_framework.serializers import ModelSerializer class MarkerSerializer(ModelSerializer): diff --git a/src/core/serializers/objects.py b/src/core/serializers/objects.py index 38f7edd4..0c789f25 100644 --- a/src/core/serializers/objects.py +++ b/src/core/serializers/objects.py @@ -1,6 +1,5 @@ -from rest_framework.serializers import ModelSerializer - from core.models import Object +from rest_framework.serializers import ModelSerializer class ObjectSerializer(ModelSerializer): diff --git a/src/core/tests/test_artworks_api.py b/src/core/tests/test_artworks_api.py index f1df0650..80e42996 100644 --- a/src/core/tests/test_artworks_api.py +++ b/src/core/tests/test_artworks_api.py @@ -1,10 +1,9 @@ """Test using the artwork API for Jandig Artwork""" +from core.models import Artwork, Marker, Object from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase - -from core.models import Artwork, Marker, Object from users.models import User fake_file = SimpleUploadedFile("fake_file.png", b"these are the file contents!") @@ -27,7 +26,9 @@ def test_url(self): def test_api_artworks_lists_one_artwork(self): marker = Marker.objects.create(owner=self.profile, source=fake_file) obj = Object.objects.create(owner=self.profile, source=fake_file) - artwork = Artwork.objects.create(author=self.profile, augmented=obj, marker=marker) + artwork = Artwork.objects.create( + author=self.profile, augmented=obj, marker=marker + ) self.assertEqual(artwork.author, self.profile) response = self.client.get("/api/v1/artworks/") self.assertEqual(response.status_code, 200) @@ -44,7 +45,9 @@ def test_api_artwork_lists_multiple_artworks(self): def test_retrieve_artwork(self): marker = Marker.objects.create(owner=self.profile, source=fake_file) obj = Object.objects.create(owner=self.profile, source=fake_file) - artwork = Artwork.objects.create(author=self.profile, augmented=obj, marker=marker) # noqa F841 + artwork = Artwork.objects.create( + author=self.profile, augmented=obj, marker=marker + ) # noqa F841 self.assertEqual(artwork.author, self.profile) response = self.client.get("/api/v1/artworks/1/") diff --git a/src/core/tests/test_exhibits_api.py b/src/core/tests/test_exhibits_api.py index 66365b98..e81e9d38 100644 --- a/src/core/tests/test_exhibits_api.py +++ b/src/core/tests/test_exhibits_api.py @@ -1,10 +1,9 @@ """Test using the exhibit API for Jandig Exhibit""" +from core.models import Artwork, Exhibit, Marker, Object from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase - -from core.models import Artwork, Exhibit, Marker, Object from users.models import User fake_file = SimpleUploadedFile("fake_file.png", b"these are the file contents!") @@ -27,7 +26,9 @@ def test_url(self): def test_api_exhibits_lists_one_exhibit(self): marker = Marker.objects.create(owner=self.profile, source=fake_file) obj = Object.objects.create(owner=self.profile, source=fake_file) - artwork = Artwork.objects.create(author=self.profile, augmented=obj, marker=marker) + artwork = Artwork.objects.create( + author=self.profile, augmented=obj, marker=marker + ) exhibit = Exhibit.objects.create(owner=self.profile, name="test") exhibit.artworks.add(artwork) response = self.client.get("/api/v1/artworks/") @@ -37,15 +38,21 @@ def test_api_exhibit_lists_multiple_exhibits(self): for i in range(0, settings.PAGE_SIZE + 1): marker = Marker.objects.create(owner=self.profile, source=fake_file) obj = Object.objects.create(owner=self.profile, source=fake_file) - artwork = Artwork.objects.create(author=self.profile, augmented=obj, marker=marker) # noqa F841 - exhibit = Exhibit.objects.create(owner=self.profile, name=f"name_{i}", slug=f"slug_{i}") # noqa F841 + artwork = Artwork.objects.create( + author=self.profile, augmented=obj, marker=marker + ) # noqa F841 + exhibit = Exhibit.objects.create( + owner=self.profile, name=f"name_{i}", slug=f"slug_{i}" + ) # noqa F841 response = self.client.get("/api/v1/exhibits/") self.assertEqual(response.status_code, 200) def test_retrieve_exhibit(self): marker = Marker.objects.create(owner=self.profile, source=fake_file) obj = Object.objects.create(owner=self.profile, source=fake_file) - artwork = Artwork.objects.create(author=self.profile, augmented=obj, marker=marker) + artwork = Artwork.objects.create( + author=self.profile, augmented=obj, marker=marker + ) exhibit = Exhibit.objects.create(owner=self.profile, name="test") exhibit.artworks.add(artwork) response = self.client.get("/api/v1/exhibits/1/") diff --git a/src/core/tests/test_markers_api.py b/src/core/tests/test_markers_api.py index 3ce10ad5..ab68ac22 100644 --- a/src/core/tests/test_markers_api.py +++ b/src/core/tests/test_markers_api.py @@ -1,11 +1,10 @@ """Test using the marker API for Jandig Markers""" +from core.models import Marker +from core.serializers.markers import MarkerSerializer from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase - -from core.models import Marker -from core.serializers.markers import MarkerSerializer from users.models import User fake_file = SimpleUploadedFile("fake_file.png", b"these are the file contents!") diff --git a/src/core/tests/test_objects_api.py b/src/core/tests/test_objects_api.py index d084ad78..621cc942 100644 --- a/src/core/tests/test_objects_api.py +++ b/src/core/tests/test_objects_api.py @@ -1,11 +1,10 @@ """Test using the object API for Jandig Objects""" +from core.models import Object +from core.serializers.objects import ObjectSerializer from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase - -from core.models import Object -from core.serializers.objects import ObjectSerializer from users.models import User fake_file = SimpleUploadedFile("fake_file.png", b"these are the file contents!") diff --git a/src/core/views/artworks.py b/src/core/views/artworks.py index eaaea233..2927f460 100644 --- a/src/core/views/artworks.py +++ b/src/core/views/artworks.py @@ -1,8 +1,7 @@ -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin -from rest_framework.viewsets import GenericViewSet - from core.models import Artwork from core.serializers.artworks import ArtworkSerializer +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin +from rest_framework.viewsets import GenericViewSet class ArtworkViewset(ListModelMixin, RetrieveModelMixin, GenericViewSet): diff --git a/src/core/views/exhibits.py b/src/core/views/exhibits.py index e3a2fe46..e65479d9 100644 --- a/src/core/views/exhibits.py +++ b/src/core/views/exhibits.py @@ -1,8 +1,7 @@ -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin -from rest_framework.viewsets import GenericViewSet - from core.models import Exhibit from core.serializers.exhibits import ExhibitSerializer +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin +from rest_framework.viewsets import GenericViewSet class ExhibitViewset(ListModelMixin, RetrieveModelMixin, GenericViewSet): diff --git a/src/core/views/markers.py b/src/core/views/markers.py index bd185f5a..95192e64 100644 --- a/src/core/views/markers.py +++ b/src/core/views/markers.py @@ -1,8 +1,7 @@ -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin -from rest_framework.viewsets import GenericViewSet - from core.models import Marker from core.serializers.markers import MarkerSerializer +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin +from rest_framework.viewsets import GenericViewSet class MarkerViewset(ListModelMixin, RetrieveModelMixin, GenericViewSet): diff --git a/src/core/views/objects.py b/src/core/views/objects.py index e7a01f61..3e29e5be 100644 --- a/src/core/views/objects.py +++ b/src/core/views/objects.py @@ -1,8 +1,7 @@ -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin -from rest_framework.viewsets import GenericViewSet - from core.models import Object from core.serializers.objects import ObjectSerializer +from rest_framework.mixins import ListModelMixin, RetrieveModelMixin +from rest_framework.viewsets import GenericViewSet class ObjectViewset(ListModelMixin, RetrieveModelMixin, GenericViewSet): diff --git a/src/core/views/static_views.py b/src/core/views/static_views.py index c7016f94..4a8fbf81 100644 --- a/src/core/views/static_views.py +++ b/src/core/views/static_views.py @@ -1,7 +1,8 @@ -from django.http import JsonResponse, HttpResponse +from django.http import HttpResponse, JsonResponse from django.shortcuts import redirect, render from django.templatetags.static import static + def home(request): return render(request, "users/profile.jinja2", {}) @@ -35,4 +36,4 @@ def robots_txt(request): "User-Agent: *", "Disallow: ", ] - return HttpResponse("\n".join(lines), content_type="text/plain") \ No newline at end of file + return HttpResponse("\n".join(lines), content_type="text/plain") diff --git a/src/manage.py b/src/manage.py index 41464304..312127d5 100755 --- a/src/manage.py +++ b/src/manage.py @@ -7,5 +7,9 @@ try: from django.core.management import execute_from_command_line except ImportError as exc: - raise ImportError("Couldn't import Django. Are you sure it's installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?") from exc + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc execute_from_command_line(sys.argv) diff --git a/src/tests/home_tests.py b/src/tests/home_tests.py index a1cc097e..6e6d5d6f 100644 --- a/src/tests/home_tests.py +++ b/src/tests/home_tests.py @@ -1,6 +1,8 @@ import re + from playwright.sync_api import Page, expect + def test_home_loads_in_english(page: Page): page.goto("http://localhost:8000/") @@ -19,4 +21,4 @@ def test_changing_language_to_portuguese_and_back_to_english(page: Page) -> None page.get_by_label("en-us").check() page.get_by_role("button", name="Ok").click() expect(page).to_have_url("http://localhost:8000/") - expect(page.get_by_role("heading")).to_have_text("Welcome to Jandig") \ No newline at end of file + expect(page.get_by_role("heading")).to_have_text("Welcome to Jandig") diff --git a/src/users/admin.py b/src/users/admin.py index 64b5c99c..189d1f8e 100644 --- a/src/users/admin.py +++ b/src/users/admin.py @@ -1,22 +1,25 @@ from typing import Any + from django.contrib import admin +from django.contrib.admin.filters import ListFilter from django.contrib.auth.admin import UserAdmin from django.contrib.auth.models import User +from django.db.models import Count, Q from django.db.models.query import QuerySet from django.http import HttpRequest -from django.db.models import Q, Count from django.urls import reverse from django.utils.html import format_html -from django.contrib import admin from users.models import Profile -from django.contrib.admin.filters import ListFilter + admin.site.unregister(User) + class NoArtFilter(admin.SimpleListFilter): title = "Art Qtdy" # Parameter for the filter that will be used in the URL query. parameter_name = "art_qtd" + def lookups(self, request, model_admin): return [ ("no_artwork", "Zero Artworks"), @@ -40,37 +43,58 @@ def queryset(self, request, queryset): if "no_exhibits" in query: conditions &= Q(_exhibits_count=0) if "no_art" in query: - return queryset.filter(Q(_artworks_count=0)&Q(_ar_objects_count=0)&Q(_exhibits_count=0)&Q(_markers_count=0)) - + return queryset.filter( + Q(_artworks_count=0) + & Q(_ar_objects_count=0) + & Q(_exhibits_count=0) + & Q(_markers_count=0) + ) + # Apply the filter filtered_queryset = queryset.filter(conditions) return filtered_queryset + @admin.register(Profile) class ProfileAdmin(admin.ModelAdmin): - list_display=["id", "user_link","artworks_count","markers_count","ar_objects_count","exhibits_count", "created", "last_login"] - ordering=["-id"] + list_display = [ + "id", + "user_link", + "artworks_count", + "markers_count", + "ar_objects_count", + "exhibits_count", + "created", + "last_login", + ] + ordering = ["-id"] list_filter = [NoArtFilter] + def get_queryset(self, request): - queryset = super().get_queryset(request).select_related("user").prefetch_related("artworks", "markers", "exhibits", "ar_objects") + queryset = ( + super() + .get_queryset(request) + .select_related("user") + .prefetch_related("artworks", "markers", "exhibits", "ar_objects") + ) queryset = queryset.annotate( - _markers_count = Count("markers", distinct=True), - _artworks_count = Count("artworks", distinct=True), - _ar_objects_count = Count("ar_objects", distinct=True), - _exhibits_count = Count("exhibits", distinct=True) + _markers_count=Count("markers", distinct=True), + _artworks_count=Count("artworks", distinct=True), + _ar_objects_count=Count("ar_objects", distinct=True), + _exhibits_count=Count("exhibits", distinct=True), ) return queryset - + def username(self, obj): return obj.user.username - def created(self,obj): + def created(self, obj): return obj.user.date_joined - def last_login(self,obj): + def last_login(self, obj): return obj.user.last_login - def user_link(self,obj): + def user_link(self, obj): """Link to related User""" link = reverse("admin:index") + "auth/user/?id=" + str(obj.user.id) return format_html('{}', link, obj.user.username) @@ -80,29 +104,36 @@ def artworks_count(self, obj): def markers_count(self, obj): return obj._markers_count - + def ar_objects_count(self, obj): return obj._ar_objects_count - + def exhibits_count(self, obj): return obj._exhibits_count artworks_count.admin_order_field = "_artworks_count" - markers_count.admin_order_field= "_markers_count" - ar_objects_count.admin_order_field="_ar_objects_count" - exhibits_count.admin_order_field="_exhibits_count" + markers_count.admin_order_field = "_markers_count" + ar_objects_count.admin_order_field = "_ar_objects_count" + exhibits_count.admin_order_field = "_exhibits_count" @admin.register(User) class JandigUserAdmin(UserAdmin): - list_display = ("username", "email","profile_link", "last_login", "date_joined", "is_staff") + list_display = ( + "username", + "email", + "profile_link", + "last_login", + "date_joined", + "is_staff", + ) list_filter = ("is_staff", "is_superuser", "is_active", "groups") + def get_queryset(self, request: HttpRequest) -> QuerySet[Any]: queryset = super().get_queryset(request).select_related("profile") return queryset - - def profile_link(self,obj): + def profile_link(self, obj): """Link to related Profile""" link = reverse("admin:index") + "users/profile/?id=" + str(obj.profile.id) return format_html('{}', link, obj.username) diff --git a/src/users/factory.py b/src/users/factory.py index fc89688a..382c92ab 100644 --- a/src/users/factory.py +++ b/src/users/factory.py @@ -1,8 +1,7 @@ +from core.models import Object from django.contrib.auth.models import User from factory.django import DjangoModelFactory -from core.models import Object - class UserFactory(DjangoModelFactory): username = "Testador" diff --git a/src/users/forms.py b/src/users/forms.py index 7e321b84..6a8cb328 100644 --- a/src/users/forms.py +++ b/src/users/forms.py @@ -2,6 +2,7 @@ import re from io import BytesIO +from core.models import Marker, Object from django import forms from django.contrib.auth import authenticate, get_user_model from django.contrib.auth.forms import AuthenticationForm @@ -13,8 +14,6 @@ from PIL import Image from pymarker.core import generate_marker_from_image, generate_patt_from_image -from core.models import Marker, Object - from .choices import COUNTRY_CHOICES log = logging.getLogger("ej") @@ -52,7 +51,10 @@ class Meta: def clean_email(self): email = self.cleaned_data.get("email") username = self.cleaned_data.get("username") - if email and User.objects.filter(email=email).exclude(username=username).exists(): + if ( + email + and User.objects.filter(email=email).exclude(username=username).exists() + ): raise forms.ValidationError(_("E-mail taken")) return email @@ -63,7 +65,9 @@ def __init__(self, *args, **kwargs): super(PasswordChangeForm, self).__init__(*args, **kwargs) self.fields["old_password"].widget.attrs["placeholder"] = _("Old Password") self.fields["new_password1"].widget.attrs["placeholder"] = _("New Password") - self.fields["new_password2"].widget.attrs["placeholder"] = _("New Password Again") + self.fields["new_password2"].widget.attrs["placeholder"] = _( + "New Password Again" + ) class ProfileForm(forms.ModelForm): @@ -110,13 +114,23 @@ def __init__(self, *args, **kwargs): def clean_username(self): username = self.cleaned_data.get("username") - if username and User.objects.filter(username=username).exclude(username=self.instance.user.username).exists(): + if ( + username + and User.objects.filter(username=username) + .exclude(username=self.instance.user.username) + .exists() + ): raise forms.ValidationError(_("Username already in use")) return username def clean_email(self): email = self.cleaned_data.get("email") - if email and User.objects.filter(email=email).exclude(username=self.instance.user.username).exists(): + if ( + email + and User.objects.filter(email=email) + .exclude(username=self.instance.user.username) + .exists() + ): raise forms.ValidationError(_("Email address must be unique")) return email @@ -184,7 +198,9 @@ def __init__(self, *args, **kwargs): log.warning(self.fields) self.fields["source"].widget.attrs["placeholder"] = _("browse file") self.fields["source"].widget.attrs["accept"] = "image/png, image/jpg" - self.fields["author"].widget.attrs["placeholder"] = _("declare different author name") + self.fields["author"].widget.attrs["placeholder"] = _( + "declare different author name" + ) self.fields["title"].widget.attrs["placeholder"] = _("Marker's title") class Meta: @@ -221,7 +237,9 @@ def __init__(self, *args, **kwargs): self.fields["source"].widget.attrs["placeholder"] = _("browse file") self.fields["source"].widget.attrs["accept"] = "image/*, .mp4, .webm" - self.fields["author"].widget.attrs["placeholder"] = _("declare different author name") + self.fields["author"].widget.attrs["placeholder"] = _( + "declare different author name" + ) self.fields["scale"].widget = HiddenInput() self.fields["rotation"].widget = HiddenInput() self.fields["position"].widget = HiddenInput() @@ -254,10 +272,16 @@ class ArtworkForm(forms.Form): def __init__(self, *args, **kwargs): super(ArtworkForm, self).__init__(*args, **kwargs) - self.fields["marker_author"].widget.attrs["placeholder"] = _("declare different author name") - self.fields["augmented_author"].widget.attrs["placeholder"] = _("declare different author name") + self.fields["marker_author"].widget.attrs["placeholder"] = _( + "declare different author name" + ) + self.fields["augmented_author"].widget.attrs["placeholder"] = _( + "declare different author name" + ) self.fields["title"].widget.attrs["placeholder"] = _("Artwork title") - self.fields["description"].widget.attrs["placeholder"] = _("Artwork description") + self.fields["description"].widget.attrs["placeholder"] = _( + "Artwork description" + ) class ExhibitForm(forms.Form): @@ -271,11 +295,15 @@ class ExhibitForm(forms.Form): def clean_slug(self): data = self.cleaned_data["slug"] if not re.match("^[a-zA-Z0-9_]*$", data): - raise forms.ValidationError(_("Url can't contain spaces or special characters")) + raise forms.ValidationError( + _("Url can't contain spaces or special characters") + ) return data def __init__(self, *args, **kwargs): super(ExhibitForm, self).__init__(*args, **kwargs) self.fields["name"].widget.attrs["placeholder"] = _("Exhibit Title") - self.fields["slug"].widget.attrs["placeholder"] = _("Complete with your Exhibit URL here") + self.fields["slug"].widget.attrs["placeholder"] = _( + "Complete with your Exhibit URL here" + ) diff --git a/src/users/tests/test_users.py b/src/users/tests/test_users.py index 0bb37a02..41acf9bc 100644 --- a/src/users/tests/test_users.py +++ b/src/users/tests/test_users.py @@ -1,7 +1,6 @@ from unittest import mock from django.test import RequestFactory, TestCase - from users.factory import UserFactory from users.services.email_service import EmailService from users.services.encrypt_service import EncryptService @@ -35,20 +34,26 @@ def test_recover_password_invalid_email(self, *args, **kwargs): self.assertEqual(response.url, "/users/invalid-recovering-email") def test_recover_password_invalid_username(self, *args, **kwargs): - request = self.client_test.post("/recover/", {"username_or_email": "testadorinvalid"}, follow=True) + request = self.client_test.post( + "/recover/", {"username_or_email": "testadorinvalid"}, follow=True + ) response = recover_password(request) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, "/users/invalid-recovering-email") def test_recover_password_valid_email(self, *args, **kwargs): - request = self.client_test.post("/recover/", {"username_or_email": "testador@memelab.com"}, follow=True) + request = self.client_test.post( + "/recover/", {"username_or_email": "testador@memelab.com"}, follow=True + ) UserFactory() response = recover_password(request) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, "/users/recover-code/") def test_recover_password_valid_username(self, *args, **kwargs): - request = self.client_test.post("/recover/", {"username_or_email": "Testador"}, follow=True) + request = self.client_test.post( + "/recover/", {"username_or_email": "Testador"}, follow=True + ) UserFactory() response = recover_password(request) self.assertEqual(response.status_code, 302) diff --git a/src/users/views.py b/src/users/views.py index 76b5bdb0..1c5c89ea 100644 --- a/src/users/views.py +++ b/src/users/views.py @@ -1,6 +1,7 @@ import json import logging +from core.models import Artwork, Exhibit, Marker, Object from django.contrib.auth import ( authenticate, get_user_model, @@ -14,8 +15,6 @@ from django.views.decorators.cache import cache_page from django.views.decorators.http import require_http_methods -from core.models import Artwork, Exhibit, Marker, Object - from .forms import ( ArtworkForm, ExhibitForm, @@ -61,9 +60,13 @@ def recover_password(request): recover_password_form = RecoverPasswordForm(request.POST) if recover_password_form.is_valid(): - username_or_email = recover_password_form.cleaned_data.get("username_or_email") + username_or_email = recover_password_form.cleaned_data.get( + "username_or_email" + ) user_service = UserService() - username_or_email_is_valid = user_service.check_if_username_or_email_exist(username_or_email) + username_or_email_is_valid = user_service.check_if_username_or_email_exist( + username_or_email + ) if not username_or_email_is_valid: return redirect("invalid_recovering_email_or_username") @@ -72,14 +75,18 @@ def recover_password(request): global global_verification_code encrypt_service = EncryptService() - global_verification_code = encrypt_service.generate_verification_code(global_recovering_email) + global_verification_code = encrypt_service.generate_verification_code( + global_recovering_email + ) build_message_and_send_to_user(global_recovering_email) return redirect("recover-code") recover_password_form = RecoverPasswordForm() - return render(request, "users/recover-password.jinja2", {"form": recover_password_form}) + return render( + request, "users/recover-password.jinja2", {"form": recover_password_form} + ) def build_message_and_send_to_user(email): @@ -144,7 +151,9 @@ def profile(request): if not user: user = request.user - profile = Profile.objects.prefetch_related("exhibits", "markers", "ar_objects", "artworks").get(user=user) + profile = Profile.objects.prefetch_related( + "exhibits", "markers", "ar_objects", "artworks" + ).get(user=user) exhibits = profile.exhibits.all() markers = profile.markers.all() diff --git a/tasks.py b/tasks.py index 4194aa1f..75d12c76 100644 --- a/tasks.py +++ b/tasks.py @@ -4,24 +4,24 @@ python = sys.executable directory = os.path.dirname(__file__) -sys.path.append('jandig') +sys.path.append("jandig") # # Call python manage.py in a more robust way # def robust_manage(ctx, cmd, env=None, **kwargs): - kwargs = {k.replace('_', '-'): v for k, v in kwargs.items() if v is not False} - opts = ' '.join(f'--{k} {"" if v is True else v}' for k, v in kwargs.items()) - cmd = f'{python} ./src/manage.py {cmd} {opts}' + kwargs = {k.replace("_", "-"): v for k, v in kwargs.items() if v is not False} + opts = " ".join(f'--{k} {"" if v is True else v}' for k, v in kwargs.items()) + cmd = f"{python} ./src/manage.py {cmd} {opts}" env = {**os.environ, **(env or {})} path = env.get("PYTHONPATH", ":".join(sys.path)) - env.setdefault('PYTHONPATH', f'src:{path}') + env.setdefault("PYTHONPATH", f"src:{path}") print(cmd) ctx.run(cmd, pty=True, env=env) def manage(ctx, cmd): - cmd = f'python3 ./src/manage.py {cmd}' + cmd = f"python3 ./src/manage.py {cmd}" ctx.run(cmd, pty=True, env=os.environ) @@ -31,7 +31,9 @@ def run(ctx, ssl=False, gunicorn=False): Run development server """ if gunicorn: - ctx.run('cd src && gunicorn --reload --worker-connections=10000 --workers=4 --log-level debug --bind 0.0.0.0:8000 config.wsgi') + ctx.run( + "cd src && gunicorn --reload --worker-connections=10000 --workers=4 --log-level debug --bind 0.0.0.0:8000 config.wsgi" + ) else: manage(ctx, "runserver 0.0.0.0:8000") @@ -60,34 +62,36 @@ def collect(ctx): # Translations # @task -def i18n(ctx, compile=False, edit=False, lang='pt_BR', keep_pot=False): +def i18n(ctx, compile=False, edit=False, lang="pt_BR", keep_pot=False): """ Extract messages for translation. """ if edit: - ctx.run(f'poedit locale/{lang}/LC_MESSAGES/django.po') + ctx.run(f"poedit locale/{lang}/LC_MESSAGES/django.po") elif compile: - ctx.run(f'{python} etc/scripts/compilemessages.py') + ctx.run(f"{python} etc/scripts/compilemessages.py") else: - print('Collecting messages') - robust_manage(ctx, 'makemessages', keep_pot=True, locale=lang) + print("Collecting messages") + robust_manage(ctx, "makemessages", keep_pot=True, locale=lang) - print('Extract Jinja translations') - ctx.run('pybabel extract -F ./etc/babel.cfg -o ./locale/jinja2.pot .') + print("Extract Jinja translations") + ctx.run("pybabel extract -F ./etc/babel.cfg -o ./locale/jinja2.pot .") - print('Join Django + Jinja translation files') - ctx.run('msgcat ./locale/django.pot ./locale/jinja2.pot --use-first -o ./locale/join.pot', - pty=True) - ctx.run(r'''sed -i '/"Language: \\n"/d' ./locale/join.pot''', pty=True) + print("Join Django + Jinja translation files") + ctx.run( + "msgcat ./locale/django.pot ./locale/jinja2.pot --use-first -o ./locale/join.pot", + pty=True, + ) + ctx.run(r"""sed -i '/"Language: \\n"/d' ./locale/join.pot""", pty=True) - print(f'Update locale {lang} with Jinja2 messages') - ctx.run(f'msgmerge ./locale/{lang}/LC_MESSAGES/django.po ./locale/join.pot -U') + print(f"Update locale {lang} with Jinja2 messages") + ctx.run(f"msgmerge ./locale/{lang}/LC_MESSAGES/django.po ./locale/join.pot -U") if not keep_pot: - print('Cleaning up') - ctx.run('rm ./locale/*.pot') + print("Cleaning up") + ctx.run("rm ./locale/*.pot") @task def docs(ctx): - ctx.run('sphinx-build docs/ build/') + ctx.run("sphinx-build docs/ build/")